【问题标题】:How to print out all methods called during runtime in Java using instrumentation?如何使用检测打印出在 Java 运行时调用的所有方法?
【发布时间】:2017-08-19 01:35:55
【问题描述】:

我想打印出在运行时调用的所有方法。它们应该按照调用的顺序打印出来,如果被调用多次,就应该打印多次。

这可用于逆向工程 - 查看当您按下按钮或执行特定操作时会调用哪些函数。

我想为此使用 Java 代理和工具。

【问题讨论】:

  • 这就是调试器的用途。您可以在调用每个方法时对其进行跟踪。您可以使用调试器 API 以编程方式执行此操作,但单步执行代码可能更简单,因为您还可以看到使用的值。
  • 澄清我希望使用 java 代理来完成。

标签: java reverse-engineering instrumentation javassist javaagents


【解决方案1】:

这可以使用 Java 代理和检测库来完成。

Java 代理 - 可以在代码的主要部分之前运行的单独代码。

仪表 - 在程序加载期间更改源代码。

使其工作的代码

(取自appcrawler并稍作修改):

agent.jar 源码:

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();
    }
    catch (Throwable t) {
      t.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());
  } 
}

清单.mf:

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

把这些文件打包成一个jar文件。还要确保包含来自 javassist.jar(可从 www.javassist.org 下载)和 tools.jar(可在 Program Files/Java/jdk/lib/ 中找到)的文件。不确定是否需要第二个,但文章说这是出于某种原因。

现在您可以将此 jar 文件用作 java 代理。

java -javaagent:agent.jar YourJavaProgram

然后瞧。 Java 代理将检测所有方法并打印出执行期间调用的每个方法。

【讨论】:

  • 注意:此代码适用于简单程序,但可能会与更复杂的程序中断,就像我的项目一样。
猜你喜欢
  • 1970-01-01
  • 2017-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
  • 2015-11-21
  • 2014-03-13
  • 1970-01-01
相关资源
最近更新 更多