The Reflection API could be used to change values of private and final fields even in the JDK default library. This could be used to manipulate the behaviour of some well known classes as we will see.
What is not possible
Lets start first with the only limitation means the only field we can't change with Reflection. That is the Java SecurityManager
. It is declared in java.lang.System as
private static volatile SecurityManager security = null;
But it won't be listed in the System class if we run this code
for(Field f : System.class.getDeclaredFields())
System.out.println(f);
Thats because of the fieldFilterMap
in sun.reflect.Reflection
that holds the map itself and the security field
in the System.class
and protects them against any access with Reflection.
So we could not deactivate the SecurityManager
.
Crazy Strings
Each Java String is represented by the JVM as an instance of the String
class. However, in some situations the JVM saves heap space by using the same instance for Strings that are. This happens for string literals, and also for strings that have been "interned" by calling String.intern()
. So if you have "hello"
in your code multiple times it is always the same object instance.
Strings are supposed to be immutable, but it is possible to use "evil" reflection to change them. The example below show how we can change the characters in a String by replacing its value
field.
public class CrazyStrings {
static {
try {
Field f = String.class.getDeclaredField("value");
f.setAccessible(true);
f.set("hello", "you stink!".toCharArray());
} catch (Exception e) {
}
}
public static void main(String args[]) {
System.out.println("hello");
}
}
So this code will print "you stink!"
1 = 42
The same idea could be used with the Integer Class
public class CrazyMath {
static {
try {
Field value = Integer.class.getDeclaredField("value");
value.setAccessible(true);
value.setInt(Integer.valueOf(1), 42);
} catch (Exception e) {
}
}
public static void main(String args[]) {
System.out.println(Integer.valueOf(1));
}
}
Everything is true
And according to this stackoverflow post we can use reflection to do something really evil.
public class Evil {
static {
try {
Field field = Boolean.class.getField("FALSE");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, true);
} catch (Exception e) {
}
}
public static void main(String args[]){
System.out.format("Everything is %s", false);
}
}
Note that what we are doing here is going to cause the JVM to behave in inexplicable ways. This is very dangerous.