Search in sources :

Example 16 with Opcode

use of org.jf.dexlib2.Opcode in project smali by JesusFreke.

the class MethodAnalyzer method analyzeIputIgetQuick.

private boolean analyzeIputIgetQuick(@Nonnull AnalyzedInstruction analyzedInstruction) {
    Instruction22cs instruction = (Instruction22cs) analyzedInstruction.instruction;
    int fieldOffset = instruction.getFieldOffset();
    RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), ReferenceOrUninitCategories);
    if (objectRegisterType.category == RegisterType.NULL) {
        return false;
    }
    TypeProto objectRegisterTypeProto = objectRegisterType.type;
    assert objectRegisterTypeProto != null;
    TypeProto classTypeProto = classPath.getClass(objectRegisterTypeProto.getType());
    FieldReference resolvedField = classTypeProto.getFieldByOffset(fieldOffset);
    if (resolvedField == null) {
        throw new AnalysisException("Could not resolve the field in class %s at offset %d", objectRegisterType.type.getType(), fieldOffset);
    }
    ClassDef thisClass = classPath.getClassDef(method.getDefiningClass());
    if (!TypeUtils.canAccessClass(thisClass.getType(), classPath.getClassDef(resolvedField.getDefiningClass()))) {
        // the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different
        // than resolvedField.getDefiningClass()), and walk up the class hierarchy.
        ClassDef fieldClass = classPath.getClassDef(objectRegisterTypeProto.getType());
        while (!TypeUtils.canAccessClass(thisClass.getType(), fieldClass)) {
            String superclass = fieldClass.getSuperclass();
            if (superclass == null) {
                throw new ExceptionWithContext("Couldn't find accessible class while resolving field %s", ReferenceUtil.getShortFieldDescriptor(resolvedField));
            }
            fieldClass = classPath.getClassDef(superclass);
        }
        // fieldClass is now the first accessible class found. Now. we need to make sure that the field is
        // actually valid for this class
        FieldReference newResolvedField = classPath.getClass(fieldClass.getType()).getFieldByOffset(fieldOffset);
        if (newResolvedField == null) {
            throw new ExceptionWithContext("Couldn't find accessible class while resolving field %s", ReferenceUtil.getShortFieldDescriptor(resolvedField));
        }
        resolvedField = new ImmutableFieldReference(fieldClass.getType(), newResolvedField.getName(), newResolvedField.getType());
    }
    String fieldType = resolvedField.getType();
    Opcode opcode = classPath.getFieldInstructionMapper().getAndCheckDeodexedOpcode(fieldType, instruction.getOpcode());
    Instruction22c deodexedInstruction = new ImmutableInstruction22c(opcode, (byte) instruction.getRegisterA(), (byte) instruction.getRegisterB(), resolvedField);
    analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
    analyzeInstruction(analyzedInstruction);
    return true;
}
Also used : FieldReference(org.jf.dexlib2.iface.reference.FieldReference) ImmutableFieldReference(org.jf.dexlib2.immutable.reference.ImmutableFieldReference) ImmutableFieldReference(org.jf.dexlib2.immutable.reference.ImmutableFieldReference) Opcode(org.jf.dexlib2.Opcode) ExceptionWithContext(org.jf.util.ExceptionWithContext)

Example 17 with Opcode

use of org.jf.dexlib2.Opcode 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 18 with Opcode

use of org.jf.dexlib2.Opcode 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 19 with Opcode

use of org.jf.dexlib2.Opcode 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", ReferenceUtil.getMethodDescriptor(resolvedMethod, true));
            }
            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", ReferenceUtil.getMethodDescriptor(resolvedMethod, true));
        }
        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 20 with Opcode

use of org.jf.dexlib2.Opcode in project smali by JesusFreke.

the class MethodAnalyzer method buildInstructionList.

