private void propagateChanges(@Nonnull BitSet changedInstructions, int registerNumber, boolean override) { //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on //the next iteration of the while loop. //This could also be done recursively, but in large methods it would likely cause very deep recursion. while (!changedInstructions.isEmpty()) { for (int instructionIndex=changedInstructions.nextSetBit(0); instructionIndex>=0; instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) { changedInstructions.clear(instructionIndex); propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber, changedInstructions, override); } } }
private int getNextFieldOffset() { SparseArray<FieldReference> instanceFields = getInstanceFields(); if (instanceFields.size() == 0) { return classPath.isArt() ? 0 : 8; } int lastItemIndex = instanceFields.size()-1; int fieldOffset = instanceFields.keyAt(lastItemIndex); FieldReference lastField = instanceFields.valueAt(lastItemIndex); if (classPath.isArt()) { return fieldOffset + getTypeSize(lastField.getType().charAt(0)); } else { switch (lastField.getType().charAt(0)) { case 'J': case 'D': return fieldOffset + 8; default: return fieldOffset + 4; } } }
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); }
AnalyzedInstruction instruction = analyzedInstructions.valueAt(i); Opcode instructionOpcode = instruction.instruction.getOpcode(); currentCodeAddress = getInstructionAddress(instruction); 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); AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex+1); addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess);
for (int i=0; i<superFields.size(); i++) { int offset = superFields.keyAt(i); field = superFields.valueAt(i); linkedFields.put(offset, field); lastOffset = offset;
if (prevAnalyzedInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF) { AnalyzedInstruction fallthroughInstruction = analyzedInstructions.valueAt( analyzedInstruction.getInstructionIndex() + 1);
private void propagateChanges(@Nonnull BitSet changedInstructions, int registerNumber, boolean override) { //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on //the next iteration of the while loop. //This could also be done recursively, but in large methods it would likely cause very deep recursion. while (!changedInstructions.isEmpty()) { for (int instructionIndex=changedInstructions.nextSetBit(0); instructionIndex>=0; instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) { changedInstructions.clear(instructionIndex); propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber, changedInstructions, override); } } }
@Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); BaksmaliOptions options = getOptions(); try { for (ClassDef classDef: dexFile.getClasses()) { ClassProto classProto = (ClassProto) options.classPath.getClass(classDef); SparseArray<FieldReference> fields = classProto.getInstanceFields(); String className = "Class " + classDef.getType() + " : " + fields.size() + " instance fields\n"; System.out.write(className.getBytes()); for (int i=0;i<fields.size();i++) { String field = fields.keyAt(i) + ":" + fields.valueAt(i).getType() + " " + fields.valueAt(i).getName() + "\n"; System.out.write(field.getBytes()); } System.out.write("\n".getBytes()); } System.out.close(); } catch (IOException ex) { throw new RuntimeException(ex); } }
@Override public void run() { if (help || inputList == null || inputList.isEmpty()) { usage(); return; } if (inputList.size() > 1) { System.err.println("Too many files specified"); usage(); return; } String input = inputList.get(0); loadDexFile(input); BaksmaliOptions options = getOptions(); try { for (ClassDef classDef: dexFile.getClasses()) { ClassProto classProto = (ClassProto) options.classPath.getClass(classDef); SparseArray<FieldReference> fields = classProto.getInstanceFields(); String className = "Class " + classDef.getType() + " : " + fields.size() + " instance fields\n"; System.out.write(className.getBytes()); for (int i=0;i<fields.size();i++) { String field = fields.keyAt(i) + ":" + fields.valueAt(i).getType() + " " + fields.valueAt(i).getName() + "\n"; System.out.write(field.getBytes()); } System.out.write("\n".getBytes()); } System.out.close(); } catch (IOException ex) { throw new RuntimeException(ex); } }
private void setPostRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, int registerNumber, @Nonnull RegisterType registerType) { BitSet changedInstructions = new BitSet(analyzedInstructions.size()); if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) { return; } propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions); //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on //the next iteration of the while loop. //This could also be done recursively, but in large methods it would likely cause very deep recursion, //which requires the user to specify a larger stack size. This isn't really a problem, but it is slightly //annoying. while (!changedInstructions.isEmpty()) { for (int instructionIndex=changedInstructions.nextSetBit(0); instructionIndex>=0; instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) { changedInstructions.clear(instructionIndex); propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber, changedInstructions); } } if (registerType.category == RegisterType.LONG_LO) { checkWidePair(registerNumber, analyzedInstruction); setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.LONG_HI_TYPE); } else if (registerType.category == RegisterType.DOUBLE_LO) { checkWidePair(registerNumber, analyzedInstruction); setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.DOUBLE_HI_TYPE); } }
private int getNextFieldOffset() { SparseArray<FieldReference> instanceFields = getInstanceFields(); if (instanceFields.size() == 0) { return 8; } int lastItemIndex = instanceFields.size()-1; int fieldOffset = instanceFields.keyAt(lastItemIndex); FieldReference lastField = instanceFields.valueAt(lastItemIndex); switch (lastField.getType().charAt(0)) { case 'J': case 'D': return fieldOffset + 8; default: return fieldOffset + 4; } }
private int getNextFieldOffset() { SparseArray<FieldReference> instanceFields = getInstanceFields(); if (instanceFields.size() == 0) { return classPath.isArt() ? 0 : 8; } int lastItemIndex = instanceFields.size()-1; int fieldOffset = instanceFields.keyAt(lastItemIndex); FieldReference lastField = instanceFields.valueAt(lastItemIndex); if (classPath.isArt()) { return fieldOffset + getTypeSize(lastField.getType().charAt(0)); } else { switch (lastField.getType().charAt(0)) { case 'J': case 'D': return fieldOffset + 8; default: return fieldOffset + 4; } } }
private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) { AnalyzedInstruction previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1); if (!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); }
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); }
if (superFields != null && superFieldCount > 0) { for (int i = 0; i < superFieldCount; i++) { instanceFields.append(superFields.keyAt(i), superFields.valueAt(i));
for (int i=0; i<superFields.size(); i++) { int offset = superFields.keyAt(i); field = superFields.valueAt(i); linkedFields.put(offset, field); lastOffset = offset;
if (prevAnalyzedInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF) { AnalyzedInstruction fallthroughInstruction = analyzedInstructions.valueAt( analyzedInstruction.getInstructionIndex() + 1);