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.
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.
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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With