private void buildInstructionList() {
    int registerCount = methodImpl.getRegisterCount();
    ImmutableList<Instruction> instructions = ImmutableList.copyOf(methodImpl.getInstructions());
    analyzedInstructions.ensureCapacity(instructions.size());
    //first, create all the instructions and populate the instructionAddresses array
    int currentCodeAddress = 0;
    for (int i = 0; i < instructions.size(); i++) {
        Instruction instruction = instructions.get(i);
        analyzedInstructions.append(currentCodeAddress, new AnalyzedInstruction(this, instruction, i, registerCount));
        assert analyzedInstructions.indexOfKey(currentCodeAddress) == i;
        currentCodeAddress += instruction.getCodeUnits();
    }
    //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception
    //and is covered by a try block should be set to a list of the first instructions of each exception handler
    //for the try block covering the instruction
    List<? extends TryBlock<? extends ExceptionHandler>> tries = methodImpl.getTryBlocks();
    tries = TryListBuilder.massageTryBlocks(tries);
    int triesIndex = 0;
    TryBlock currentTry = null;
    AnalyzedInstruction[] currentExceptionHandlers = null;
    AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][];
    if (tries != null) {
        for (int i = 0; i < analyzedInstructions.size(); i++) {
            AnalyzedInstruction instruction = analyzedInstructions.valueAt(i);
            Opcode instructionOpcode = instruction.instruction.getOpcode();
            currentCodeAddress = getInstructionAddress(instruction);
            //check if we have gone past the end of the current try
            if (currentTry != null) {
                if (currentTry.getStartCodeAddress() + currentTry.getCodeUnitCount() <= currentCodeAddress) {
                    currentTry = null;
                    triesIndex++;
                }
            }
            //check if the next try is applicable yet
            if (currentTry == null && triesIndex < tries.size()) {
                TryBlock<? extends ExceptionHandler> tryBlock = tries.get(triesIndex);
                if (tryBlock.getStartCodeAddress() <= currentCodeAddress) {
                    assert (tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount() > currentCodeAddress);
                    currentTry = tryBlock;
                    currentExceptionHandlers = buildExceptionHandlerArray(tryBlock);
                }
            }
            //for the current instruction
            if (currentTry != null && instructionOpcode.canThrow()) {
                exceptionHandlers[i] = currentExceptionHandlers;
            }
        }
    }
    //and no reachable code will have an unreachable predessor or successor
    assert analyzedInstructions.size() > 0;
    BitSet instructionsToProcess = new BitSet(instructions.size());
    addPredecessorSuccessor(startOfMethod, analyzedInstructions.valueAt(0), exceptionHandlers, instructionsToProcess);
    while (!instructionsToProcess.isEmpty()) {
        int currentInstructionIndex = instructionsToProcess.nextSetBit(0);
        instructionsToProcess.clear(currentInstructionIndex);
        AnalyzedInstruction instruction = analyzedInstructions.valueAt(currentInstructionIndex);
        Opcode instructionOpcode = instruction.instruction.getOpcode();
        int instructionCodeAddress = getInstructionAddress(instruction);
        if (instruction.instruction.getOpcode().canContinue()) {
            if (currentInstructionIndex == analyzedInstructions.size() - 1) {
                throw new AnalysisException("Execution can continue past the last instruction");
            }
            AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex + 1);
            addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess);
        }
        if (instruction.instruction instanceof OffsetInstruction) {
            OffsetInstruction offsetInstruction = (OffsetInstruction) instruction.instruction;
            if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
                AnalyzedInstruction analyzedSwitchPayload = analyzedInstructions.get(instructionCodeAddress + offsetInstruction.getCodeOffset());
                if (analyzedSwitchPayload == null) {
                    throw new AnalysisException("Invalid switch payload offset");
                }
                SwitchPayload switchPayload = (SwitchPayload) analyzedSwitchPayload.instruction;
                for (SwitchElement switchElement : switchPayload.getSwitchElements()) {
                    AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + switchElement.getOffset());
                    if (targetInstruction == null) {
                        throw new AnalysisException("Invalid switch target offset");
                    }
                    addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
                }
            } else if (instructionOpcode != Opcode.FILL_ARRAY_DATA) {
                int targetAddressOffset = offsetInstruction.getCodeOffset();
                AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + targetAddressOffset);
                addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
            }
        }
    }
}
Also used : BitSet(java.util.BitSet) Opcode(org.jf.dexlib2.Opcode)

Aggregations

Opcode (org.jf.dexlib2.Opcode)17 Instruction (org.jf.dexlib2.iface.instruction.Instruction)15 ReferenceInstruction (org.jf.dexlib2.iface.instruction.ReferenceInstruction)11 OffsetInstruction (org.jf.dexlib2.iface.instruction.OffsetInstruction)10 MethodReference (org.jf.dexlib2.iface.reference.MethodReference)7 AnalyzedInstruction (org.jf.dexlib2.analysis.AnalyzedInstruction)6 Test (org.junit.Test)6 InvalidItemIndex (org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex)4 Instruction31t (org.jf.dexlib2.iface.instruction.formats.Instruction31t)4 FieldReference (org.jf.dexlib2.iface.reference.FieldReference)4 TypeReference (org.jf.dexlib2.iface.reference.TypeReference)4 InvalidInstructionOffset (org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset)4 ExceptionWithContext (org.jf.util.ExceptionWithContext)4 Nonnull (javax.annotation.Nonnull)3 Instruction20bc (org.jf.dexlib2.iface.instruction.formats.Instruction20bc)3 Instruction22c (org.jf.dexlib2.iface.instruction.formats.Instruction22c)3 Reference (org.jf.dexlib2.iface.reference.Reference)3 ImmutableFieldReference (org.jf.dexlib2.immutable.reference.ImmutableFieldReference)3 IOException (java.io.IOException)2 ReferenceType (org.jf.dexlib2.ReferenceType)2