private void analyzeBinary2AddrOp(@Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { if (checkForBoolean) { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; RegisterType source1RegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA()); RegisterType source2RegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (BooleanCategories.get(source1RegisterType.category) && BooleanCategories.get(source2RegisterType.category)) { destRegisterType = RegisterType.BOOLEAN_TYPE; } } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); }
instructionToAnalyze.restoreOdexedInstruction(); analyzedState.set(instructionToAnalyze.getInstructionIndex()); instructionsToAnalyze.set(successor.getInstructionIndex()); AnalyzedInstruction analyzedInstruction = analyzedInstructions.valueAt(i); Instruction instruction = analyzedInstruction.getInstruction(); analyzedInstruction.setDeodexedInstruction( new UnresolvedOdexInstruction(instruction, objectRegisterNumber));
private void analyzeNewInstance(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; int register = ((OneRegisterInstruction)analyzedInstruction.instruction).getRegisterA(); RegisterType destRegisterType = analyzedInstruction.getPostInstructionRegisterType(register); if (destRegisterType.category != RegisterType.UNKNOWN) { //the post-instruction destination register will only be set if we have already analyzed this instruction //at least once. If this is the case, then the uninit reference has already been propagated to all //successors and nothing else needs to be done. assert destRegisterType.category == RegisterType.UNINIT_REF; return; } TypeReference typeReference = (TypeReference)instruction.getReference(); RegisterType classType = RegisterType.getRegisterType(classPath, typeReference); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterType(RegisterType.UNINIT_REF, classType.type)); }
private void propagateRegisterToSuccessors(@Nonnull AnalyzedInstruction instruction, int registerNumber, @Nonnull BitSet changedInstructions, boolean override) { RegisterType postRegisterType = instruction.getPostInstructionRegisterType(registerNumber); for (AnalyzedInstruction successor: instruction.successors) { if (successor.mergeRegister(registerNumber, postRegisterType, analyzedState, override)) { changedInstructions.set(successor.instructionIndex); } } }
private void analyzeInvokeDirectCommon(@Nonnull AnalyzedInstruction analyzedInstruction, int objectRegister) { // This handles the case of invoking a constructor on an uninitialized reference. This propagates the // initialized type for the object register, and also any known aliased registers. // // In some cases, unrelated uninitialized references may not have been propagated past this instruction. This // happens when propagating those types and the type of object register of this instruction isn't known yet. // In this case, we can't determine if the uninitialized reference being propagated in an alias of the object // register, so we don't stop propagation. // // We check for any of these unpropagated uninitialized references here and propagate them. if (analyzedInstruction.isInvokeInit()) { RegisterType uninitRef = analyzedInstruction.getPreInstructionRegisterType(objectRegister); if (uninitRef.category != RegisterType.UNINIT_REF && uninitRef.category != RegisterType.UNINIT_THIS) { assert analyzedInstruction.getSetRegisters().isEmpty(); return; } RegisterType initRef = RegisterType.getRegisterType(RegisterType.REFERENCE, uninitRef.type); for (int register: analyzedInstruction.getSetRegisters()) { RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register); if (registerType == uninitRef) { setPostRegisterTypeAndPropagateChanges(analyzedInstruction, register, initRef); } else { // This is unrelated uninitialized reference. propagate it as-is setPostRegisterTypeAndPropagateChanges(analyzedInstruction, register, registerType); } } } }
static boolean canPropagateTypeAfterInstanceOf(AnalyzedInstruction analyzedInstanceOfInstruction, AnalyzedInstruction analyzedIfInstruction, ClassPath classPath) { if (!classPath.isArt()) { return false; } Instruction ifInstruction = analyzedIfInstruction.instruction; if (((Instruction21t)ifInstruction).getRegisterA() == analyzedInstanceOfInstruction.getDestinationRegister()) { Reference reference = ((Instruction22c)analyzedInstanceOfInstruction.getInstruction()).getReference(); RegisterType registerType = RegisterType.getRegisterType(classPath, (TypeReference)reference); try { if (registerType.type != null && !registerType.type.isInterface()) { int objectRegister = ((TwoRegisterInstruction)analyzedInstanceOfInstruction.getInstruction()) .getRegisterB(); RegisterType originalType = analyzedIfInstruction.getPreInstructionRegisterType(objectRegister); return isNotWideningConversion(originalType, registerType); } } catch (UnresolvedClassException ex) { return false; } } return false; }
setRegisters.add(getDestinationRegister()); setRegisters.add(getDestinationRegister() + 1); if (isInvokeInit()) { RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(destinationRegister); if (preInstructionDestRegisterType.category == RegisterType.UNINIT_REF || preInstructionDestRegisterType.category == RegisterType.UNINIT_THIS) { getPredecessorCount() == 1 && (instruction.getOpcode() == Opcode.IF_EQZ || instruction.getOpcode() == Opcode.IF_NEZ)) { ((TwoRegisterInstruction)prevPrevAnalyzedInstruction.instruction); RegisterType originalType = prevPrevAnalyzedInstruction.getPostInstructionRegisterType( moveInstruction.getRegisterB()); if (moveInstruction.getRegisterA() != instanceOfInstruction.getRegisterB()) {
int instructionIndex = analyzedInstruction.getInstructionIndex(); if (instructionIndex > 0) { if (analyzedInstruction.getPredecessorCount() != 1) { return; AnalyzedInstruction prevAnalyzedInstruction = analyzedInstruction.getPredecessors().first(); if (prevAnalyzedInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF) { analyzedInstruction.getInstructionIndex() + 1); RegisterType originalType = analyzedInstruction.getPreInstructionRegisterType(narrowingRegister); (TypeReference)instanceOfInstruction.getReference()); for (int register : analyzedInstruction.getSetRegisters()) { if (analyzedInstruction.instruction.getOpcode() == Opcode.IF_EQZ) { overridePredecessorRegisterTypeAndPropagateChanges(fallthroughInstruction,
private void addMergeRegs(BitSet registers, int registerCount) { if (analyzedInstruction.getPredecessorCount() <= 1) { //in the common case of an instruction that only has a single predecessor which is the previous //instruction, the pre-instruction registers will always match the previous instruction's //post-instruction registers return; } for (int registerNum=0; registerNum<registerCount; registerNum++) { RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum); for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum); if (predecessorRegisterType.category != RegisterType.UNKNOWN && !predecessorRegisterType.equals(mergedRegisterType)) { registers.set(registerNum); } } } }
private void writeFullMerge(IndentingWriter writer, int registerNum) throws IOException { registerFormatter.writeTo(writer, registerNum); writer.write('='); analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer); writer.write(":merge{"); boolean first = true; for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum); if (!first) { writer.write(','); } if (predecessor.getInstructionIndex() == -1) { //the fake "StartOfMethod" instruction writer.write("Start:"); } else { writer.write("0x"); writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor)); writer.write(':'); } predecessorRegisterType.writeTo(writer); first = false; } writer.write('}'); }
private void addMergeRegs(BitSet registers, int registerCount) { if (analyzedInstruction.getPredecessorCount() <= 1) { //in the common case of an instruction that only has a single predecessor which is the previous //instruction, the pre-instruction registers will always match the previous instruction's //post-instruction registers return; } for (int registerNum=0; registerNum<registerCount; registerNum++) { RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum); for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { RegisterType predecessorRegisterType = analyzedInstruction.getPredecessorRegisterType( predecessor, registerNum); if (predecessorRegisterType.category != RegisterType.UNKNOWN && !predecessorRegisterType.equals(mergedRegisterType)) { registers.set(registerNum); } } } }
private void writeFullMerge(IndentingWriter writer, int registerNum) throws IOException { registerFormatter.writeTo(writer, registerNum); writer.write('='); analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer); writer.write(":merge{"); boolean first = true; for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { RegisterType predecessorRegisterType = analyzedInstruction.getPredecessorRegisterType( predecessor, registerNum); if (!first) { writer.write(','); } if (predecessor.getInstructionIndex() == -1) { //the fake "StartOfMethod" instruction writer.write("Start:"); } else { writer.write("0x"); writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor)); writer.write(':'); } predecessorRegisterType.writeTo(writer); first = false; } writer.write('}'); }
private void addDestRegs(BitSet printPostRegister, int registerCount) { for (int registerNum=0; registerNum<registerCount; registerNum++) { if (!analyzedInstruction.getPreInstructionRegisterType(registerNum).equals( analyzedInstruction.getPostInstructionRegisterType(registerNum))) { printPostRegister.set(registerNum); } } }
if (isInvokeInit()) { int destinationRegister; if (instruction instanceof FiveRegisterInstruction) { return true; RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(registerNumber); if (preInstructionDestRegisterType.category != RegisterType.UNINIT_REF && preInstructionDestRegisterType.category != RegisterType.UNINIT_THIS) { if (getPreInstructionRegisterType(registerNumber).equals(preInstructionDestRegisterType)) { return true; if (!setsRegister()) { return false; int destinationRegister = getDestinationRegister(); if (setsWideRegister() && registerNumber == (destinationRegister + 1)) { return true;
private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, @Nonnull AnalyzedInstruction successor, @Nonnull AnalyzedInstruction[][] exceptionHandlers, @Nonnull BitSet instructionsToProcess, boolean allowMoveException) { if (!allowMoveException && successor.instruction.getOpcode() == Opcode.MOVE_EXCEPTION) { throw new AnalysisException("Execution can pass from the " + predecessor.instruction.getOpcode().name + " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) + " to the move-exception instruction at address 0x" + Integer.toHexString(getInstructionAddress(successor))); } if (!successor.addPredecessor(predecessor)) { return; } predecessor.addSuccessor(successor); instructionsToProcess.set(successor.getInstructionIndex()); //if the successor can throw an instruction, then we need to add the exception handlers as additional //successors to the predecessor (and then apply this same logic recursively if needed) //Technically, we should handle the monitor-exit instruction as a special case. The exception is actually //thrown *after* the instruction executes, instead of "before" the instruction executes, lke for any other //instruction. But since it doesn't modify any registers, we can treat it like any other instruction. AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex]; if (exceptionHandlersForSuccessor != null) { //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction //can throw an exception assert successor.instruction.getOpcode().canThrow(); for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) { addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, instructionsToProcess, true); } } }
this, currentCodeAddress, instruction.getInstruction()); if (instruction.getInstruction().getOpcode().format == Format.UnresolvedOdexInstruction) { methodItems.add(new CommentedOutMethodItem( InstructionMethodItemFactory.makeInstructionFormatMethodItem( this, currentCodeAddress, instruction.getOriginalInstruction()))); !instruction.getInstruction().getOpcode().format.isPayloadFormat) { methodItems.add( new PreInstructionRegisterInfoMethodItem(classDef.options.registerInfo, currentCodeAddress += instruction.getInstruction().getCodeUnits();
@Override public boolean writeTo(IndentingWriter writer) throws IOException { int registerCount = analyzedInstruction.getRegisterCount(); BitSet registers = new BitSet(registerCount); BitSet mergeRegisters = null; if (analyzedInstruction.isBeginningInstruction()) { addParamRegs(registers, registerCount); addMergeRegs(mergeRegisters, registerCount); } else if ((registerInfo & baksmaliOptions.FULLMERGE) != 0 && (analyzedInstruction.isBeginningInstruction())) { addParamRegs(registers, registerCount);
private void addArgsRegs(BitSet registers) { if (analyzedInstruction.getInstruction() instanceof RegisterRangeInstruction) { RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction(); } else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) { FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction(); int regCount = instruction.getRegisterCount(); switch (regCount) { registers.set(instruction.getRegisterC()); } else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction(); registers.set(instruction.getRegisterA()); registers.set(instruction.getRegisterB()); registers.set(instruction.getRegisterC()); } else if (analyzedInstruction.getInstruction() instanceof TwoRegisterInstruction) { TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction(); registers.set(instruction.getRegisterA()); registers.set(instruction.getRegisterB()); } else if (analyzedInstruction.getInstruction() instanceof OneRegisterInstruction) { OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.getInstruction(); registers.set(instruction.getRegisterA());
@Override public void deOdex(DexFile parentFile, Method method, ClassPath cp) { if (!(parentFile instanceof DexBackedOdexFile)) { throw new RuntimeException("ODEX instruction in non-ODEX file"); } DexBackedOdexFile odexFile = (DexBackedOdexFile) parentFile; InlineMethodResolver inlineMethodResolver = InlineMethodResolver.createInlineMethodResolver(odexFile.getOdexVersion()); MethodAnalyzer analyzer = new MethodAnalyzer(cp, method, inlineMethodResolver, false); targetMethod = inlineMethodResolver.resolveExecuteInline(new AnalyzedInstruction(analyzer, instruction, -1, -1)); }
@Override public boolean writeTo(IndentingWriter writer) throws IOException { int registerInfo = registerFormatter.options.registerInfo; int registerCount = analyzedInstruction.getRegisterCount(); BitSet registers = new BitSet(registerCount); if ((registerInfo & baksmaliOptions.ALL) != 0) { registers.set(0, registerCount); } else { if ((registerInfo & baksmaliOptions.ALLPOST) != 0) { registers.set(0, registerCount); } else if ((registerInfo & baksmaliOptions.DEST) != 0) { addDestRegs(registers, registerCount); } } return writeRegisterInfo(writer, registers); }