I am reverse engineering a Java client application of which I'd like to track modifications of certain fields to see what's changed after which action to resolve the obfuscated names.
I could probably use a debugger of some kind, but I decided to homebrew it for the learning experience.
I've created a class adapter using ASM which is looking through every method's every instruction and when it hits PUTFIELD instruction its supposed to call the object's fireCallback method
It's pretty simple as long as I can expect the PUTFIELD target to be the working class, but if its being called on other object I can't figure out how can I detect which object is it called on
I was reading JVM spec and I found there's a DUP and POP instructions that could be used to stack manipulation and that when PUTFIELD is called there's on stack the object reference and the setting value so I thought why couldn't I just duplicate the stack before putfield and then simply pop the setting value and call fireCallback on the remaining objectref
But it just can't be that simple, unfortunately the PUTFIELD takes two words if the setting value is of type double or long, and I can't simply figure how can I handle this exception?
Or is there some simpler way? How do I know what object is loaded to the stack before putfield?
My current code:
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);
}
}
}
}
this results in a VerifyError with message "Expecting to find object/array on stack" in case there was different set of items in the stack at the time..