Search in sources :

Example 81 with Method

use of org.jf.dexlib2.iface.Method in project smali by JesusFreke.

the class MethodAnalyzer method analyzeExecuteInline.

private void analyzeExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) {
    if (inlineResolver == null) {
        throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing");
    }
    Instruction35mi instruction = (Instruction35mi) analyzedInstruction.instruction;
    Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction);
    Opcode deodexedOpcode;
    int acccessFlags = resolvedMethod.getAccessFlags();
    if (AccessFlags.STATIC.isSet(acccessFlags)) {
        deodexedOpcode = Opcode.INVOKE_STATIC;
    } else if (AccessFlags.PRIVATE.isSet(acccessFlags)) {
        deodexedOpcode = Opcode.INVOKE_DIRECT;
    } else {
        deodexedOpcode = Opcode.INVOKE_VIRTUAL;
    }
    Instruction35c deodexedInstruction = new ImmutableInstruction35c(deodexedOpcode, instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod);
    analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
    analyzeInstruction(analyzedInstruction);
}
Also used : Opcode(org.jf.dexlib2.Opcode)

Example 82 with Method

use of org.jf.dexlib2.iface.Method in project smali by JesusFreke.

the class MethodAnalyzer method analyzeInvokeVirtualQuick.

private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper, boolean isRange) {
    int methodIndex;
    int objectRegister;
    if (isRange) {
        Instruction3rms instruction = (Instruction3rms) analyzedInstruction.instruction;
        methodIndex = instruction.getVtableIndex();
        objectRegister = instruction.getStartRegister();
    } else {
        Instruction35ms instruction = (Instruction35ms) analyzedInstruction.instruction;
        methodIndex = instruction.getVtableIndex();
        objectRegister = instruction.getRegisterC();
    }
    RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, objectRegister, ReferenceOrUninitCategories);
    TypeProto objectRegisterTypeProto = objectRegisterType.type;
    if (objectRegisterType.category == RegisterType.NULL) {
        return false;
    }
    assert objectRegisterTypeProto != null;
    MethodReference resolvedMethod;
    if (isSuper) {
        // invoke-super is only used for the same class that we're currently in
        TypeProto typeProto = classPath.getClass(method.getDefiningClass());
        TypeProto superType;
        String superclassType = typeProto.getSuperclass();
        if (superclassType != null) {
            superType = classPath.getClass(superclassType);
        } else {
            // This is either java.lang.Object, or an UnknownClassProto
            superType = typeProto;
        }
        resolvedMethod = superType.getMethodByVtableIndex(methodIndex);
    } else {
        resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex);
    }
    if (resolvedMethod == null) {
        throw new AnalysisException("Could not resolve the method in class %s at index %d", objectRegisterType.type.getType(), methodIndex);
    }
    // no need to check class access for invoke-super. A class can obviously access its superclass.
    ClassDef thisClass = classPath.getClassDef(method.getDefiningClass());
    if (classPath.getClass(resolvedMethod.getDefiningClass()).isInterface()) {
        resolvedMethod = new ReparentedMethodReference(resolvedMethod, objectRegisterTypeProto.getType());
    } else if (!isSuper && !TypeUtils.canAccessClass(thisClass.getType(), classPath.getClassDef(resolvedMethod.getDefiningClass()))) {
        // the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different
        // than resolvedMethod.getDefiningClass()), and walk up the class hierarchy.
        ClassDef methodClass = classPath.getClassDef(objectRegisterTypeProto.getType());
        while (!TypeUtils.canAccessClass(thisClass.getType(), methodClass)) {
            String superclass = methodClass.getSuperclass();
            if (superclass == null) {
                throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s", resolvedMethod);
            }
            methodClass = classPath.getClassDef(superclass);
        }
        // methodClass is now the first accessible class found. Now. we need to make sure that the method is
        // actually valid for this class
        MethodReference newResolvedMethod = classPath.getClass(methodClass.getType()).getMethodByVtableIndex(methodIndex);
        if (newResolvedMethod == null) {
            throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s", resolvedMethod);
        }
        resolvedMethod = newResolvedMethod;
        resolvedMethod = new ImmutableMethodReference(methodClass.getType(), resolvedMethod.getName(), resolvedMethod.getParameterTypes(), resolvedMethod.getReturnType());
    }
    if (normalizeVirtualMethods) {
        MethodReference replacementMethod = normalizeMethodReference(resolvedMethod);
        if (replacementMethod != null) {
            resolvedMethod = replacementMethod;
        }
    }
    Instruction deodexedInstruction;
    if (isRange) {
        Instruction3rms instruction = (Instruction3rms) analyzedInstruction.instruction;
        Opcode opcode;
        if (isSuper) {
            opcode = Opcode.INVOKE_SUPER_RANGE;
        } else {
            opcode = Opcode.INVOKE_VIRTUAL_RANGE;
        }
        deodexedInstruction = new ImmutableInstruction3rc(opcode, instruction.getStartRegister(), instruction.getRegisterCount(), resolvedMethod);
    } else {
        Instruction35ms instruction = (Instruction35ms) analyzedInstruction.instruction;
        Opcode opcode;
        if (isSuper) {
            opcode = Opcode.INVOKE_SUPER;
        } else {
            opcode = Opcode.INVOKE_VIRTUAL;
        }
        deodexedInstruction = new ImmutableInstruction35c(opcode, instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod);
    }
    analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
    analyzeInstruction(analyzedInstruction);
    return true;
}
Also used : ImmutableMethodReference(org.jf.dexlib2.immutable.reference.ImmutableMethodReference) Opcode(org.jf.dexlib2.Opcode) ExceptionWithContext(org.jf.util.ExceptionWithContext) BaseMethodReference(org.jf.dexlib2.base.reference.BaseMethodReference) ImmutableMethodReference(org.jf.dexlib2.immutable.reference.ImmutableMethodReference) MethodReference(org.jf.dexlib2.iface.reference.MethodReference)

