リフレクションを使用してクラスを実際に拡張することはできませんが、カプセル化することはできます。
もちろん、これは重大なセキュリティ リスクであり、これを許可するかどうかを慎重に検討する必要があります。
参照: https://web.archive.org/web/20120201052157/http://initbinder.com/articles/hack_any_java_class_using_reflection_attack.html
このようなものがうまくいくはずです。
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);
}
}
}