Search in sources :

Example 6 with AnalysisException

use of org.jf.dexlib2.analysis.AnalysisException 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 7 with AnalysisException

use of org.jf.dexlib2.analysis.AnalysisException in project smali by JesusFreke.

the class MethodAnalyzer method analyzeMoveResult.

private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) {
    AnalyzedInstruction previousInstruction = null;
    if (analyzedInstruction.instructionIndex > 0) {
        previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex - 1);
    }
    if (previousInstruction == null || !previousInstruction.instruction.getOpcode().setsResult()) {
        throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " + "invoke-*/fill-new-array instruction");
    }
    RegisterType resultRegisterType;
    ReferenceInstruction invokeInstruction = (ReferenceInstruction) previousInstruction.instruction;
    Reference reference = invokeInstruction.getReference();
    if (reference instanceof MethodReference) {
        resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference) reference).getReturnType());
    } else {
        resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference) reference);
    }
    setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType);
}
Also used : BaseMethodReference(org.jf.dexlib2.base.reference.BaseMethodReference) TypeReference(org.jf.dexlib2.iface.reference.TypeReference) ImmutableMethodReference(org.jf.dexlib2.immutable.reference.ImmutableMethodReference) Reference(org.jf.dexlib2.iface.reference.Reference) FieldReference(org.jf.dexlib2.iface.reference.FieldReference) ImmutableFieldReference(org.jf.dexlib2.immutable.reference.ImmutableFieldReference) MethodReference(org.jf.dexlib2.iface.reference.MethodReference) BaseMethodReference(org.jf.dexlib2.base.reference.BaseMethodReference) ImmutableMethodReference(org.jf.dexlib2.immutable.reference.ImmutableMethodReference) MethodReference(org.jf.dexlib2.iface.reference.MethodReference) TypeReference(org.jf.dexlib2.iface.reference.TypeReference)

Example 8 with AnalysisException

use of org.jf.dexlib2.analysis.AnalysisException 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 9 with AnalysisException

use of org.jf.dexlib2.analysis.AnalysisException 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)5 IOException (java.io.IOException)2 AnalysisException (org.jf.dexlib2.analysis.AnalysisException)2 AnalyzedInstruction (org.jf.dexlib2.analysis.AnalyzedInstruction)2 MethodAnalyzer (org.jf.dexlib2.analysis.MethodAnalyzer)2 BaseMethodReference (org.jf.dexlib2.base.reference.BaseMethodReference)2 FieldReference (org.jf.dexlib2.iface.reference.FieldReference)2 MethodReference (org.jf.dexlib2.iface.reference.MethodReference)2 TypeReference (org.jf.dexlib2.iface.reference.TypeReference)2 ImmutableFieldReference (org.jf.dexlib2.immutable.reference.ImmutableFieldReference)2 ImmutableMethodReference (org.jf.dexlib2.immutable.reference.ImmutableMethodReference)2 ExceptionWithContext (org.jf.util.ExceptionWithContext)2 IndentingWriter (org.jf.util.IndentingWriter)2 DebugMethodItem (com.taobao.android.baksmali.adaptors.Debug.DebugMethodItem)1 EndPrologueMethodItem (com.taobao.android.baksmali.adaptors.Debug.EndPrologueMethodItem)1 BitSet (java.util.BitSet)1 DebugMethodItem (org.jf.baksmali.Adaptors.Debug.DebugMethodItem)1 Reference (org.jf.dexlib2.iface.reference.Reference)1