通过附加API检测Java类

时间:2014-09-22 06:26:40

标签: java bytecode instrumentation java-bytecode-asm

我正在尝试通过attach API检测java类(我想专门用java.sql.DriverManager.getConnection()方法检测并记录返回的Connection对象。

所以,我正在进行存储和加载操作,并调用我的一个类中定义的方法(比如foo.TestRecordingClass.myFooRecordingMethod())。

现在,我的问题是每当我尝试调用前面提到的方法时(通过附加API:agentmain被调用),我得到的是NoClassDefFoundError

但是,同样的事情完全符合premain,a.k.a Xbootclasspath方法。

提前致谢: - )

编辑1:

好的,我可以使用appendToBootstrapClassLoaderSearch(JarFile)对象的instrumentation方法来解决问题。

现在,我面临的另一个问题是将一个this对象加载到堆栈上。

理论上,如果我执行aload_0操作,那应该加载当前对象,那么我可以将它传递给任何方法,对吗?

在方法visitInsn中(即从方法返回时),我这样做:

super.visitVarInsn(Opcodes.ALOAD, 0); super.visitMethodInsn(Opcodes.INVOKESTATIC, fooClassName, "fooMethodReturnInstrumentor", "(Ljava/lang/Object;)V");

这应该加载对象本身,但我无法检索任何内容。

1 个答案:

答案 0 :(得分:1)

如果您检测一个类并插入对其他类的新引用,那么这些类必须可由检测类访问,包括通过其ClassLoader解析它必须成功(与this answer比较)并且必须要么位于相同的package,要么具有public访问修饰符。 This answer包含有关检测核心Java类的一些注释。

因此,如果您的foo.TestRecordingClasspublic并添加到引导类路径中,则任何已检测的类都可以访问它。

仅当方法不是this而不是构造函数时,第一个变量才包含static。在后一种情况下,第一个变量包含一个未初始化的,它在调用超级构造函数之前不能传递给方法调用。

另一方面,此分配仅针对方法的开头进行修复。在该方法中,变量可能会被重用用于其他目的,如果两个分支路径用于不同目的,它们甚至会变得无效。

因此,在不是构造函数的实例方法的开头,您确实可以使用aload_0后跟invokestatic消耗一个对象,将this传递给该方法。你的“我无法找回任何东西”的问题描述有点薄。如果从未调用过您的方法,这可能是一个简单的标志,表示永远不会调用检测代码。如果您收到null,则表明第一个变量不包含this,这是一个强有力的指标。然后,验证插入的调用是否确实位于实例方法的开头。

如果要将调用放在不同的位置,则必须在方法调用之前检查变量0是否永远不会被覆盖。