Example 83 with Method

use of org.jf.dexlib2.iface.Method in project smali by JesusFreke.

the class MethodAnalyzer method analyzeExecuteInlineRange.

private void analyzeExecuteInlineRange(@Nonnull AnalyzedInstruction analyzedInstruction) {
    if (inlineResolver == null) {
        throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing");
    }
    Instruction3rmi instruction = (Instruction3rmi) analyzedInstruction.instruction;
    Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction);
    Opcode deodexedOpcode;
    int acccessFlags = resolvedMethod.getAccessFlags();
    if (AccessFlags.STATIC.isSet(acccessFlags)) {
        deodexedOpcode = Opcode.INVOKE_STATIC_RANGE;
    } else if (AccessFlags.PRIVATE.isSet(acccessFlags)) {
        deodexedOpcode = Opcode.INVOKE_DIRECT_RANGE;
    } else {
        deodexedOpcode = Opcode.INVOKE_VIRTUAL_RANGE;
    }
    Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(deodexedOpcode, instruction.getStartRegister(), instruction.getRegisterCount(), resolvedMethod);
    analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
    analyzeInstruction(analyzedInstruction);
}
Also used : Opcode(org.jf.dexlib2.Opcode)

Example 84 with Method

use of org.jf.dexlib2.iface.Method in project smali by JesusFreke.

the class InstructionMethodItemTest method testInvalidReference.

