我已经看到很多框架允许您在运行时将字节码注入Java类。但是在所有的例子和文档中,他们只展示了如何注入BEFORE和AFTER方法。但我需要在方法的MIDDLE中注入某个地方。我该怎么做?
以下是我可能要注入的示例方法:
public void doSomething() {
doOneThing();
doSomeMoreStuff();
if (someCondition) {
doEvenMoreThings();
}
if (someOtherCondition) {
doRandomStuff();
}
doStuff();
}
我想在这里注入
if (someOtherCondition) {
doRandomStuff();
// INJECT HERE
}
这样完全转换的方法看起来像这样:
public void doSomething() {
doOneThing();
doSomeMoreStuff();
if (someCondition) {
doEvenMoreThings();
}
if (someOtherCondition) {
doRandomStuff();
callMyInjectedMethodHere(); // This call has been injected
}
doStuff();
}
这可能吗?如果是这样,怎么样?
我见过的每个框架都有文档,建议我只能直接在doOneThing();
之上或doStuff();
之下注入。
您使用的框架并不重要,任何您喜欢的框架都可以让您这样做对我来说是一个很好的答案。
答案 0 :(得分:1)
如果使用ASM库很容易(其他字节码库也应该有解决方案)。
考虑到ASM库,您必须创建自己的MethodVisitor并跟踪doRandomStuff
的方法调用指令(假设doRandomStuff
有 ONLY ONE 调用以简化,否则,会更复杂)。
原始字节码序列类似于:
...
aload 0
invokvirtual owner:doRandomStuff()V
newLable
aload 0
invokevirtual owner:doStuff()V
然后您的MethodVisitor类似于:
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的methodvisitor
正文中使用您自己的visitMethod()
。
答案 1 :(得分:-1)
我建议学习Java字节码。如果应用程序被严重混淆,则可能难以或无法以自动方式进行修改。但是,如果您对字节码有所了解并愿意花时间对其进行逆向工程,那么无论它有多混淆,您都可以随时对其进行修改。
一个好的起点是阅读JVM规范。然后尝试反汇编各种类,以了解源级构造如何转换为字节码。
我推荐使用Krakatau反汇编程序/汇编程序,因为它处理字节码格式的每个模糊角落,甚至可以在混淆代码上运行。遗憾的是,Java 8并不受支持。 (披露,我写了Krakatau)