简体   繁体   English

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

[英]Java Bytecode Manipulation - How to inject in middle of method?

I have seen many frameworks around that let you inject bytecode into Java classes at runtime. 我已经看到了许多框架,这些框架使您可以在运行时将字节码注入Java类。 But in all of the examples and documentation, they just show how to inject BEFORE and AFTER methods. 但是在所有示例和文档中,它们仅显示了如何注入BEFORE和AFTER方法。 But I need to inject somewhere in the MIDDLE of a method. 但是我需要在方法的中间位置注入。 How do I do this? 我该怎么做呢?

Here is an example method I might want to inject into: 这是我可能要注入的示例方法:

public void doSomething() {
    doOneThing();
    doSomeMoreStuff();

    if (someCondition) {
        doEvenMoreThings();
    }

    if (someOtherCondition) {
        doRandomStuff();
    }

    doStuff();
}

I want to inject here 我想在这里注入

if (someOtherCondition) {
    doRandomStuff();
    // INJECT HERE
}

so that the fully transformed method looks something like this: 这样完全转换的方法看起来像这样:

public void doSomething() {
    doOneThing();
    doSomeMoreStuff();

    if (someCondition) {
        doEvenMoreThings();
    }

    if (someOtherCondition) {
        doRandomStuff();
        callMyInjectedMethodHere(); // This call has been injected
    }

    doStuff();
}

Is this possible? 这可能吗? If so, how? 如果是这样,怎么办?

Every framework I've ever seen has docs that would suggest I can only inject directly above doOneThing(); 我见过的每个框架都有文档,这些文档建议我只能在doOneThing();上方直接注入doOneThing(); or directly below doStuff(); 或直接在doStuff(); .

The framework you use doesn't really matter, any one you like that allows you to do this is a good answer for me. 您使用的框架并不重要,您喜欢的任何一个允许您执行此操作的框架对我来说都是一个很好的答案。

It is easy if you use ASM library (Other bytecode libraries should also have solution for it ). 如果使用ASM库,这很容易(其他字节码库也应该有解决方案)。

Considering the ASM library, you have to create your own MethodVisitor and track the method invocation instruction for doRandomStuff (Assume there is ONLY ONE invocation for doRandomStuff for simplification, otherwise, it would be more complicate). 考虑到ASM库,您必须创建自己的MethodVisitor并跟踪doRandomStuff的方法调用指令(为简化doRandomStuff ,假设doRandomStuff 只能进行一次调用,否则会更加复杂)。

The original bytecode sequence is something like: 原始字节码序列类似于:

  ...
 aload 0
 invokvirtual owner:doRandomStuff()V
 newLable 
 aload 0
 invokevirtual owner:doStuff()V

Then your MethodVisitor is something like: 然后,您的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()
           }
        }
}

Then using your own methodvisitor in the body of visitMethod() of some ClassVisitor. 然后使用自己的methodvisitor在体内visitMethod()一些ClassVisitor的。

I'd recommend learning Java bytecode. 我建议学习Java字节码。 If the application is heavily obfuscated, it can be difficult or impossible to modify in an automated fashion. 如果应用程序被严重混淆,则可能很难或不可能以自动化方式进行修改。 However, if you are knowledgeable about bytecode and willing to take the time to reverse engineer it, you can always modify it, no matter how obfuscated it is. 但是,如果您了解字节码并且愿意花时间对它进行逆向工程,那么无论它多么混乱,您都可以随时对其进行修改。

A good place to start is reading the the JVM specification. 一个不错的起点是阅读JVM规范。 Then try disassembling various classes to get a feeling for how source level constructs get translated into bytecode. 然后尝试分解各种类,以了解如何将源级别的构造转换为字节码。

I'd recommend the Krakatau disassembler/assembler since it handles every obscure corner of the bytecode format and works even on obfuscated code. 我建议使用Krakatau反汇编程序/汇编程序,因为它可以处理字节码格式的每个晦涩之处,甚至可以处理混淆代码。 Unfortunately, Java 8 isn't supported. 不幸的是,不支持Java 8。 (Disclosure, I wrote Krakatau) (公开,我写了《喀拉喀托》)

https://github.com/Storyyeller/Krakatau https://github.com/Storyyeller/Krakatau

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM