如何使用检测打印出Java中运行时调用的所有方法?

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

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

我想为此使用Java代理和检测。

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

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

Instrumentation – 在程序的加载时更改源代码。

使其运作的代码

(取自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(); } 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 

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

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

 java -javaagent:agent.jar YourJavaProgram 

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