5

I'm fetching a class dynamically like this:

Class<?> clazz = Class.forName("com.android.systemui.quicksettings.QuickSettingsTile");

I'd like to create another class called DummyTile thats extends my previous class. It would have looked like this:

public class DummyTile extends QuickSettingsTile {
 public DummyTile(Context context, QuickSettingsController qsc) {
 super(context, qsc);
 }
 public void updateTile() {
 System.out.println("Hello");
 }
 @Override
 public void updateResources() {
 updateTile();
 super.updateResources();
 }
}

...but I'm not sure how to do this using reflection. This is the class that I'm trying to extend. I'm also not sure as to how I would override a method and initialise the object using the constructor. I've worked with very simple things using reflection but never dealt with extending another class dynamically.

If someone could point me in the right direction with some snippets, I'm confident that I'll be able to handle it from there.

Johan
77.2k27 gold badges203 silver badges345 bronze badges
asked Oct 18, 2013 at 13:16
2
  • 2
    Why do you want to do this? Commented Oct 18, 2013 at 13:18
  • So that I can modify some features in my Android ROM using Xposed: repo.xposed.info Commented Oct 18, 2013 at 13:20

3 Answers 3

3

You can’t do that with reflection. You can create interface implementations dynamically using java.lang.reflect.Proxy but that’s it.

If you want more you have to use third-party libraries. But these libraries usually work on a lower level, e.g. byte code and require some experience. And they cannot be used in restricted environments.

answered Oct 18, 2013 at 13:21
1

You can't really extend a class using reflection, but you can encapsulate it.
This is of course a major security risk and you should think hard about whether you want to allow this.

See: https://web.archive.org/web/20120201052157/http://initbinder.com/articles/hack_any_java_class_using_reflection_attack.html

Something like this should do the trick.

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.ClassNotFoundException;
import java.lang.InstantiationException;
import java.lang.IllegalAccessException;
import java.lang.reflect.InvocationTargetException;
import java.lang.NoSuchMethodException;
public class Tester {
 private static String CLASS_NAME = "VictimClass";
 private static Class victimClass = null;
 private static Object victimClassObj = null;
 public static void main(String[] args) {
 victimClass = loadClass(victimClass, CLASS_NAME);
 printClassStructure();
 attack();
 }
 private static Class loadClass(Class clazz, String className) {
 Thread thread = Thread.currentThread();
 ClassLoader classLoader =
 thread.getContextClassLoader();
 try {
 clazz = Class.forName(className, true, classLoader);
 }
 catch (ClassNotFoundException e) {
 System.err.println("Error: could not find class: "
 + CLASS_NAME);
 }
 return clazz;
 }
 private static void printClassStructure() {
 Constructor[] constructors =
 victimClass.getDeclaredConstructors();
 for (Constructor c : constructors) {
 int modifier = c.getModifiers();
 System.out.println("Declared constructor name: "
 + c.getName() + "ntis accessible: "
 + c.isAccessible() + "ntis private: "
 + Modifier.isPrivate(modifier) + "n");
 }
 Method[] methods = victimClass.getDeclaredMethods();
 for (Method m : methods) {
 int modifier = m.getModifiers();
 System.out.println("Declared method name: " + m.getName()
 + "ntis accessible: "
 + m.isAccessible()
 + "ntis private: "
 + Modifier.isPrivate(modifier)
 + "ntis static: "
 + Modifier.isStatic(modifier) + "n");
 }
 Field[] fields = victimClass.getDeclaredFields();
 for (Field f : fields) {
 int modifier = f.getModifiers();
 System.out.println("Declared field name: " + f.getName()
 + "ntis accessible: "
 + f.isAccessible()
 + "ntis private: "
 + Modifier.isPrivate(modifier)
 + "ntis static: "
 + Modifier.isStatic(modifier)
 + "ntis final: "
 + Modifier.isFinal(modifier) + "n");
 }
 }
 private static void attack() {
 Field[] fields = victimClass.getDeclaredFields();
 Method[] methods = victimClass.getDeclaredMethods();
 Constructor[] constructors = victimClass.getDeclaredConstructors();
 //make constructor accessible
 constructors[0].setAccessible(true);
 System.err.println("Initiating reflection attack:");
 try {
 //create new object by invoking private constructor
 victimClassObj = constructors[0].newInstance(new Object[] {});
 //make static method accessible and get its value
 //please note: when invoking static method,
 //object represented by this Method is null
 methods[2].setAccessible(true);
 Object o = methods[2].invoke(null, new Object[] {});
 System.out.println("Got user ID from private static accessor: "
 + o.toString());
 //make method accessible and get its value
 methods[0].setAccessible(true);
 o = methods[0].invoke(victimClassObj, new Object[] {});
 System.out.println("Got original password from private accessor: "
 + o.toString());
 //make method accessible and set to it new value
 methods[1].setAccessible(true);
 System.out.println("Injecting new password using private mutator");
 methods[1].invoke(victimClassObj, new Object[] {"injected_password"});
 //get method’s its new value
 o = methods[0].invoke(victimClassObj, new Object[] {});
 System.out.println("Got injected password from private accessor: "
 + o.toString());
 //make field accessible and get its value
 fields[2].setAccessible(true);
 o = fields[2].get(victimClassObj);
 System.out.println("Got private field: " + o);
 //make field accessible and set to it new value
 System.out.println("Injecting value to a private field:");
 fields[2].set(victimClassObj, "new_default_value");
 //get field’s its new value
 o = fields[2].get(victimClassObj);
 System.out.println("Got updated private field: " + o);
 //make field accessible and get its value
 fields[1].setAccessible(true);
 o = fields[1].get(victimClassObj);
 System.out.println("Got private static field: " + o);
 //make field accessible and set to it new value
 System.out.println("Injecting value to a private static final field:");
 fields[1].set(null, new Integer(2));
 //get field’s its new value
 o = fields[1].get(victimClassObj);
 System.out.println("Got updated private static final field: " + o);
 }
 catch (InstantiationException e) {
 System.err.println("Error: could not instantiate: " + e);
 }
 catch (IllegalAccessException e) {
 System.err.println("Error: could not access: " + e);
 }
 catch (InvocationTargetException e) {
 System.err.println("Error: could not invoke the target: " + e);
 }
 }
}
James
1,9481 gold badge12 silver badges14 bronze badges
answered Oct 18, 2013 at 13:31
0

You can use Duckapter which adds duck typing to Java.

DummyTile tile = ...;
QuickSettingsTile settingsTile = Duck.type(tile, QuickSettingsTile.class);
answered Oct 18, 2013 at 13:39

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.