如何动态创建一个使用反射扩展另一个动态类的类?

时间:2013-10-18 13:16:33

标签: java reflection

我像这样动态地获取一个类:

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

我想创建另一个名为DummyTile的类,它扩展了我之前的课程。它看起来像这样:

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();
    }

}

...但我不确定如何使用反射来做到这一点。 This is the class that I'm trying to extend.我也不确定如何使用构造函数覆盖方法并初始化对象。我使用反射处理非常简单的事情,但从未处理过动态扩展另一个类。

如果有人能用一些片段指出我正确的方向,我相信我能够从那里处理它。

3 个答案:

答案 0 :(得分:3)

你不能用反射做到这一点。您可以使用interface动态创建java.lang.reflect.Proxy实现,但就是这样。

如果您想要更多,则必须使用第三方库。但是这些库通常在较低级别上工作,例如字节码并需要一些经验。它们不能在受限制的环境中使用。

答案 1 :(得分:1)

你无法使用反射扩展一个类,但你可以封装它 这当然是一个主要的安全风险,您应该认真思考是否要允许这样做。

请参阅: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);
    }
  }
}

答案 2 :(得分:0)

您可以使用Duckapter向Java添加duck typing。

DummyTile tile = ...;
QuickSettingsTile settingsTile = Duck.type(tile, QuickSettingsTile.class);