问题
I already understand how to manipulate a class on runtime using ASM from this post.
But I have further question regarding how to modify the constant pool. Below is a sample java program that I want modify
Main jar file:
public class test {
private static final String a = "Hello World";
private static final String b = "ASM is awasome";
public static void main(String[] args) {
int x = 10;
int y = 25;
int z = x * y;
System.out.println(a);
System.out.println(z);
System.out.println(b);
}
}
I want to modify variable a
from "Hello World"
to "Multiply Of x*y is: "
My Agent Class
import java.lang.instrument.*;
import java.security.ProtectionDomain;
import org.objectweb.asm.*;
public class ExampleAgent implements ClassFileTransformer {
private static final String TRANSFORM_CLASS = "src/test";
private static final String TRANSFORM_METHOD_NAME = "main";
private static final String TRANSFORM_METHOD_DESC = "([Ljava/lang/String;)V";
public static void premain(String arg, Instrumentation instrumentation) {
instrumentation.addTransformer(new ExampleAgent());
}
public byte[] transform(ClassLoader loader, String className, Class<?> cl,
ProtectionDomain pd, byte[] classfileBuffer) {
if(!TRANSFORM_CLASS.equals(className)) return null;
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(
access, name, desc, signature, exceptions);
//Code to modify the value of a
return mv;
}
}, 0);
return cw.toByteArray();
}
}
Result On Console Window Should be
Multiply Of x*y is:
250
ASM is awasome
回答1:
As said in this comment, with ASM you don’t deal with the constant pool at all; you only deal with the actual uses of the constant(s).
Regarding your example, you have to be aware of the fact that a declaration like… final String a = "Hello World";
is a compile-time constant. Therefore, there will be a ConstantValue attribute at the field describing the value, but every read access to the constant will get replaced at compile-time already.
So to “change a
” effectively, you have to replace each actual use of the constant value, but you have to be aware that you can’t recognize whether an occurrence of the value truly stems from a field access to a
or is just another use of the same constant value.
Uses like in your example code are easy to change; you only have to look for ldc instructions. Replacing the constant value declaration of the field itself, also is rather easy. More involved would be replacing constants within annotations, but really hard would be replacing uses of the constant as case
label of a switch
statement, as the program logic would break if you just replace the constant in such a scenario. You would have to rewrite more code to make a switch over string work with a different constant.
Focusing on the easier tasks only, the transformation code becomes:
public byte[] transform(ClassLoader loader, String className, Class<?> cl,
ProtectionDomain pd, byte[] classfileBuffer) {
if(!TRANSFORM_CLASS.equals(className)) return null;
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object cst) {
if("Hello World".equals(cst)) cst = "Multiply Of x*y is: ";
return super.visitField(access, name, desc, signature, cst);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(
access, name, desc, signature, exceptions);
if(name.equals(TRANSFORM_METHOD_NAME)
&& desc.equals(TRANSFORM_METHOD_DESC)) {
return new MethodVisitor(Opcodes.ASM5, mv) {
@Override
public void visitLdcInsn(Object cst) {
if("Hello World".equals(cst)) cst = "Multiply Of x*y is: ";
super.visitLdcInsn(cst);
}
};
}
return mv;
}
}, 0);
return cw.toByteArray();
}
来源:https://stackoverflow.com/questions/49442149/how-to-modify-constant-pool-using-asm