Look at the source code of a Java class modified by a Java Agent

假装没事ソ 提交于 2020-01-15 03:20:05

问题


I need to see how a Java Agent modified my initial class, so I can understand what the code does.

build.gradle

configurations {
    jar.archiveName = 'agent2.jar'
}

jar {
    manifest {
        attributes(
                "Premain-Class": "com.training.agentexample.Agent",
                "Can-Redefine-Classes": false,
                "Can-Set-Native-Method-Prefix": false
        )
    }

    //Fat jar with all dependencies.
    from {
        (configurations.runtime).collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
}

dependencies {
    compile group: 'org.javassist', name: 'javassist', version: '3.22.0-GA'
}

Main.java

public class Main {

    public static void main(String[] args) {
        System.currentTimeMillis();
        App app = new App();
        app.execute("John");
        Scanner in = new Scanner(System.in);
        System.out.println("Enter text to exit");
        in.next();   //Wait until the user clicks to proceed.
    }
}

App.java

public class App {

    public void execute(String param) {
        String message = "Hello World";
        System.out.println(message + " " + param);
    }
}

Agent.java

public class Agent {

    public static void premain(final String agentArgs, final Instrumentation inst) {
        System.out.println("Hey, look: I'm instrumenting a freshly started JVM!");
        inst.addTransformer(new RuntimeTimerTransformer());
    }
}

RuntimeTimerTransformer.java

public class RuntimeTimerTransformer implements ClassFileTransformer {

    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) {
        return transformClass(redefiningClass, bytes);
    }

    private byte[] transformClass(Class classToTransform, byte[] b) {
        ClassPool pool = ClassPool.getDefault();
        CtClass cl = null;
        try {
            cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
            CtBehavior[] methods = cl.getDeclaredBehaviors();
            for (CtBehavior method : methods) {
                if (!method.isEmpty()) {
                    changeMethod(method);
                }
            }
            b = cl.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cl != null) {
                cl.detach();
            }
        }
        return b;
    }

    private void changeMethod(CtBehavior method) throws CannotCompileException {
        String name = method.getName();
        if (name.equals("execute")) {
            addElapsedTime(method);
        }
    }

    private void addElapsedTime(CtBehavior method) throws CannotCompileException {
        method.addLocalVariable("$_start", CtClass.longType);
        method.addLocalVariable("$_end", CtClass.longType);
        method.addLocalVariable("$_total", CtClass.longType);
        method.insertBefore("{ $_start = System.nanoTime();\nSystem.out.println($0);\n$1 = \"Robert\"; }");
        method.insertAfter("{ $_end = System.nanoTime();\n$_total = $_end - $_start;\nSystem.out.println($_total);\nthrow new RuntimeException(\"Break!\"); }");
    }
}

I debug it from Intellij Idea. I set JAVA_TOOL_OPTIONS=-javaagent:"C:\Development\agent-example\build-gradle\libs\agent2.jar"=name=agentExample

Output

Hey, look: I'm instrumenting a freshly started JVM!
Connected to the target VM, address: '127.0.0.1:64486', transport: 'socket'
Exception in thread "main" java.lang.RuntimeException: Break!
    at app.App.execute(App.java:10)
    at app.app.Main.main(Main.java:12)
app.app.App@3e6fa38a
Hello World !Robert
736583
Picked up JAVA_TOOL_OPTIONS: -javaagent:"C:\Development\agent-example\java-assist-agent\build\libs\agent2.jar"=name=agentExample
Disconnected from the target VM, address: '127.0.0.1:64486', transport: 'socket'

Process finished with exit code 1

I can set breakpoints. My question. How do I see real source code which is being executed? By the way, you can use this code as an example to get started with Java Agent.


回答1:


This is not an answer I was looking for, but this is how close I could get. I still need a better solution, especially what if I cannot access agent code. Your ideas a welcome!

1) Modify transform method.

