gpt4 book ai didi

java - 使用字节码操作库 ASM 在每次 putfield 操作后调用对象的方法

转载 作者:行者123 更新时间:2023-12-01 12:53:57 25 4
gpt4 key购买 nike

我正在对一个 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,并显示消息“期望在堆栈上找到对象/数组”,以防当时堆栈中存在不同的项目集。

最佳答案

您的问题看起来有点奇怪,因为 putfield 指令已经包含您需要的所有信息。它有一个 reference to the owner class和一个field signature telling the type of the field .

因此,对于遇到 putfield 指令时的有效字节码,最顶层堆栈值必须与字段的类型兼容,下一个值必须是对与所有者类兼容的实例的引用。换句话说,如果字段的签名是 "J""D",则您的值在堆栈顶部占据两个单词,否则它是一个单词.

请注意,对于此类任务,请使用 GeneratorAdapter比较方便。当用作访问者时,它默认会复制遇到的代码,并且可以计算 maxStack 和 maxLocal 值等。因此,您只需重写要注入(inject)代码的指令的访问方法,而无需实现迭代逻辑。

例如对于代码看起来的每个 putField 指令,在类 mypackage.MyDebugger 中调用类似 public static void fieldWrite(Object Owner, String fieldName) 的方法像:

// i.e. class MyCodeTransformer extends GeneratorAdapter
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if(opcode==Opcodes.PUTFIELD) {
final Type fieldType = Type.getType(desc);
super.swap(Type.getObjectType(owner), fieldType);
if(fieldType.getSize()==1) super.dupX1(); else super.dupX2();
super.visitLdcInsn(name);
super.visitMethodInsn(Opcodes.INVOKESTATIC, "mypackage/MyDebugger",
"fieldWrite", "(Ljava/lang/Object;Ljava/lang/String;)V", false);
}
super.visitFieldInsn(opcode, owner, name, desc);
}

关于java - 使用字节码操作库 ASM 在每次 putfield 操作后调用对象的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24026909/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com