How to print out all methods called during runtime in Java using instrumentation?

那年仲夏 提交于 2019-12-19 11:44:20

问题


I want to print out all methods that get called during runtime. They should be printed out in the order that they're called in and if they're called multiple times, they should be printed multiple times.

This can be used for reverse engineering - seeing which functions get called when you press a button or do a specific action.

I want to use Java agents and instrumentation for this.


回答1:


This can be done using Java Agents and an instrumentation library.

Java agent - Separate code that can be made to run before the main part of the code.

Instrumentation - Changing the source code during the load-time of a program.

Code for making it work

(taken from appcrawler and modified slightly):

The agent.jar source code:

SimpleTransformer.java:

package test;

import java.security.*;
import java.lang.instrument.*;
import java.util.*;
import javassist.*;

public class SimpleTransformer implements ClassFileTransformer {

  public SimpleTransformer() {
    super();
  }

  public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
    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 (int i = 0; i < methods.length; i++) {
        if (methods[i].isEmpty() == false) {
          changeMethod(methods[i]);
        }
      }
      b = cl.toBytecode();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    finally {
      if (cl != null) {
        cl.detach();
      }
    }
    return b;
  }

  private void changeMethod(CtBehavior method) throws NotFoundException, CannotCompileException {
    /*if (method.getName().equals("doIt")) {
      method.insertBefore("System.out.println(\"started method at \" + new java.util.Date());");
      method.insertAfter("System.out.println(\"ended method at \" + new java.util.Date());");
    }*/



          //MY CODE
      //!Modifier.isAbstract(method.getModifiers()) -- abstract methods can't be modified. If you get exceptions, then add this to the if statement.
      //native methods can't be modified.
      if (!Modifier.isNative(method.getModifiers())) {
          String insertString = "System.out.println(\"started method " + method.getName() + "\");";
          method.insertBefore(insertString);
      }
  }

SimpleMain.java:

package test;

import java.lang.instrument.Instrumentation;

public class SimpleMain {
  public static void premain(String agentArguments, Instrumentation instrumentation) {  
    instrumentation.addTransformer(new SimpleTransformer());
  } 
}

MANIFEST.mf:

Manifest-Version: 1.0
Boot-Class-Path: javassist.jar
Premain-Class: test.SimpleMain

Take these files and package them into a jar file. Also make sure to include files from javassist.jar (downloadable from www.javassist.org) and tools.jar (found in Program Files/Java/jdk/lib/). Not sure if the second one is necessary, but the article says it is for some reason.

Now you can use this jar file as a java agent.

java -javaagent:agent.jar YourJavaProgram

And voila. The java agent will instrument all methods and print out every method called during execution.



来源:https://stackoverflow.com/questions/43027872/how-to-print-out-all-methods-called-during-runtime-in-java-using-instrumentation

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