本地Java字节码插桩

5

对于Java字节码注入,有ASM框架和BCEL和Javaassist库。

然而,我需要在本地代码中进行注入,因为一些Java类已经在Java代理程序运行时加载,例如java.lang.Thread、java.lang.Class等。

是否有用于在本地代码中注入Java类的库?

编辑: 似乎有点混淆。

我的意图是: 创建一个本地Java代理程序,使用JVMTI API在类被加载时更改字节码,使用OnClassLoad事件钩子。


5
你需要解决的最初问题是什么? - Thorbjørn Ravn Andersen
“本地代码”是什么意思?http://www.cs.ioc.ee/~ando/jbe/ 提供了一种工具,使您能够直接编辑Java字节码。 - Gelin Luo
@ThorbjørnRavnAndersen 我想要对像Thread和Class这样在JavaAgent加载之前就已经被加载的类进行仪器化,因此它们必须在本地代理中进行仪器化。 - pdeva
在没有答案的情况下,很难接受一个答案,就像在这个帖子中一样... - pdeva
我想知道你最终是如何解决这个问题的?我正准备评估使用本地代理选项,该代理可以为某些类的字节码提供仪器支持,但仍然找不到任何可以实现此功能的C/C++库。 - Mark Bramnik
3个回答

9
在我的博士研究中遇到了这个问题。对我最有效的答案是使用一个Java库(我使用了ASM)在单独的JVM中执行字节码修改。
我使用JVMTI类加载钩子来捕获类文件并通过TCP连接将其传输到单独的JVM。一旦类在单独的JVM中被修改,我将其返回给JVMTI代理,该代理将其复制到VM内存并返回指向已修改类文件的指针给JVM。
我发现在正在进行分析的同一JVM中编织类太困难了,因为我想要修改的系统类文件 (例如java.lang.Object) 必须在任何需要执行编织的类文件之前加载。我寻找了c/c++字节码库,但没有取得多少成功,在最后选择了我用过的单独的JVM方法。
您可以使用主机名/端口来参数化JVMTI代理,也可以根据您的要求使用某种形式的发现。

3
有些其他答案略有错误或完全错误。您可以更改已加载的类的字节码,甚至是系统类。一旦加载了一个类,您就不能影响其外部签名(添加字段/方法),但是您可以更改方法体。JVM中提供的基本heapTracker JVMTI演示了更改java.lang.Object.<init>()行为的方式。 - Stephen Nelson

3
JIT将字节码转换为本机代码。如果您想生成本机代码,需要让JIT执行或编写通过JNI调用的本机代码。
也许您尝试实现的目标可以通过另一种更简单的方式来完成。
创建一个本机Java代理程序,在加载类时使用JVMTI API,使用OnClassLoad事件钩子改变类的字节码。
虽然您不需要做您想要的事情。为什么要让解决方案比必要的更复杂(且不太可能起作用)?

在这种情况下,你的问题没有任何意义。你为什么需要使用本地代码来生成字节码? - Peter Lawrey
每个ClassLoader都可以加载这些类并重新加载字节码(有限制)。系统从BootStrap类加载器开始,应用程序本身在其自己的类加载器中启动。 - Peter Lawrey
1
http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html#redefineClasses%28java.lang.instrument.ClassDefinition...%29 - Peter Lawrey
如果您想修改系统类,最简单的方法是更改副本(从src.zip中),编译它并将其添加到引导类路径(或将其添加到认可目录)。 - Peter Lawrey
1
我知道如何重新定义类,但它不允许添加字段。另外,重新编译rt.jar也不是一个选项。你显然对任何本地字节码工具库都没有任何了解。请停止建议那些行不通的替代方案,专注于原始问题。 - pdeva
显示剩余6条评论

-2

一旦类被加载,就无法更改其字节码。您可以确保在加载之前运行您的仪器,或者创建一个新的ClassLoader,并通过不要求父类重新加载其中的类。但是,您不能将这些类与在ClassLoader之外加载的代码一起使用,因为该代码将引用先前加载的未更改的类。


1
我不想在加载字节码后更改它。我想使用本地代理在类加载时更改字节码。 - pdeva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接