How To Modify Constant Pool Using ASM?

时光总嘲笑我的痴心妄想 提交于 2019-12-11 04:24:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!