Introduction
, , , - ExprEditor. API Javassist , -.
, API , -, .
Example, :
public class Example {
public static final Example ex1 = new Example("__EX_1__");
public static String DEFAULT_NAME = "Paulo";
private String name;
static {
System.out.println("Class inited");
}
public Example(String name) {
this.name = name;
}
}
, , , reset . , System.out, , , , ( ' ).
, :
public class Test {
public static void main(String[] args) throws Throwable {
System.out.println(Example.DEFAULT_NAME);
Example.DEFAULT_NAME = "Jose";
System.out.println(Example.DEFAULT_NAME);
try {
reset();
} catch (Throwable t) {
System.out.println("Problems calling reset, maybe not injected?");
}
System.out.println(Example.DEFAULT_NAME);
}
private static void reset() throws Throwable {
Method declaredMethod = Example.class.getDeclaredMethod("__NEW_NAME__", new Class[] {});
declaredMethod.invoke(null, new Object[] {});
}
}
, :
Class inited
Paulo
Jose
Problems calling reset, maybe not injected?
Jose
, (, , !: P)
, , - , ? javap - Example :
javap -c -l -v -p Example.class
, .
- c: -
- l:
- v: be verbose , ..
- p:
- ( ):
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: new #1 // class test7/Example
3: dup
4: ldc #13 // String __EX_1__
6: invokespecial #15 // Method "<init>":(Ljava/lang/String;)V
9: putstatic #19 // Field ex1:Ltest7/Example;
12: ldc #21 // String Paulo
14: putstatic #23 // Field DEFAULT_NAME:Ljava/lang/String;
17: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;
20: ldc #31 // String Class inited
22: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
LineNumberTable:
line 4: 0
line 5: 12
line 10: 17
line 11: 25
LocalVariableTable:
Start Length Slot Name Signature
, , 9, a putstatic ex1, , , , .
, , , -. NEW_NAME() bytecode:
public static void __NEW_NAME__();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: new #1 // class test7/Example
3: dup
4: ldc #13 // String __EX_1__
6: invokespecial #15 // Method "<init>":(Ljava/lang/String;)V
9: putstatic #19 // Field ex1:Ltest7/Example;
12: ldc #21 // String Paulo
14: putstatic #23 // Field DEFAULT_NAME:Ljava/lang/String;
17: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;
20: ldc #31 // String Class inited
22: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
LineNumberTable:
line 4: 0
line 5: 12
line 10: 17
line 11: 25
LocalVariableTable:
Start Length Slot Name Signature
- 9 , .
. , - final. , "", ? "", , - , :)
, , , , , , . :
public class Injector {
public static void main(String[] args) throws Throwable {
CtClass cc = ClassPool.getDefault().get(Example.class.getName());
CtConstructor staticConstructor = cc.getClassInitializer();
if (staticConstructor != null) {
CtConstructor staticConstructorClone = new CtConstructor(staticConstructor, cc, null);
staticConstructorClone.getMethodInfo().setName("__NEW_NAME__");
staticConstructorClone.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
cc.addConstructor(staticConstructorClone);
staticConstructorClone.instrument(new ExprEditor() {
@Override
public void edit(FieldAccess f) throws CannotCompileException {
try {
if (f.isStatic() && f.isWriter() && Modifier.isFinal(f.getField().getModifiers())) {
System.out.println("Found field");
f.replace("{ }");
}
} catch (NotFoundException e) {
e.printStackTrace();
}
}
});
cc.writeFile("...);
}
}
}
, , instrument ExprEditor, . , , , , "{}", " ".
- :
public static void __NEW_NAME__();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=0
0: new #1 // class test7/Example
3: dup
4: ldc #13 // String __EX_1__
6: invokespecial #15 // Method "<init>":(Ljava/lang/String;)V
9: astore_1
10: aconst_null
11: astore_0
12: ldc #21 // String Paulo
14: putstatic #23 // Field DEFAULT_NAME:Ljava/lang/String;
17: getstatic #25 // Field java/lang/System.out:Ljava/io/PrintStream;
20: ldc #31 // String Class inited
22: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: return
LineNumberTable:
line 4: 0
line 5: 12
line 10: 17
line 11: 25
LocalVariableTable:
Start Length Slot Name Signature
, stackframe 9 putstatic, astore_1, javassist 3 , 9 11:
9: astore_1
10: aconst_null
11: astore_0
, , :
Class inited
Paulo
Jose
Class inited
Paulo
, , , , - ... , ExprEditor, , .
resetState(), , , , , -.
, . , .