有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java ASM AdviceAdapter onMethodEnter打印所有参数

我希望使用ASM打印传递到方法中的所有参数的值。我找到了一些例子,但我搞不懂。老实说,我可能还没有完成我的“家庭作业”,也就是说,我没有尽可能多地学习ASM来构建它。但如果有人愿意帮我,那就太好了

举个例子,假设该方法返回一个void,并将一个整数作为参数

(我在https://gist.github.com/VijayKrishna/1ca807c952187a7d8c4d看到了这个例子)


共 (1) 个答案

  1. # 1 楼答案

    好吧,我知道了。开始了

    这里是方法类。它读入一个类文件(Print.class),并在调用PrintInt方法时添加打印int的指令

    package asm;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    import org.objectweb.asm.AnnotationVisitor;
    import org.objectweb.asm.Attribute;
    import org.objectweb.asm.ClassReader;
    import org.objectweb.asm.ClassVisitor;
    import org.objectweb.asm.ClassWriter;
    import org.objectweb.asm.Label;
    import org.objectweb.asm.MethodVisitor;
    import org.objectweb.asm.Opcodes;
    import org.objectweb.asm.commons.AdviceAdapter;
    
    public class PrintInjector extends ClassVisitor {
    
        public PrintInjector(int api, ClassVisitor mv) {
            super(api, mv);
        }
    
        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            MethodVisitor mv = cv.visitMethod(access,  name,  desc,  signature,  exceptions);
            System.out.println(String.format("%s %s %s", name, desc, signature));
            if(name.equals("PrintInt"))
                    mv = new PrintSingleIntParameter(Opcodes.ASM5, mv, access, name, desc);
            return mv;
        }
    
        public static void main(String[] args) throws IOException {
            ClassReader cr = new ClassReader(new FileInputStream(new File("bin\\Print.class")));
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
            PrintInjector pi = new PrintInjector(Opcodes.ASM5, cw);
    
            cr.accept(pi,  0);
    
            FileOutputStream fos = new FileOutputStream(new File("Print.class"));
            fos.write(cw.toByteArray());
            fos.flush();
            fos.close();
        }
    
        class PrintSingleIntParameter extends AdviceAdapter {
    
            protected PrintSingleIntParameter(int api, MethodVisitor mv, int access,
                    String name, String desc) {
                super(api, mv, access, name, desc);
            }
    
            @Override
            protected void onMethodEnter() {
                Label l0 = new Label();
                mv.visitLabel(l0);
                mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                mv.visitVarInsn(ILOAD, 0); //1 instead of 0 if PrintInt wasn't static
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V", false);
            }       
        }
    }
    

    这是我的指纹。阶级

    public class Print {
        public static int PrintInt(int i) {
            System.out.println(i);
            return i;
        }
    
        public static void main(String[] args) {
            int a = PrintInt(10);
            System.out.println("Done");
        }
    }
    

    输出

    10
    a:10
    Done
    

    您需要调整onMethodEnter中的代码,以满足您的任何需求。我现在意识到,我拥有的代码并不能保持字节码的干净(就像我在其他使用寄存器的程序中运行该代码时,字节码会中断一样)