java - 使用 ASM 修改局部变量

标签 java java-bytecode-asm

我需要使用 ASM 来查找方法内部的局部变量,它是:

String var4 = "hello!";

我创建了三个类。一个执行转换,一个扩展 ClassVisitor,一个扩展 MethodVisitor,如下所示:

Transformer 入口点 (Transformationer.java)

package RainbowBansTransAgent;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import org.objectweb.asm.*;

public class Transformationer implements ClassFileTransformer {

    public byte[] transform(String arg1, byte[] arg2){
        ClassReader cr = new ClassReader(arg2);
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
        cr.accept(cw, 0);
        return cw.toByteArray();
    }

    @Override
    public byte[] transform(ClassLoader arg0, String className, Class<?> arg2,
            ProtectionDomain arg3, byte[] arg4)
            throws IllegalClassFormatException {
        BooleanKeys.transformer_loaded = true;
        byte[] b = null;
        String realName = className.replaceAll("/", ".");
        if(realName.equals("joebkt.PlayerList")){
            if(BooleanKeys.returned_bytes){
                return null;
            }else{
            BooleanKeys.found_class = true;
            b =  transform(realName, arg4);
            if(b !=null){
                BooleanKeys.returned_bytes = true;
            }
            }
        }
        else System.out.println("Class name " + realName + " is not what we're looking for!");
        return b;
    }

}

ClassVisior 扩展程序 (RBClassVisitor.java)

package RainbowBansTransAgent;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class RBClassVisitor extends ClassVisitor{

    public RBClassVisitor() {
        super(Opcodes.ASM5);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
        String signature, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, desc, signature,
                exceptions);
        return new RBMethodVisitor(mv);
    }

}

MethodVisitor 扩展程序 (RBMethodVisitor.java)

package RainbowBansTransAgent;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class RBMethodVisitor extends MethodVisitor {

    MethodVisitor mv;

    public RBMethodVisitor(MethodVisitor mv) {
        super(Opcodes.ASM5, mv);
        this.mv = mv;
    }

    public void visitLineNumber(int line, Label start){
        if(line == 409){
            mv.visitCode();
        }
    }

    public void visitCode(){

    }

}

如您所见,我的 visitCode() 方法是空的。我知道这是应该进行字节码操作的方法。

我看到 MethodVisitor 有一个

mv.visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index);   

方法,但我不知道如何正确使用 Label 类。

我的转换器将读取一个文件,并将变量更改为文件的内容。使用 ASM,我该怎么做?

编辑:我想要更改的内容的字节码说: 最不发达国家“你好!” (java.lang.String)

我想把它改成:

ldc“再见!” (java.lang.String)

最佳答案

如果没有基本了解 Java 字节码的工作原理,您不应该尝试进行字节码转换。有关它的信息的主要来源是 The Java® Virtual Machine Specification .对于初学者,您可以阅读 §3 “Compiling for the Java Virtual Machine”学习,某些语言如何构造映射到 byte code instructions .

对于您想要的转换类型,您必须了解的最重要的一点是,在字节代码级别上没有局部变量(您从 Java 语言中了解到的方式)。堆栈帧中有一定数量的局部变量的空间,由数字索引寻址。您在 ASM API 中发现的方法 visitLocalVariable 只有在类文件编译时包含调试信息时才会被调用。

如果它被调用,它会告诉您有关局部变量 name 以及它映射到哪个 index 的信息。 Label 参数告诉您变量的范围,因为它超出了范围,索引可能用于不同的变量。如果您使用这种了解变量特定索引的方式编写代码,则必须记住,此代码仅适用于包含调试提示的类。

因此在字节码级别上,没有变量 var4 的正式声明,而只是将字符串 "hello" 赋值给一个特定的变量,隐含地如果该变量不存在,则创建该变量。该赋值在字节码级别上实现为两条指令,ldc "hello",后跟astore n,其中n是局部变量。实际上,ldc 只包含一个指向保存字符串的常量池的索引,但 ASM 会处理这个并将调用 visitLdcInsn("hello")遇到这条指令时。

所以你可能会搜索两个指令序列,这意味着你必须首先找到正确的索引(例如,使用调试信息,如果存在的话)。或者,如果字符串 "hello" 预计只出现在这个单一的分配中,等待 visitLdcInsn("hello") 的出现并将其替换为不同的常量字符串是最简单的替换形式。

关于java - 使用 ASM 修改局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34834404/

相关文章:

java - Android 设备上的音频文件路径

java - Android java从字符串访问URL而不是硬编码

Java asm从方法变量中获取 "this"对象

java - 字节码检测生成 java validator 错误

java - 父类(super class)不能分配给运行时由 asm 实现的类

java - 改变深度优先搜索的方向

java - Dagger 不喜欢抛出异常的构造函数

java - 使用 java DOM 替换/更改 XSD 文件中的元素类型

java - 是否可以更轻松地检查方法是否被父类(super class)覆盖?

java - ASM 4.0树API : mapping of bytecodes in InsnNodes?