public Throwable build(Op op, String className, String message) { String binaryName = ClassNameUtils.internalToBinary(className); try { @SuppressWarnings("unchecked") Class<Throwable> exceptionClass = (Class<Throwable>) vm.getClassLoader().loadClass(binaryName); return build(op, exceptionClass, message); } catch (Exception e) { e.printStackTrace(); } return new Exception(); } }
@Before public void setUp() throws ClassNotFoundException { vm = mock(VirtualMachine.class); classManager = mock(ClassManager.class); when(vm.getClassManager()).thenReturn(classManager); classLoader = mock(SmaliClassLoader.class); when(vm.getClassLoader()).thenReturn(classLoader); configuration = mock(Configuration.class); when(vm.getConfiguration()).thenReturn(configuration); mState = mock(MethodState.class); context = mock(ExecutionContext.class); when(context.getMethodState()).thenReturn(mState); method = new java_lang_Class_forName(); op = mock(Op.class); exceptionFactory = mock(ExceptionFactory.class); when(vm.getExceptionFactory()).thenReturn(exceptionFactory); }
@Override public void execute(VirtualMachine vm, Op op, ExecutionContext context) { MethodState mState = context.getMethodState(); String argumentType = mState.peekParameter(0).getType(); VirtualType virtualType = vm.getClassManager().getVirtualType(argumentType); try { Class<?> value = vm.getClassLoader().loadClass(virtualType.getBinaryName()); mState.assignReturnRegister(value, RETURN_TYPE); } catch (ClassNotFoundException e) { throw new RuntimeException("Class not found: " + argumentType, e); } }
private static Class<?> getTestClass() { try { String binaryName = ClassNameUtils.internalToBinary(CLASS_NAME); return VMTester.spawnVM().getClassLoader().loadClass(binaryName); } catch (ClassNotFoundException e) { e.printStackTrace(); return null; } }
@Override public NewArrayOp create(MethodLocation location, TIntObjectMap<MethodLocation> addressToLocation, VirtualMachine vm) { MethodLocation child = Utils.getNextLocation(location, addressToLocation); Instruction22c instr = (Instruction22c) location.getInstruction(); int destRegister = instr.getRegisterA(); int sizeRegister = instr.getRegisterB(); String arrayType = ReferenceUtil.getReferenceString(instr.getReference()); return new NewArrayOp(location, child, destRegister, sizeRegister, arrayType, vm.getClassLoader()); }
private static ExecutionContextMethod test(VirtualMachine vm, ExecutionContext context, String fieldName, String callingMethodSignature, boolean setAccessible) throws Exception { // Setup caller context ExecutionContext callerContext = vm.spawnRootContext(callingMethodSignature); Field callerContextField = ExecutionContext.class.getDeclaredField("callerContext"); callerContextField.setAccessible(true); callerContextField.set(context, callerContext); // Setup actual field to use as parameter ClassLoader classLoader = vm.getClassLoader(); Class<?> klazz = classLoader.loadClass(DUMMY_CLASS_NAME_BINARY); Constructor<?> ctor = klazz.getDeclaredConstructor(); ctor.setAccessible(true); Object instance = ctor.newInstance(); Field field = instance.getClass().getDeclaredField(fieldName); field.setAccessible(setAccessible); // Setup method state and arguments HeapItem fieldItem = new HeapItem(field, "Ljava/lang/reflect/Field;"); HeapItem instanceItem = new HeapItem(instance, DUMMY_CLASS_NAME); MethodState methodState = context.getMethodState(); methodState.pokeRegister(0, fieldItem); methodState.pokeRegister(1, instanceItem); ExecutionContextMethod fieldGet = new java_lang_reflect_Field_get(); fieldGet.execute(vm, null, context); return fieldGet; }
private void executeLocalObjectInit(MethodState callerMethodState) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { int instanceRegister = parameterRegisters[0]; HeapItem instanceItem = callerMethodState.peekRegister(instanceRegister); UninitializedInstance uninitializedInstance = (UninitializedInstance) instanceItem.getValue(); VirtualType instanceType = uninitializedInstance.getType(); // Create a Java class of the true type Class<?> klazz = vm.getClassLoader().loadClass(instanceType.getBinaryName()); Object newInstance = ObjectInstantiator.newInstance(klazz); HeapItem newInstanceItem = new HeapItem(newInstance, instanceType.getName()); callerMethodState.assignRegisterAndUpdateIdentities(instanceRegister, newInstanceItem); }
@Test public void invokeVirtualManyParametersThrowsNoExceptions() throws InstantiationException, IllegalAccessException, ClassNotFoundException { VirtualMachine vm = VMTester.spawnVM(); Class<?> virtualClass = vm.getClassLoader().loadClass(CLASS_NAME_BINARY); Object instance = virtualClass.newInstance(); initial.setRegisters(0, instance, CLASS_NAME, 1, 0x100L, "J", 3, 0x200L, "J", 5, 0x300L, "J", 7, 0x3, "I"); expected.setRegisters(MethodState.ResultRegister, 0x3, "I"); VMTester.test(CLASS_NAME, "invokeRangeManyParameters()V", initial, expected); }
@Test public void canInsertLocalClassAndClassIntoSameArray() throws ClassNotFoundException { String valueType = CommonTypes.CLASS; String arrayType = "[" + valueType; Object[] array = new Class<?>[2]; int index1 = 0; int index2 = 1; Class<?> value1 = String.class; String binaryClassName = ClassNameUtils.internalToBinary(CLASS_NAME); ClassLoader classLoader = VMTester.spawnVM().getClassLoader(); Class<?> value2 = classLoader.loadClass(binaryClassName); initial.setRegisters(0, array, arrayType, 1, index1, "I", 2, value1, valueType, 3, index2, "I", 4, value2, valueType); expected.setRegisters(0, new Class<?>[]{value1, value2}, arrayType); VMTester.test(CLASS_NAME, "putObjects()V", initial, expected); }
@Test public void invokeReturnIntReturnsInt() throws ClassNotFoundException, IllegalAccessException, InstantiationException { VirtualMachine vm = VMTester.spawnVM(); Class<?> virtualClass = vm.getClassLoader().loadClass(CLASS_NAME_BINARY); Object instance = virtualClass.newInstance(); initial.setRegisters(0, instance, CLASS_NAME); expected.setRegisters(MethodState.ResultRegister, 0x7, "I"); VMTester.test(CLASS_NAME, "invokeReturnInt()V", initial, expected); }
@Test public void invokeReturnVoidReturnsVoid() throws InstantiationException, IllegalAccessException, ClassNotFoundException { VirtualMachine vm = VMTester.spawnVM(true); Class<?> virtualClass = vm.getClassLoader().loadClass(CLASS_NAME_BINARY); Object instance = virtualClass.newInstance(); initial.setRegisters(0, instance, CLASS_NAME); ExecutionGraph graph = VMTester.execute(CLASS_NAME, "invokeReturnVoid()V", initial); HeapItem consensus = graph.getTerminatingRegisterConsensus(MethodState.ResultRegister); assertNull(consensus); }
@Test public void invokeGetClassOnSelfReturnsCorrectClass() throws InstantiationException, IllegalAccessException, ClassNotFoundException { VirtualMachine vm = VMTester.spawnVM(); Class<?> virtualClass = vm.getClassLoader().loadClass(CLASS_NAME_BINARY); Object instance = virtualClass.newInstance(); initial.setRegisters(0, instance, CLASS_NAME); ExecutionGraph graph = VMTester.execute(vm, CLASS_NAME, "invokeGetClassOnThis()V", initial); HeapItem consensus = graph.getTerminatingRegisterConsensus(MethodState.ResultRegister); assertEquals(instance.getClass(), consensus.getValue()); } }
@Test public void invokeReturnParameterReturnsParameter() throws InstantiationException, IllegalAccessException, ClassNotFoundException { VirtualMachine vm = VMTester.spawnVM(); Class<?> virtualClass = vm.getClassLoader().loadClass(CLASS_NAME_BINARY); Object instance = virtualClass.newInstance(); initial.setRegisters(0, instance, CLASS_NAME, 1, 0x5, "I"); expected.setRegisters(1, 0x5, "I", MethodState.ResultRegister, 0x5, "I"); ExecutionGraph graph = VMTester.execute(vm, CLASS_NAME, "invokeReturnParameter()V", initial); VMTester.testState(graph, expected); // Can't simply put instance in the expected state because mutable objects get cloned. // The object class at consensus would be different than the initial class. HeapItem consensus = graph.getTerminatingRegisterConsensus(0); assertEquals(CLASS_NAME, consensus.getType()); assertEquals(virtualClass.getName(), consensus.getValue().getClass().getName()); }
@Test public void canCallInitOfClassWithDefaultConstructorAndGetNewInstance() throws ClassNotFoundException { String instanceClassName = "Lclass_with_default_constructor;"; VirtualMachine vm = VMTester.spawnVM(false); VirtualClass instanceType = vm.getClassManager().getVirtualClass(instanceClassName); Class<?> virtualClass = vm.getClassLoader().loadClass(ClassNameUtils.internalToBinary(instanceClassName)); initial.setRegisters(0, new UninitializedInstance(instanceType), instanceClassName); ExecutionGraph graph = VMTester.execute(vm, CLASS_NAME, "callInitOfClassWithDefaultConstructor()V", initial); //VMTester.testState(graph, expected); HeapItem consensus = graph.getTerminatingRegisterConsensus(0); assertEquals(instanceClassName, consensus.getType()); assertEquals(virtualClass.getName(), consensus.getValue().getClass().getName()); }
@Test public void canConstClassLocal() throws ClassNotFoundException { VirtualMachine vm = VMTester.spawnVM(); Class<?> expectedClass = vm.getClassLoader().loadClass(ClassNameUtils.internalToBinary(CLASS_NAME)); expected.setRegisters(0, expectedClass, CommonTypes.CLASS); ExecutionGraph graph = VMTester.execute(vm, CLASS_NAME, "constClassLocal()V"); VMTester.testState(graph, expected); }
@Test public void canCallInitOfClassWithoutDefaultConstructorWhichChecksForNullArgumentAndGetNewInstance() throws ClassNotFoundException { String instanceClassName = "Lclass_without_default_constructor_checks_null;"; VirtualMachine vm = VMTester.spawnVM(false); VirtualClass instanceType = vm.getClassManager().getVirtualClass(instanceClassName); Class<?> virtualClass = vm.getClassLoader().loadClass(ClassNameUtils.internalToBinary(instanceClassName)); char[] initArg = new char[] { '4', '2' }; initial.setRegisters(0, new UninitializedInstance(instanceType), instanceClassName, 1, initArg, "[C"); expected.setRegisters(1, initArg, "[C"); ExecutionGraph graph = VMTester.execute(vm, CLASS_NAME, "callInitOfClassWithoutDefaultConstructorWhichChecksForNullArgument()V", initial); VMTester.testState(graph, expected); HeapItem consensus = graph.getTerminatingRegisterConsensus(0); assertEquals(instanceClassName, consensus.getType()); assertEquals(virtualClass.getName(), consensus.getValue().getClass().getName()); }
@Test public void canCallInitOfClassWithoutDefaultConstructorAndGetNewInstance() throws ClassNotFoundException { String instanceClassName = "Lclass_without_default_constructor;"; VirtualMachine vm = VMTester.spawnVM(false); VirtualClass instanceType = vm.getClassManager().getVirtualClass(instanceClassName); Class<?> virtualClass = vm.getClassLoader().loadClass(ClassNameUtils.internalToBinary(instanceClassName)); char[] initArg = new char[] { '4', '2' }; initial.setRegisters(0, new UninitializedInstance(instanceType), instanceClassName, 1, initArg, "[C"); expected.setRegisters(1, initArg, "[C"); ExecutionGraph graph = VMTester.execute(vm, CLASS_NAME, "callInitOfClassWithoutDefaultConstructor()V", initial); VMTester.testState(graph, expected); HeapItem consensus = graph.getTerminatingRegisterConsensus(0); assertEquals(instanceClassName, consensus.getType()); assertEquals(virtualClass.getName(), consensus.getValue().getClass().getName()); }
@Test public void instanceInitializerWorksAsExpected() throws ClassNotFoundException { // TODO: easy, try reloadClasses false, or explain why it's needed VirtualMachine vm = VMTester.spawnVM(true); VirtualClass instanceType = vm.getClassManager().getVirtualClass(CLASS_NAME); initial.setRegisters(0, new UninitializedInstance(instanceType), CLASS_NAME); Class<?> virtualClass = vm.getClassLoader().loadClass(CLASS_NAME_BINARY); ExecutionGraph graph = VMTester.execute(vm, CLASS_NAME, "<init>()V", initial); // Can't simply put instance in the expected state because mutable objects get cloned. // The object parse at consensus would be different than the initial parse. HeapItem consensus = graph.getTerminatingRegisterConsensus(0); assertEquals(CLASS_NAME, consensus.getType()); assertEquals(virtualClass, consensus.getValue().getClass()); }
@Test @SuppressWarnings({ "unchecked" }) public void canReflectivelyInstantiateAnEnum() throws ClassNotFoundException { String className = "Lextends_enum;"; String methodDescriptor = "<init>(Ljava/lang/String;II)V"; String enumName = "NONE"; VirtualMachine vm = VMTester.spawnVM(); VirtualClass virtualClass = vm.getClassManager().getVirtualClass(className); VirtualMethod method = virtualClass.getMethod(methodDescriptor); int offset = method.getRegisterCount() - method.getParameterSize(); initial.setRegister(offset, new UninitializedInstance(virtualClass), className); initial.setRegister(offset + 1, enumName, CommonTypes.STRING); initial.setRegister(offset + 2, 0, CommonTypes.INTEGER); initial.setRegister(offset + 3, 0, CommonTypes.INTEGER); ExecutionGraph graph = VMTester.execute(vm, className, methodDescriptor, initial); HeapItem instance = graph.getTerminatingRegisterConsensus(0); Class<? extends Enum> klazz = (Class<? extends Enum>) vm.getClassLoader().loadClass(ClassNameUtils.internalToSource(className)); Object expectedValue = Enum.valueOf(klazz, enumName); assertEquals(expectedValue, instance.getValue()); }
@Test @SuppressWarnings({ "unchecked" }) public void canReflectivelyInstantiateAnObfuscatedEnum() throws ClassNotFoundException { String className = "Lextends_enum_obfuscated;"; String methodDescriptor = "<init>(Ljava/lang/String;II)V"; String enumName = "WEAK"; String obfuscatedEnumName = "c"; VirtualMachine vm = VMTester.spawnVM(); VirtualClass virtualClass = vm.getClassManager().getVirtualClass(className); VirtualMethod method = virtualClass.getMethod(methodDescriptor); int offset = method.getRegisterCount() - method.getParameterSize(); initial.setRegister(offset, new UninitializedInstance(virtualClass), className); initial.setRegister(offset + 1, enumName, CommonTypes.STRING); initial.setRegister(offset + 2, 0, CommonTypes.INTEGER); initial.setRegister(offset + 3, 0, CommonTypes.INTEGER); ExecutionGraph graph = VMTester.execute(vm, className, methodDescriptor, initial); HeapItem instance = graph.getTerminatingRegisterConsensus(0); Class<? extends Enum> klazz = (Class<? extends Enum>) vm.getClassLoader().loadClass(ClassNameUtils.internalToSource(className)); Object expectedValue = Enum.valueOf(klazz, obfuscatedEnumName); assertEquals(expectedValue, instance.getValue()); }