public void addInstruction(@Nonnull BuilderInstruction instruction) { MethodLocation last = instructionList.get(instructionList.size() - 1); last.instruction = instruction; instruction.location = last; int nextCodeAddress = last.codeAddress + instruction.getCodeUnits(); instructionList.add(new MethodLocation(null, nextCodeAddress, instructionList.size())); this.fixInstructions = true; }
int codeAddress = first.codeAddress + first.instruction.getCodeUnits(); for (int i = index1 + 1; i <= index2; i++) { MethodLocation location = instructionList.get(i); codeAddress += location.instruction.getCodeUnits();
public void replaceInstruction(int index, @Nonnull BuilderInstruction replacementInstruction) { if (index >= instructionList.size() - 1) { throw new IndexOutOfBoundsException(); } MethodLocation replaceLocation = instructionList.get(index); replacementInstruction.location = replaceLocation; BuilderInstruction old = replaceLocation.instruction; assert old != null; old.location = null; replaceLocation.instruction = replacementInstruction; // TODO: factor out index/address fix up loop int codeAddress = replaceLocation.codeAddress + replaceLocation.instruction.getCodeUnits(); for (int i = index + 1; i < instructionList.size(); i++) { MethodLocation location = instructionList.get(i); location.codeAddress = codeAddress; Instruction instruction = location.getInstruction(); if (instruction != null) { codeAddress += instruction.getCodeUnits(); } else { assert i == instructionList.size() - 1; } } this.fixInstructions = true; }
public void addInstruction(int index, BuilderInstruction instruction) { // the end check here is intentially >= rather than >, because the list always includes an "empty" // (null instruction) MethodLocation at the end. To add an instruction to the end of the list, the user would // provide the index of this empty item, which would be size() - 1. if (index >= instructionList.size()) { throw new IndexOutOfBoundsException(); } if (index == instructionList.size() - 1) { addInstruction(instruction); return; } int codeAddress = instructionList.get(index).getCodeAddress(); MethodLocation newLoc = new MethodLocation(instruction, codeAddress, index); instructionList.add(index, newLoc); instruction.location = newLoc; codeAddress += instruction.getCodeUnits(); for (int i = index + 1; i < instructionList.size(); i++) { MethodLocation location = instructionList.get(i); location.index++; location.codeAddress = codeAddress; if (location.instruction != null) { codeAddress += location.instruction.getCodeUnits(); } else { // only the last MethodLocation should have a null instruction assert i == instructionList.size() - 1; } } this.fixInstructions = true; }
void peepUninitializedInstanceThisReference() { List<Integer> peepAddresses = addresses.stream().filter(this::canPeepUninitializedInstanceThisReference).collect(Collectors.toList()); if (0 == peepAddresses.size()) { return; } madeChanges = true; peepCount += peepAddresses.size(); Collections.sort(peepAddresses, Collections.reverseOrder()); for (int address : peepAddresses) { BuilderInstruction replacement = buildUninitializedInstanceReferenceResultReplacement(address); manipulator.replaceInstruction(address, replacement); int nextAddress = address + replacement.getCodeUnits(); manipulator.removeInstruction(nextAddress); } }
void peepClassForName() { List<Integer> peepAddresses = addresses.stream().filter(this::canPeepClassForName).collect(Collectors.toList()); if (0 == peepAddresses.size()) { return; } madeChanges = true; peepCount += peepAddresses.size(); Collections.sort(peepAddresses, Collections.reverseOrder()); for (int address : peepAddresses) { BuilderInstruction original = manipulator.getInstruction(address); int nextAddress = address + original.getCodeUnits(); if (addresses.contains(nextAddress)) { BuilderInstruction nextInstruction = manipulator.getInstruction(nextAddress); if (nextInstruction.getOpcode().name.startsWith("move-result")) { // There is a move-result after the instruction being replaced. "Deal" with it. manipulator.removeInstruction(nextAddress); } } BuilderInstruction replacement = buildClassForNameReplacement(address); manipulator.replaceInstruction(address, replacement); } }
private void removeMoveResultIfNecessary(int address) { BuilderInstruction instruction = manipulator.getInstruction(address); int nextAddress = address + instruction.getCodeUnits(); BuilderInstruction nextInstr = manipulator.getInstruction(nextAddress); String opName = nextInstr.getOpcode().name; if (opName.startsWith("move-result")) { manipulator.removeInstruction(nextAddress); } }
public void replaceInstruction(int insertAddress, List<BuilderInstruction> instructions) { recreateOrExecuteAgain = false; int address = insertAddress; for (BuilderInstruction instruction : instructions) { addInstruction(address, instruction); address += instruction.getCodeUnits(); } MethodLocation location = getLocation(address); recreateOrExecuteAgain = true; removeInstruction(location); }
private void setupInstruction(BuilderInstruction instruction, Opcode opcode) { when(location.getInstruction()).thenReturn(instruction); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); when(instruction.getOpcode()).thenReturn(opcode); }
private BuilderInstruction buildInstruction22t(Opcode opcode, int offset) { BuilderInstruction instruction = mock(BuilderInstruction.class, withSettings().extraInterfaces(Instruction22t.class)); when(location.getInstruction()).thenReturn(instruction); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); when(instruction.getOpcode()).thenReturn(opcode); when(((Instruction22t) instruction).getRegisterA()).thenReturn(ARG1_REGISTER); when(((Instruction22t) instruction).getRegisterB()).thenReturn(ARG2_REGISTER); when(((Instruction22t) instruction).getCodeOffset()).thenReturn(offset); return instruction; }
private static Set<Integer> getExceptionHandlerAddresses(ExecutionGraphManipulator manipulator) { int[] allAddresses = manipulator.getAddresses(); Arrays.sort(allAddresses); int highestAddress = allAddresses[allAddresses.length - 1]; Set<Integer> handlerAddresses = new HashSet<>(); List<BuilderTryBlock> tryBlocks = manipulator.getTryBlocks(); for (BuilderTryBlock tryBlock : tryBlocks) { List<? extends BuilderExceptionHandler> handlers = tryBlock.getExceptionHandlers(); for (BuilderExceptionHandler handler : handlers) { int address = handler.getHandlerCodeAddress(); BuilderInstruction instruction = manipulator.getInstruction(address); while (address < highestAddress) { // Add all instructions until return, goto, etc. handlerAddresses.add(address); address += instruction.getCodeUnits(); instruction = manipulator.getInstruction(address); if (!instruction.getOpcode().canContinue()) { break; } } } } return handlerAddresses; }
@Before public void setUp() { vm = mock(VirtualMachine.class); classManager = mock(ClassManager.class); when(vm.getClassManager()).thenReturn(classManager); location = mock(MethodLocation.class); instruction = mock(BuilderInstruction.class, withSettings().extraInterfaces(SwitchPayload.class)); when(location.getInstruction()).thenReturn(instruction); when(location.getCodeAddress()).thenReturn(ADDRESS); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); addressToLocation = new TIntObjectHashMap<MethodLocation>(); addressToLocation.put(ADDRESS, location); opFactory = new SwitchPayloadOpFactory(); }
boolean canPeepUninitializedInstanceThisReference(int address) { Op op = manipulator.getOp(address); if (!op.getName().startsWith("invoke-virtual")) { return false; } InvokeOp invokeOp = (InvokeOp) op; int instanceRegister = invokeOp.getParameterRegisters()[0]; HeapItem item = manipulator.getRegisterConsensus(address, instanceRegister); if (!item.getType().equals(manipulator.getMethod().getClassName())) { // It's a "this" reference. It'll probably be unknown after invoking if it wasn't handled by InvokeOp. return false; } String methodSignature = ((InvokeOp) op).getMethod().getSignature(); // May eventually add a few other methods here if (!methodSignature.equals(OBJECT_GET_CLASS_SIGNATURE)) { return false; } BuilderInstruction original = manipulator.getInstruction(address); int nextAddress = address + original.getCodeUnits(); if (!addresses.contains(nextAddress)) { return false; } BuilderInstruction nextInstruction = manipulator.getInstruction(nextAddress); if (!nextInstruction.getOpcode().name.startsWith("move-result")) { return false; } return true; }
@Before public void setUp() { vm = mock(VirtualMachine.class); mState = mock(MethodState.class); node = mock(ExecutionNode.class); item = mock(HeapItem.class); when(mState.readRegister(REGISTER_B)).thenReturn(item); location = mock(MethodLocation.class); instruction = mock(BuilderInstruction.class, withSettings().extraInterfaces(Instruction12x.class)); when(location.getInstruction()).thenReturn(instruction); when(location.getCodeAddress()).thenReturn(ADDRESS); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); when(((Instruction12x) instruction).getRegisterA()).thenReturn(REGISTER_A); when(((Instruction12x) instruction).getRegisterB()).thenReturn(REGISTER_B); addressToLocation = new TIntObjectHashMap<MethodLocation>(); addressToLocation.put(ADDRESS, location); opFactory = new UnaryMathOpFactory(); }
@Before public void setUp() { vm = mock(VirtualMachine.class); node = mock(ExecutionNode.class); mState = mock(MethodState.class); location = mock(MethodLocation.class); instruction = mock(BuilderInstruction.class, withSettings().extraInterfaces(Instruction3rc.class, VariableRegisterInstruction.class, ReferenceInstruction.class, RegisterRangeInstruction.class)); when(location.getInstruction()).thenReturn(instruction); when(location.getCodeAddress()).thenReturn(ADDRESS); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); Reference ref = new ImmutableTypeReference("[I"); when(((ReferenceInstruction) instruction).getReference()).thenReturn(ref); addressToLocation = new TIntObjectHashMap<MethodLocation>(); addressToLocation.put(ADDRESS, location); opFactory = new FilledNewArrayOpFactory(); }
@Before public void setUp() { vm = mock(VirtualMachine.class); mState = mock(MethodState.class); node = mock(ExecutionNode.class); setItem = ArgumentCaptor.forClass(HeapItem.class); itemB = mock(HeapItem.class); when(itemB.isUnknown()).thenReturn(false); when(mState.readRegister(REGISTER_B)).thenReturn(itemB); itemC = mock(HeapItem.class); when(itemC.isUnknown()).thenReturn(false); when(mState.readRegister(REGISTER_C)).thenReturn(itemC); location = mock(MethodLocation.class); instruction = mock(BuilderInstruction.class, withSettings().extraInterfaces(Instruction23x.class)); when(location.getInstruction()).thenReturn(instruction); when(location.getCodeAddress()).thenReturn(ADDRESS); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); when(((Instruction23x) instruction).getRegisterA()).thenReturn(REGISTER_A); when(((Instruction23x) instruction).getRegisterB()).thenReturn(REGISTER_B); when(((Instruction23x) instruction).getRegisterC()).thenReturn(REGISTER_C); addressToLocation = new TIntObjectHashMap<MethodLocation>(); addressToLocation.put(ADDRESS, location); opFactory = new CmpOpFactory(); }
@Before public void setUp() { vm = mock(VirtualMachine.class); ectx = mock(ExecutionContext.class); mState = mock(MethodState.class); when(ectx.getMethodState()).thenReturn(mState); node = mock(ExecutionNode.class); itemA = mock(HeapItem.class); when(mState.readRegister(REGISTER_A)).thenReturn(itemA); itemB = mock(HeapItem.class); when(mState.readRegister(REGISTER_B)).thenReturn(itemB); setItem = ArgumentCaptor.forClass(HeapItem.class); location = mock(MethodLocation.class); when(location.getCodeAddress()).thenReturn(ADDRESS); instruction = mock(BuilderInstruction.class, withSettings().extraInterfaces(Instruction22c.class)); when(location.getInstruction()).thenReturn(instruction); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); when(((Instruction22c) instruction).getRegisterA()).thenReturn(REGISTER_A); when(((Instruction22c) instruction).getRegisterB()).thenReturn(REGISTER_B); FieldReference fieldRef = new ImmutableFieldReference("Lsome/class;", "someMethod", "I"); when(((Instruction22c) instruction).getReference()).thenReturn(fieldRef); addressToLocation = new TIntObjectHashMap<MethodLocation>(); addressToLocation.put(ADDRESS, location); opFactory = new IPutOpFactory(); }
@Before public void setUp() { vm = mock(VirtualMachine.class); ectx = mock(ExecutionContext.class); mState = mock(MethodState.class); when(ectx.getMethodState()).thenReturn(mState); node = mock(ExecutionNode.class); itemB = mock(HeapItem.class); when(mState.readRegister(REGISTER_B)).thenReturn(itemB); setItem = ArgumentCaptor.forClass(HeapItem.class); location = mock(MethodLocation.class); instruction = mock(BuilderInstruction.class, withSettings().extraInterfaces(Instruction22c.class)); when(location.getInstruction()).thenReturn(instruction); when(location.getCodeAddress()).thenReturn(ADDRESS); when(instruction.getLocation()).thenReturn(location); when(instruction.getCodeUnits()).thenReturn(0); when(((Instruction22c) instruction).getRegisterA()).thenReturn(REGISTER_A); when(((Instruction22c) instruction).getRegisterB()).thenReturn(REGISTER_B); FieldReference fieldRef = new ImmutableFieldReference("Lsome/class;", "someMethod", "I"); when(((Instruction22c) instruction).getReference()).thenReturn(fieldRef); addressToLocation = new TIntObjectHashMap<MethodLocation>(); addressToLocation.put(ADDRESS, location); opFactory = new IGetOpFactory(); }
@Override public Op create(MethodLocation location, TIntObjectMap<MethodLocation> addressToLocation, VirtualMachine vm) { BuilderInstruction instruction = (BuilderInstruction) location.getInstruction(); int address = instruction.getLocation().getCodeAddress(); int returnAddress = address + instruction.getCodeUnits(); MethodLocation returnLocation = addressToLocation.get(returnAddress); int branchOffset = ((OffsetInstruction) instruction).getCodeOffset(); int childAddress = address + branchOffset; MethodLocation child = addressToLocation.get(childAddress); Instruction31t instr = (Instruction31t) location.getInstruction(); int register = instr.getRegisterA(); return new FillArrayDataOp(location, child, returnLocation, register); } }
BuilderInstruction buildUninitializedInstanceReferenceResultReplacement(int address) { InvokeOp invokeOp = (InvokeOp) manipulator.getOp(address); int instanceRegister = invokeOp.getParameterRegisters()[0]; HeapItem item = manipulator.getRegisterConsensus(address, instanceRegister); BuilderInstruction original = manipulator.getInstruction(address); int nextAddress = address + original.getCodeUnits(); MoveOp moveOp = (MoveOp) manipulator.getOp(nextAddress); int destRegsiter = moveOp.getToRegister(); ReferenceInstruction instr = (ReferenceInstruction) original; String methodDescriptor = ReferenceUtil.getReferenceString(instr.getReference()); BuilderInstruction replacementInstruction = null; if (methodDescriptor.equals(OBJECT_GET_CLASS_SIGNATURE)) { String smaliClassName = item.getType(); BuilderTypeReference classRef = manipulator.getDexBuilder().internTypeReference(smaliClassName); replacementInstruction = new BuilderInstruction21c(Opcode.CONST_CLASS, destRegsiter, classRef); } return replacementInstruction; }