5

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

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

我想创建另一个名为DummyTilethats 的类扩展了我以前的类。它看起来像这样:

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

}

...但我不确定如何使用反射来做到这一点。这是我正在尝试扩展的课程。我也不确定如何重写方法并使用构造函数初始化对象。我使用反射处理了非常简单的事情,但从未处理过动态扩展另一个类。

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

4

3 回答 3

3

你不能用反射来做到这一点。您可以interface使用动态创建实现java.lang.reflect.Proxy,仅此而已。

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

于 2013-10-18T13:21:45.447 回答
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);
    }
  }
}
于 2013-10-18T13:31:27.217 回答
0

您可以使用Duckapter,它将鸭子类型添加到 Java。

DummyTile tile = ...;
QuickSettingsTile settingsTile = Duck.type(tile, QuickSettingsTile.class);
于 2013-10-18T13:39:53.407 回答