【发布时间】:2014-07-24 11:34:04
【问题描述】:
我正在对一个 Java 客户端应用程序进行逆向工程,我想对其某些字段的修改进行跟踪,以查看在解决混淆名称的操作之后发生了什么变化。
我可能会使用某种调试器,但我决定自制它以获取学习经验。
我使用 ASM 创建了一个类适配器,它查看每个方法的每条指令,当它遇到 PUTFIELD 指令时,它应该调用对象的 fireCallback 方法
只要我可以期望 PUTFIELD 目标是工作类,这非常简单,但是如果它被其他对象调用,我无法弄清楚如何检测它调用的是哪个对象
我正在阅读 JVM 规范,我发现有一个 DUP 和 POP 指令可用于堆栈操作,当调用 PUTFIELD 时,堆栈上有对象引用和设置值,所以我想为什么我不能复制putfield 之前的堆栈,然后简单地弹出设置值并在剩余的 objectref 上调用 fireCallback
但这不可能那么简单,不幸的是,如果设置值是 double 或 long 类型,则 PUTFIELD 需要两个字,我无法简单地弄清楚如何处理这个异常?
或者有更简单的方法吗?如何知道 putfield 之前加载到堆栈的对象是什么?
我当前的代码:
for (MethodNode method : (List<MethodNode>) methods) {
if (ADD_FIELD_CALLBACKS) {
Iterator<AbstractInsnNode> insIt = method.instructions
.iterator();
while (insIt.hasNext()) {
AbstractInsnNode ins = insIt.next();
int opcode = ins.getOpcode();
if (ins.getOpcode() == Opcodes.PUTFIELD) {
FieldInsnNode fieldInsNode = (FieldInsnNode) ins;
System.out.println(name + "'s updating "
+ fieldInsNode.owner + "'s "
+ fieldInsNode.name + " in method "
+ method.name);
InsnList onFieldEditInsList = new InsnList();
method.instructions.insertBefore(ins, new InsnNode(
Opcodes.DUP2));
onFieldEditInsList.add(new InsnNode(Opcodes.POP));
onFieldEditInsList.add(new LdcInsnNode(
fieldInsNode.name));
onFieldEditInsList
.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
fieldInsNode.owner, "fireCallback",
"(Ljava/lang/String;)V", false));
method.maxStack += 2;
method.instructions.insert(ins, onFieldEditInsList);
}
}
}
}
如果当时堆栈中存在不同的项目集,这会导致带有消息“期望在堆栈上找到对象/数组”的 VerifyError..
【问题讨论】:
-
你不能只使用
dup2,然后用Ljava.lang.Object 调用你的fireCallback 方法,然后使用Object.toString() 方法吗?它至少可以帮助调试 -
我不明白这将如何解决问题?我的意思是,代码甚至没有运行,因为它没有通过验证..
标签: java reverse-engineering instrumentation java-bytecode-asm bytecode-manipulation