【问题标题】:Bytecode changes over time in undocumented manner字节码以未记录的方式随时间变化
【发布时间】:2013-08-19 20:02:14
【问题描述】:

今天我在我的 openjdk 7 上使用 javaagent 和检测来探索大型应用程序的类(例如带有应用程序的 jboss 服务器)。我每 10 秒对所有类调用一次重新转换,因此它们的字节码进入了我的 ClassFileTransformer 实现。

我的实现只是跟踪类的字节码如何随时间变化。首先,我很惊讶,字段和方法的顺序、方法访问修饰符、常量池的内容和其他诸如此类的事情因一项检查而异。但是,它仍然是documented

未记录的内容 - 某些项目可能会在类的常量池中创建并注入方法中。现在我注意到数值(Longs、Doubles、Floats 等)会发生这种情况。

这就是它在 javap 中的样子;之前:

pool:
...
#17 Float NaNf
method:
#1 fload #17 //NaNf
...

在运行时更改类之后:

pool:
...
#17 Float NaNf
#18 Float NaNf
method:
#1 fload #18 //NaNf <- look, it loads #18 now

我仔细检查过,没有连接其他转换器或代理。

为什么 JVM 不能让我的字节码保持不变?我在哪里可以了解此类优化/转换(或者还有什么)?我阅读了 JVM 源代码,但这些只会让我更加困惑。

我只是想创建某种实时字节码验证器 - 一种安全工具。

【问题讨论】:

  • 没有什么说生成的代码必须是确定性的,只要代码的效果是确定性的。毫无疑问,许多差异的出现是因为每次运行时事物都会散列到不同的桶中。
  • 抱歉,我不了解存储桶。你指的是什么桶?顺便说一句,没有生成该代码。它被编译,放入罐子中并且一直保持不变。
  • 你有任何正在改变字节码的转换器吗?
  • @Antimony No. 我的返回null,没有其他附加。
  • 存储在文件系统中的.class文件中的代码不会改变,除非你改变它。但是根据定义,转换器会更改类文件的存储映像。

标签: java jvm bytecode


【解决方案1】:

未记录的内容 - 某些项目可能在类的常量池中创建并注入到方法中。

嗯,你自己链接的文章清楚地说:

常量池可能有更多或更少的条目。常量池条目可能有不同的顺序;但是,方法字节码中的常量池索引将对应。

所以它实际上是 记录在案的。原因是准确地记住每个类的字节码是没有用的,因此会重复所有在许多类中相同的常量池条目。 JVM 通常具有与普通类文件不同的内部格式,并在需要时生成类文件,例如调用变压器时。

【讨论】:

  • 其实我关心的是方法体的改变,而不是类池的改变。但是,“JVM ......一旦需要就生成一个类文件”使它更清楚。您对如何检测类更改(作为字节码或 JVM 中的一些数据)有任何想法吗?
  • 问题是,您期望(想要检测)什么样的变化?唯一的非内部更改是通过转换器,JVM 将一个接一个地调用所有转换器。因此,当您删除周期性触发器时,您可以使用转换器已被调用这一事实作为转换发生的指示。
  • 我预计 JVM 内外都会对方法的字节码进行恶意更改。现在我明白了,这个问题可能是无法解决的。当然不是在字节码转换器的帮助下。
  • 问题仍然是你期望什么样的操纵?这种操作的唯一接口是转换器接口或类似于转换器的调试接口。无论如何,拥有覆盖任意数据所需特权的本机代码都会受到关注。他们也可以简单地操纵您的变压器。来自外部的代码必须通过管理 API 才能将代理加载到 JVM 中。这可以通过身份验证机制禁用或保护以确保安全。这比事后检测事件要好。
  • 感谢您的回答。现在我决定使用禁用远程连接和检测任何重新转换调用的转换器的组合。
猜你喜欢
  • 2017-09-01
  • 2021-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多