@Test
public void testInvalidReference() throws IOException {
    Instruction21c instruction = new Instruction21c() {

        @Override
        public int getRegisterA() {
            return 0;
        }

        @Nonnull
        @Override
        public Reference getReference() {
            return new BaseStringReference() {

                @Override
                public void validateReference() throws InvalidReferenceException {
                    throw new InvalidReferenceException("blahblahblah");
                }

                @Nonnull
                @Override
                public String getString() {
                    throw new RuntimeException("invalid reference");
                }
            };
        }

        @Override
        public int getReferenceType() {
            return ReferenceType.STRING;
        }

        @Override
        public Opcode getOpcode() {
            return Opcode.CONST_STRING;
        }

        @Override
        public int getCodeUnits() {
            return Format.Format21c.size / 2;
        }
    };
    MethodImplementation methodImplementation = new MethodImplementation() {

        @Override
        public int getRegisterCount() {
            return 1;
        }

        @Nonnull
        @Override
        public Iterable<? extends Instruction> getInstructions() {
            return ImmutableList.of(instruction);
        }

        @Nonnull
        @Override
        public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
            return ImmutableList.of();
        }

        @Nonnull
        @Override
        public Iterable<? extends DebugItem> getDebugItems() {
            return ImmutableList.of();
        }
    };
    Method method = new TestMethod(methodImplementation);
    ClassDefinition classDefinition = new ClassDefinition(new BaksmaliOptions(), new TestClassDef());
    MethodDefinition methodDefinition = new MethodDefinition(classDefinition, method, methodImplementation);
    methodDefinition.registerFormatter = new RegisterFormatter(new BaksmaliOptions(), 1, 0);
    InstructionMethodItem methodItem = new InstructionMethodItem<Instruction21c>(methodDefinition, 0, instruction);
    StringWriter stringWriter = new StringWriter();
    BaksmaliWriter writer = new BaksmaliWriter(stringWriter);
    methodItem.writeTo(writer);
    Assert.assertEquals("#Invalid reference\n#const-string v0, blahblahblah\nnop", stringWriter.toString());
}
Also used : Instruction21c(org.jf.dexlib2.iface.instruction.formats.Instruction21c) ClassDefinition(org.jf.baksmali.Adaptors.ClassDefinition) RegisterFormatter(org.jf.baksmali.Adaptors.RegisterFormatter) BaseStringReference(org.jf.dexlib2.base.reference.BaseStringReference) InstructionMethodItem(org.jf.baksmali.Adaptors.Format.InstructionMethodItem) StringWriter(java.io.StringWriter) MethodDefinition(org.jf.baksmali.Adaptors.MethodDefinition) BaksmaliWriter(org.jf.baksmali.formatter.BaksmaliWriter) Test(org.junit.Test)

Example 85 with Method

use of org.jf.dexlib2.iface.Method in project smali by JesusFreke.

the class AnalyzedInstruction method setsRegister.

/**
 * Determines if this instruction sets the given register, or alters its type
 *
 * @param registerNumber The register to check
 * @return true if this instruction sets the given register or alters its type
 */
