反射hacking javaプログラムの利用
4255 ワード
一般にclientプログラムはprivateメソッドを直接呼び出すことはできないが,反射により実現できる.
OK,singletonモードは取得したインスタンスの一意性を保証することができ,以下では反射によってこの制限を変更することができる.
最後の例では、Runtimeクラスには、現在のruntimeインスタンスを表すprivate static fieldがあります.まず、現在のruntimeインスタンスを取得し、印刷します.そして、currentRuntimeはclass初期化時に初期化されるのでRuntimeを設定する.CurrentRuntime静的ドメインはnullであり、今回の変更を検証するためにruntimeインスタンスを再度取得し、印刷します.最後に、dosコマンドdirを現在のruntimeインスタンスで呼び出してみましょう.
package chentao;
public class A
{
private static String getPassword() {
return "call the method!";
}
}
package chentao;
import java.lang.reflect.InvocationTargetException;
public class Test
{
/**
* @param args
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
// ERROR
/*String password = A.getPassword();
System.out.println("I got it:" + password);*/
Class cl = Class.forName("chentao.A");
java.lang.reflect.Method[] m = cl.getDeclaredMethods();
m[0].setAccessible(true);
String password = (String) m[0].invoke(null, null);
System.out.println("I got it:" + password);
}
}
/*output:
I got it:call the method!*/
OK,singletonモードは取得したインスタンスの一意性を保証することができ,以下では反射によってこの制限を変更することができる.
package chentao;
public class B
{
public static final B singleton = new B("I'm the only instance of class B");
private String name;
private B(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}
package chentao;
package chentao;
import java.lang.reflect.InvocationTargetException;
public class TestB
{
/**
* @param args
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InstantiationException
*/
public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException
{
Class cl = Class.forName("chentao.B");
java.lang.reflect.Constructor[] c = cl.getDeclaredConstructors();
c[0].setAccessible(true);
B anotherB = (B) c[0].newInstance(new Object[]{"Not anymore!!"});
System.out.println(B.singleton);
System.out.println(anotherB);
}
}
/*output:
I'm the only instance of class B
Not anymore!!
*/
最後の例では、Runtimeクラスには、現在のruntimeインスタンスを表すprivate static fieldがあります.まず、現在のruntimeインスタンスを取得し、印刷します.そして、currentRuntimeはclass初期化時に初期化されるのでRuntimeを設定する.CurrentRuntime静的ドメインはnullであり、今回の変更を検証するためにruntimeインスタンスを再度取得し、印刷します.最後に、dosコマンドdirを現在のruntimeインスタンスで呼び出してみましょう.
package chentao;
import java.lang.reflect.InvocationTargetException;
public class TestRuntime
{
/**
* @param args
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InstantiationException
*/
public static void main(String[] args) throws Exception
{
Runtime r = Runtime.getRuntime();
System.out.println("Before: Runtime.getRuntime() yields " + r);
Class cl = Class.forName("java.lang.Runtime");
java.lang.reflect.Field f = cl.getDeclaredField("currentRuntime");
f.setAccessible(true);
f.set(null, null);
r = Runtime.getRuntime();
System.out.println("After: Runtime.getRuntime() yields " + r);
r.exec("dir"); //raises NullPointerException!!
}
}
/*Output:
Before: Runtime.getRuntime() yields java.lang.Runtime@cac268
After: Runtime.getRuntime() yields null
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:59)
*/