private byte[] transformClass(Class classToTransform, byte[] b) {
    ClassPool pool = ClassPool.getDefault();
    CtClass cl = null;
    try {
        cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
        CtBehavior[] methods = cl.getDeclaredBehaviors();
        for (CtBehavior method : methods) {
            if (!method.isEmpty()) {
                changeMethod(method);
            }
        }
        b = cl.toBytecode();

        OutputStream os = new FileOutputStream(CLASS_OUTPUT_DIR + cl.getName() + CLASS_EXTENSION);
        BufferedOutputStream bos = new BufferedOutputStream(os);
        bos.write(b);
        bos.close();

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cl != null) {
            cl.detach();
        }
    }
    return b;
}

Update

See update bellow. I used Intellij Idea to open bytecode classes.

2) Then open the bytecode. I used jd-gui-1.4.0.jar. This is what I got.

Compiled App.class

public class App
{
  /* Error */
  public void execute(String param)
  {
    // Byte code:
    //   0: invokestatic 55 java/lang/System:nanoTime   ()J
    //   3: lstore 4
    //   5: getstatic 4 java/lang/System:out    Ljava/io/PrintStream;
    //   8: aload_0
    //   9: invokevirtual 58    java/io/PrintStream:println (Ljava/lang/Object;)V
    //   12: ldc 60
    //   14: astore_1
    //   15: ldc 2
    //   17: astore_2
    //   18: ldc 3
    //   20: astore_3
    //   21: getstatic 4    java/lang/System:out    Ljava/io/PrintStream;
    //   24: aload_2
    //   25: invokevirtual 5    java/io/PrintStream:println (Ljava/lang/String;)V
    //   28: getstatic 4    java/lang/System:out    Ljava/io/PrintStream;
    //   31: new 6  java/lang/StringBuilder
    //   34: dup
    //   35: invokespecial 7    java/lang/StringBuilder:<init>  ()V
    //   38: aload_2
    //   39: invokevirtual 8    java/lang/StringBuilder:append  (Ljava/lang/String;)Ljava/lang/StringBuilder;
    //   42: aload_3
    //   43: invokevirtual 8    java/lang/StringBuilder:append  (Ljava/lang/String;)Ljava/lang/StringBuilder;
    //   46: aload_1
    //   47: invokevirtual 8    java/lang/StringBuilder:append  (Ljava/lang/String;)Ljava/lang/StringBuilder;
    //   50: invokevirtual 9    java/lang/StringBuilder:toString    ()Ljava/lang/String;
    //   53: invokevirtual 5    java/io/PrintStream:println (Ljava/lang/String;)V
    //   56: goto +3 -> 59
    //   59: aconst_null
    //   60: astore 11
    //   62: invokestatic 55    java/lang/System:nanoTime   ()J
    //   65: lstore 6
    //   67: lload 6
    //   69: lload 4
    //   71: lsub
    //   72: lstore 8
    //   74: getstatic 4    java/lang/System:out    Ljava/io/PrintStream;
    //   77: lload 8
    //   79: invokevirtual 63   java/io/PrintStream:println (J)V
    //   82: new 65 java/lang/RuntimeException
    //   85: dup
    //   86: ldc 67
    //   88: invokespecial 69   java/lang/RuntimeException:<init>   (Ljava/lang/String;)V
    //   91: athrow
    //   92: athrow
    // Line number table:
    //   Java source line #6    -> byte code offset #15
    //   Java source line #7    -> byte code offset #18
    //   Java source line #8    -> byte code offset #21
    //   Java source line #9    -> byte code offset #28
    //   Java source line #10   -> byte code offset #56
    // Local variable table:
    //   start  length  slot    name    signature
    //   0  59  0   this    App
    //   0  59  1   param   String
    //   18 41  2   message String
    //   21 38  3   appender    String
    //   0  59  4   $_start long
    //   0  59  6   $_end   long
    //   0  59  8   $_total long
  }
}

And in Idea



来源:https://stackoverflow.com/questions/50487601/look-at-the-source-code-of-a-java-class-modified-by-a-java-agent

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