Java Bytecode Manipulation - How to inject in middle of method?
我见过很多框架让你在运行时将字节码注入Java 类。但在所有示例和文档中,它们只是展示了如何注入 BEFORE 和 AFTER 方法。但我需要在方法中间的某个地方注入。我该怎么做?
这是我可能想要注入的示例方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public void doSomething() { doOneThing(); doSomeMoreStuff(); if (someCondition) { doEvenMoreThings(); } if (someOtherCondition) { doRandomStuff(); } doStuff(); } |
我想在这里注入
1 2 3 4 | if (someOtherCondition) { doRandomStuff(); // INJECT HERE } |
所以完全转换的方法看起来像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void doSomething() { doOneThing(); doSomeMoreStuff(); if (someCondition) { doEvenMoreThings(); } if (someOtherCondition) { doRandomStuff(); callMyInjectedMethodHere(); // This call has been injected } doStuff(); } |
这可能吗?如果有,怎么做?
我见过的每个框架都有文档建议我只能在
你使用的框架并不重要,任何你喜欢的允许你这样做的对我来说都是一个很好的答案。
如果你使用 ASM 库很容易(其他字节码库也应该有解决方案)。
考虑到 ASM 库,您必须创建自己的 MethodVisitor 并跟踪
原始字节码序列类似于:
1 2 3 4 5 6 | ... aload 0 invokvirtual owner:doRandomStuff()V newLable aload 0 invokevirtual owner:doStuff()V |
那么你的 MethodVisitor 类似于:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class YourMethodVisitor extends MethodVisitor{ @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { String target = MethodType.methodType(void.class).toMethodDescriptorString(); super.visitMethodInsn(opcode, owner, name, desc, itf); //visit doRandomStuff() if(opcode == Opcodes.INVOKEVIRTUAL && owner =="yourOwner" && name.equals("doRandomStuff") && desc.equals(target)){ mv.visitVarInsn(Opcodes.ALOAD, 0); //Load this super.visitMethodInsn(opcode, owner,"callMyInjectedMethodHere", target, itf); //visit callMyInjectedMethodHere() } } } |
然后在某些 ClassVisitor 的
我建议学习 Java 字节码。如果应用程序被严重混淆,则可能很难或不可能以自动化方式进行修改。但是,如果您了解字节码并愿意花时间对其进行逆向工程,则无论它多么模糊,您都可以随时修改它。
一个好的起点是阅读 JVM 规范。然后尝试反汇编各种类,以了解源级构造如何转换为字节码。
我推荐 Krakatau 反汇编器/汇编器,因为它可以处理字节码格式的每个晦涩角落,甚至可以处理混淆代码。不幸的是,不支持 Java 8。 (披露,我写了 Krakatau)
https://github.com/Storyyeller/Krakatau