Search in sources :

Example 11 with RegisterType

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

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

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

the class PreInstructionRegisterInfoMethodItem method writeRegisterInfo.

private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers, BitSet fullMergeRegisters) throws IOException {
    boolean firstRegister = true;
    boolean previousWasFullMerge = false;
    int registerNum = registers.nextSetBit(0);
    if (registerNum < 0) {
        return false;
    }
    writer.write('#');
    for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
        boolean fullMerge = fullMergeRegisters != null && fullMergeRegisters.get(registerNum);
        if (fullMerge) {
            if (!firstRegister) {
                writer.write('\n');
                writer.write('#');
            }
            writeFullMerge(writer, registerNum);
            previousWasFullMerge = true;
        } else {
            if (previousWasFullMerge) {
                writer.write('\n');
                writer.write('#');
                previousWasFullMerge = false;
            }
            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
            registerFormatter.writeTo(writer, registerNum);
            writer.write('=');
            registerType.writeTo(writer);
            writer.write(';');
        }
        firstRegister = false;
    }
    return true;
}
Also used : RegisterType(org.jf.dexlib2.analysis.RegisterType)

Example 14 with RegisterType

use of org.jf.dexlib2.analysis.RegisterType 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)

Example 15 with RegisterType

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

the class PostInstructionRegisterInfoMethodItem method writeRegisterInfo.

private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers) throws IOException {
    int registerNum = registers.nextSetBit(0);
    if (registerNum < 0) {
        return false;
    }
    writer.write('#');
    for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
        RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum);
        registerFormatter.writeTo(writer, registerNum);
        writer.write('=');
        registerType.writeTo(writer);
        writer.write(';');
    }
    return true;
}
Also used : RegisterType(org.jf.dexlib2.analysis.RegisterType)

Aggregations

RegisterType (org.jf.dexlib2.analysis.RegisterType)7 TypeReference (org.jf.dexlib2.iface.reference.TypeReference)7 Opcode (org.jf.dexlib2.Opcode)4 FieldReference (org.jf.dexlib2.iface.reference.FieldReference)4 ImmutableFieldReference (org.jf.dexlib2.immutable.reference.ImmutableFieldReference)4 AnalyzedInstruction (org.jf.dexlib2.analysis.AnalyzedInstruction)3 BaseMethodReference (org.jf.dexlib2.base.reference.BaseMethodReference)3 MethodReference (org.jf.dexlib2.iface.reference.MethodReference)3 ImmutableMethodReference (org.jf.dexlib2.immutable.reference.ImmutableMethodReference)3 Instruction22c (org.jf.dexlib2.iface.instruction.formats.Instruction22c)2 Reference (org.jf.dexlib2.iface.reference.Reference)2 ExceptionWithContext (org.jf.util.ExceptionWithContext)2 JavaCodeFragment (com.intellij.psi.JavaCodeFragment)1 JavaRecursiveElementVisitor (com.intellij.psi.JavaRecursiveElementVisitor)1 PsiElement (com.intellij.psi.PsiElement)1 PsiLocalVariable (com.intellij.psi.PsiLocalVariable)1 LazyValue (org.jf.smalidea.debugging.value.LazyValue)1 SmaliInstruction (org.jf.smalidea.psi.impl.SmaliInstruction)1 SmaliMethod (org.jf.smalidea.psi.impl.SmaliMethod)1