转换调用方法参数

时间:2014-05-09 06:37:54

标签: java java-bytecode-asm bytecode-manipulation

我正在尝试确保通过我的类转换器运行动态加载的类,为了这样做,我需要在将字节码加载到类之前修改它

我要做的是确定调用defineClass之前是否调用了defineClass并在调用defineClass之前调用我的字节码转换方法

但是我无法确定每个参数的起始位置,它们是按顺序排列的,但我不知道如何知道哪个参数从哪个开始?

此处以及使用ASMifier创建的示例

//The first parameter
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
//second parameter, byte array, this is what I am looking for!!
mv.visitVarInsn(ALOAD, 4);
//third parameter
mv.visitInsn(ICONST_0);
//fourth parameter
mv.visitVarInsn(ALOAD, 4);
mv.visitInsn(ARRAYLENGTH);
//fifth parameter
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getProtectionDomain", "()Ljava/security/ProtectionDomain;");
mv.visitMethodInsn(INVOKEVIRTUAL, "b", "defineClass", "(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;");

我如何删除哪些指令正在加载为defineClass作为参数的字节数组,以便通过我的变换器运行它并使用返回值?

我无法看清参数之间的明确分离,而且我找不到任何有关此内容的文档..

我不明白JVM何时知道参数何时开始以及何时参数结束......

我可以很容易地提取字节数组参数索引是什么,但是知道我可以找到加载字节数组的字节码?

1 个答案:

答案 0 :(得分:0)

有两种方法:

  1. 跟踪将特定值放入堆栈的指令(例如,使用ASM字节码操作框架中的SourceInterpreter
  2. 在使用这些值的位置访问堆栈上的值(例如,在INVOKEVIRTUAL用于defineClass方法之前)
  3. 第二种方法更容易实现,因为方法descriptor tells you每个方法参数使用什么堆栈槽。然后你只需要从堆栈中加载值,复制它们供你自己使用,然后把它们放回原处。

    ASM字节码框架提供了LocalVariablesSorter帮助程序,可以很容易地在字节码中引入新的局部变量。