public boolean setsRegister(int registerNumber) {
    if (isInvokeInit()) {
        // When constructing a new object, the register type will be an uninitialized reference after the
        // new-instance instruction, but becomes an initialized reference once the <init> method is called. So even
        // though invoke instructions don't normally change any registers, calling an <init> method will change the
        // type of its object register. If the uninitialized reference has been copied to other registers, they will
        // be initialized as well, so we need to check for that too
        int destinationRegister;
        if (instruction instanceof FiveRegisterInstruction) {
            assert ((FiveRegisterInstruction) instruction).getRegisterCount() > 0;
            destinationRegister = ((FiveRegisterInstruction) instruction).getRegisterC();
        } else {
            assert instruction instanceof RegisterRangeInstruction;
            RegisterRangeInstruction rangeInstruction = (RegisterRangeInstruction) instruction;
            assert rangeInstruction.getRegisterCount() > 0;
            destinationRegister = rangeInstruction.getStartRegister();
        }
        RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(destinationRegister);
        if (preInstructionDestRegisterType.category == RegisterType.UNKNOWN) {
            // We never let an uninitialized reference propagate past an invoke-init if the object register type is
            // unknown This is because the uninitialized reference may be an alias to the reference being
            // initialized, but we can't know that until the object register's type is known
            RegisterType preInstructionRegisterType = getPreInstructionRegisterType(registerNumber);
            if (preInstructionRegisterType.category == RegisterType.UNINIT_REF || preInstructionRegisterType.category == RegisterType.UNINIT_THIS) {
                return true;
            }
        }
        if (preInstructionDestRegisterType.category != RegisterType.UNINIT_REF && preInstructionDestRegisterType.category != RegisterType.UNINIT_THIS) {
            return false;
        }
        if (registerNumber == destinationRegister) {
            return true;
        }
        // check if the uninit ref has been copied to another register
        return preInstructionDestRegisterType.equals(getPreInstructionRegisterType(registerNumber));
    }
    // branch of the following if-eqz/if-nez
    if (instructionIndex > 0 && methodAnalyzer.getClassPath().isArt() && getPredecessorCount() == 1 && (instruction.getOpcode() == Opcode.IF_EQZ || instruction.getOpcode() == Opcode.IF_NEZ)) {
        AnalyzedInstruction prevInstruction = predecessors.first();
        if (prevInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF && MethodAnalyzer.canPropagateTypeAfterInstanceOf(prevInstruction, this, methodAnalyzer.getClassPath())) {
            Instruction22c instanceOfInstruction = (Instruction22c) prevInstruction.instruction;
            if (registerNumber == instanceOfInstruction.getRegisterB()) {
                return true;
            }
            // TODO: do we need to do some sort of additional check that these multiple move-object predecessors actually refer to the same value?
            if (instructionIndex > 1) {
                int originalSourceRegister = -1;
                RegisterType newType = null;
                for (AnalyzedInstruction prevPrevAnalyzedInstruction : prevInstruction.predecessors) {
                    Opcode opcode = prevPrevAnalyzedInstruction.instruction.getOpcode();
                    if (opcode == Opcode.MOVE_OBJECT || opcode == Opcode.MOVE_OBJECT_16 || opcode == Opcode.MOVE_OBJECT_FROM16) {
                        TwoRegisterInstruction moveInstruction = ((TwoRegisterInstruction) prevPrevAnalyzedInstruction.instruction);
                        RegisterType originalType = prevPrevAnalyzedInstruction.getPostInstructionRegisterType(moveInstruction.getRegisterB());
                        if (moveInstruction.getRegisterA() != instanceOfInstruction.getRegisterB()) {
                            originalSourceRegister = -1;
                            break;
                        }
                        if (originalType.type == null) {
                            originalSourceRegister = -1;
                            break;
                        }
                        if (newType == null) {
                            newType = RegisterType.getRegisterType(methodAnalyzer.getClassPath(), (TypeReference) instanceOfInstruction.getReference());
                        }
                        if (MethodAnalyzer.isNotWideningConversion(originalType, newType)) {
                            if (originalSourceRegister != -1) {
                                if (originalSourceRegister != moveInstruction.getRegisterB()) {
                                    originalSourceRegister = -1;
                                    break;
                                }
                            } else {
                                originalSourceRegister = moveInstruction.getRegisterB();
                            }
                        }
                    } else {
                        originalSourceRegister = -1;
                        break;
                    }
                }
                if (originalSourceRegister != -1 && registerNumber == originalSourceRegister) {
                    return true;
                }
            }
        }
    }
    if (!instruction.getOpcode().setsRegister()) {
        return false;
    }
    int destinationRegister = getDestinationRegister();
    if (registerNumber == destinationRegister) {
        return true;
    }
    if (instruction.getOpcode().setsWideRegister() && registerNumber == (destinationRegister + 1)) {
        return true;
    }
    return false;
}
Also used : Instruction22c(org.jf.dexlib2.iface.instruction.formats.Instruction22c) Opcode(org.jf.dexlib2.Opcode) TypeReference(org.jf.dexlib2.iface.reference.TypeReference)

Aggregations

Method (org.jf.dexlib2.iface.Method)30 ClassDef (org.jf.dexlib2.iface.ClassDef)27 MethodImplementation (org.jf.dexlib2.iface.MethodImplementation)23 Test (org.junit.Test)21 Instruction (org.jf.dexlib2.iface.instruction.Instruction)19 MethodReference (org.jf.dexlib2.iface.reference.MethodReference)18 DexFile (org.jf.dexlib2.iface.DexFile)16 ImmutableMethod (org.jf.dexlib2.immutable.ImmutableMethod)15 DexBackedClassDef (org.jf.dexlib2.dexbacked.DexBackedClassDef)13 ArrayList (java.util.ArrayList)12 ImmutableClassDef (org.jf.dexlib2.immutable.ImmutableClassDef)12 MutableMethodImplementation (org.jf.dexlib2.builder.MutableMethodImplementation)10 ImmutableDexFile (org.jf.dexlib2.immutable.ImmutableDexFile)10 HashSet (java.util.HashSet)9 Nonnull (javax.annotation.Nonnull)9 BuilderInstruction10x (org.jf.dexlib2.builder.instruction.BuilderInstruction10x)8 ReferenceInstruction (org.jf.dexlib2.iface.instruction.ReferenceInstruction)8 ImmutableMethodParameter (org.jf.dexlib2.immutable.ImmutableMethodParameter)8 ImmutableMethodReference (org.jf.dexlib2.immutable.reference.ImmutableMethodReference)8 File (java.io.File)7