5

次のようにクラスを動的にフェッチしています。

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

}

...しかし、リフレクションを使用してこれを行う方法がわかりません。これは私が拡張しようとしているクラスです。メソッドをオーバーライドし、コンストラクターを使用してオブジェクトを初期化する方法についてもわかりません。私はリフレクションを使用して非常に単純なものを扱ってきましたが、別のクラスを動的に拡張することは一度もありませんでした。

誰かがいくつかのスニペットで私を正しい方向に向けることができれば、そこからそれを処理できると確信しています.

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

ダックタイピングを Java に追加するDuckapterを使用できます。

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