3

この投稿から、ASM を使用して実行時にクラスを操作する方法を既に理解しています。

しかし、定数プールを変更する方法についてさらに質問があります。以下は、変更したいサンプルJavaプログラムです

主な jar ファイル:

    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);

    }

}

a変数を"Hello World"~に変更したい"Multiply Of x*y is: "

私のエージェントクラス

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();

    }
}

コンソール ウィンドウの結果は

Multiply Of x*y is: 
250
ASM is awasome
4

1 に答える 1

8

このコメントで述べたように、ASM では定数プールをまったく処理しません。定数の実際の使用のみを扱います。

あなたの例に関しては、次のような宣言
… final String a = "Hello World";がコンパイル時の定数であるという事実に注意する必要があります。したがって、値を説明するフィールドにConstantValue属性がありますが、定数へのすべての読み取りアクセスは、コンパイル時にすでに置き換えられています。

したがって、効果的に「変更」するには、定数値の実際の使用をそれぞれ置き換える必要がありますが、値の出現が本当にフィールドへのアクセスに起因するのか、それとも単なる別の使用であるaかを認識できないことに注意する必要があります。a同じ定数値。

サンプルコードのような用途は簡単に変更できます。ldc指示を探すだけです。フィールド自体の定数値宣言を置き換えることも、かなり簡単です。より複雑なのは、注釈内の定数を置き換えることですが、そのようなシナリオで定数を置き換えるだけではプログラムロジックが壊れるためcase、ステートメントのラベルとして定数の使用を置き換えることは本当に難しいでしょう. switch文字列の切り替えを別の定数で機能させるには、さらにコードを書き直す必要があります。

簡単なタスクのみに注目すると、変換コードは次のようになります。

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();
}
于 2018-03-23T16:16:56.813 に答える