使用 ASM 的 Java 字节码检测,MethodVisitor 为 null

标签 java java-bytecode-asm

因此,使用下面编写的代码,我的输出是:

Starting application with the Agent
Visiting class: HelloWorld
Class Major Version: 51
Super class: java/lang/Object
Source: HelloWorld.java
Method: <init> desc = ()V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method: main desc = ([Ljava/lang/String;)V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method: foo desc = ()V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method ends here
Done instrumenting: HelloWorld

这让我很困惑。为什么我的 methodVisitor 会是 null? ASM源代码似乎只在classVisitornull时才为methodVisitor返回null,这是不正确的就我而言。

package com.amir.agent.instrumentor;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class amirClassVisitor {

    private byte[] outData = null;

    public amirClassVisitor() {
    }

    public void performInstrumentation(final String className,
                                       final byte[] classAsBytes) {
        final ClassVisitor cl = new ClassVisitor(Opcodes.ASM4) {
            @Override
            public void visit(final int version,
                              final int access,
                              final String name,
                              final String signature,
                              final String superName,
                              final String[] interfaces) {
                System.out.println("Visiting class: "+name);
                System.out.println("Class Major Version: "+version);
                System.out.println("Super class: " + superName);
                super.visit(version, access, name, signature, superName, interfaces);
            }

            @Override
            public void visitOuterClass(final String owner,
                                        final String name,
                                        final String desc) {
                System.out.println("Outer class: "+owner);
                super.visitOuterClass(owner, name, desc);
            }

            @Override
            public AnnotationVisitor visitAnnotation(final String desc,
                                                     final boolean visible) {
                System.out.println("Annotation: "+desc);
                return super.visitAnnotation(desc, visible);
            }

            @Override
            public void visitAttribute(final Attribute attr) {
                System.out.println("Class Attribute: " + attr.type);
                super.visitAttribute(attr);
            }

            @Override
            public void visitInnerClass(final String name,
                                        final String outerName,
                                        final String innerName,
                                        final int access) {
                System.out.println("Inner Class: " + innerName + " defined in " + outerName);
                super.visitInnerClass(name, outerName, innerName, access);
            }

            @Override
            public FieldVisitor visitField(final int access,
                                           final String name,
                                           final String desc,
                                           final String signature,
                                           final Object value) {
                System.out.println("Field: "+name+" "+desc+" value:"+value);
                return super.visitField(access, name, desc, signature, value);
            }

            @Override
            public void visitEnd() {
                System.out.println("Method ends here");
                super.visitEnd();
            }

            @Override
            public MethodVisitor visitMethod(final int access,
                                             final String name,
                                             final String desc,
                                             final String signature,
                                             final String[] exceptions) {
                final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
                System.out.println("Method: " +name+ " desc = " +desc+ " cv = " +this+ " and mv = " +mv);
                return mv;
            }

            @Override
            public void visitSource(final String source,
                                    final String debug) {
                System.out.println("Source: "+source);
                super.visitSource(source, debug);
            }

        };

        final ClassReader classReader = new ClassReader(classAsBytes);
        classReader.accept(cl, 0);
        System.out.println("Done instrumenting: " +className);

    }

    public byte[] result() {
        return outData;
    }

}

编辑:

我这样称呼这段代码:

public class ClassLoadInterceptor implements ClassFileTransformer {

    @SuppressWarnings("unchecked")
    public byte[] transform(final java.lang.ClassLoader loader,
                            final java.lang.String className,
                            final java.lang.Class classBeingRedefined,
                            final java.security.ProtectionDomain protectionDomain,
                            final byte[] classfileBuffer) throws IllegalClassFormatException {

        if (!(className.startsWith("java") || className.startsWith("sun") || className.startsWith("com/workday/agent"))) {
            WorkdayClassVisitor v = new WorkdayClassVisitor();
            v.performInstrumentation(className, classfileBuffer);
            System.out.println("\t Instrumenting : " +className);
            byte[] instrumented_class = v.result();
            writeOutClassFile("debug", className + ".class", classfileBuffer);
            writeOutClassFile("debug", className + "_instrumented" + ".class", instrumented_class);
            return instrumented_class;
        }

        return classfileBuffer;

    }

最佳答案

你打印出来的不是“my methodVisitor”,而是调用visitMethodsuper返回的值,换句话说就是默认值ClassVisitor.visitMethod 返回的值:

Returns:
   an object to visit the byte code of the method, or null if this class visitor is not interested in visiting the code of this method.

由于抽象类 ClassVisitor 没有实现任何操作,因此它对访问该方法没有兴趣,因此 null 是完美的返回值。

因此,由您来实例化一个新的 MethodVisitor 来实现您想要的行为。或者,由于您似乎打算对一个类进行检测,因此让您的类访问者委托(delegate)给 ClassWriter您将其传递给 super class constructor 。这样您将继承可以自定义的复制行为。然后,super.visitMethod 将返回一个非 null 方法访问者,它将复制该方法。

关于使用 ASM 的 Java 字节码检测,MethodVisitor 为 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28820678/

相关文章:

java - 是否不鼓励使用多行 toString() 输出?

java - 如何在 MAC OS X 中为 Java 应用程序设置 VM

java - 区分线程,即使它们具有相同的名称

使用 ASM 操作 Java 字节码

java - 如何在Java中重新定义已经定义的类

java - build 学生类(class)

java - 如何将任意对象作为参数传递给 jasper 报告?

android - Dalvik 字节码中的 "throws"和 "annotation for exception"

java - 转换为二进制 Java 类时 Jasmin NoSuchMethodError

java - 使用 ASM 字节码检测在堆栈上加载构造函数参数(值)