Jos*_*one 3 java bytecode-manipulation java-bytecode-asm
如何检查类的字节码(使用诸如ASM之类的东西)来了解哪些初始值传递给方法?
例如:给定一些将值互相传递的方法:
void m1(Object o) {
Object v = o;
m2(v);
m2("box");
}
void m2(Object o) {
Object v = o;
m3(x);
}
void m3(Object o) {
}
Run Code Online (Sandbox Code Playgroud)
还有一些方法调用,都在同一个类中定义:
{
Object foo = "foo";
m1(foo);
m2("bar");
m3("baz");
}
Run Code Online (Sandbox Code Playgroud)
我怎么可以检查类的字节码得知m3将与值被称为4倍"foo","box","bar"和"baz"?
使用ASM,理论上可以跟踪每个方法,如果从其中调用同一个类的另一个方法.访问者API负责定义方法调用的方法是visitMethodIns.假设您的类被调用bar.Foo,您需要跟踪:
visitMethodIns(<any>, "bar.Foo", <any>, <any>)
Run Code Online (Sandbox Code Playgroud)
然后,您需要构建一个彼此调用的方法的传递关系,其中最后两个参数允许您构建这样的关系层次结构.此外,您需要跟踪这些方法调用的参数,更棘手但也不是不可能.
它更复杂的原因是参数可以加载到操作数堆栈的可能方式的数量.对于您的示例,您只需要关注visitIns和visitLCDIns回调.
在常量池值(LCD)上调用方法时,参数的分辨率相当微不足道.但是,在调用方法学习局部变量赋值之前,您需要跟踪整个指令链,以便知道您正在调用方法参数上的方法.因此,你可以找到答案
ALOAD_0 / ASTORE_1 / ALOAD_1 => ALOAD_0
Run Code Online (Sandbox Code Playgroud)
从方法局部变量数组中读取/写入序列的有效结果.
有了这一切,通过解析字节代码,您将了解以下调用转换:
m1(Ljava/lang/Object)V -> m2(Ljava/lang/Object)V [ALOAD 0]
-> m2(Ljava/lang/Object)V [LCD "box"]
m2(Ljava/lang/Object)V -> m3(Ljava/lang/Object)V [ALOAD 0]
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用这些结果来解析块,在那里您可以找到这些方法调用及其含义.然而,你会创建一个非常脆弱的解决方案,其中的间接如下:
{
Foo foo = this;
foo.m1("bar");
}
Run Code Online (Sandbox Code Playgroud)
不会被发现.正如评论中所指出的,您基本上需要模拟Java虚拟机以"运行"您的代码.
即使您实施了一个复杂的解决方案来追踪所有这些,您仍然无法确定您的结果.当我从实现中调用接口方法时会发生什么.还是一个子类的方法?由于动态调度方法,您永远无法确定被调用的目标.
| 归档时间: |
|
| 查看次数: |
1109 次 |
| 最近记录: |