Java字节码操作 - 如何在方法中间注入?

时间:2015-11-18 20:43:28

标签: java bytecode bytecode-manipulation

我已经看到很多框架允许您在运行时将字节码注入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();之下注入。

您使用的框架并不重要,任何您喜欢的框架都可以让您这样做对我来说是一个很好的答案。

2 个答案:

答案 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)

https://github.com/Storyyeller/Krakatau