常量池错误

逆向工程 爪哇 字节码
2021-06-17 07:41:49

为了调试 jar 文件,我尝试使用 JByteMod 工具修改 java 字节码并将一些变量打印到标准输出。我试图打印的变量是一个ArrayList. 具体来说,它是 class 的一个公共属性MethodNode,名为outgoings_. 代码是这样的:

invokeinterface Object Iterator.next()
checkcast MethodNode
astore 4
######## my code begins from here #######
getstatic PrintStream System.out
aload 4
getfield List MethodNode.outgoings_
invokevirtual void PrintStream.println(Object)

上面的代码工作正常并且实际打印了列表。由于某些原因,我需要打印该列表的第一个元素,因此我更改了代码:

invokeinterface Object Iterator.next()
checkcast MethodNode
astore 4
######## my code begins from here #######
getstatic PrintStream System.out
aload 4
getfield List MethodNode.outgoings_
iconst_0
invokeinterface Object List.get(int)
invokevirtual void PrintStream.println(Object)

但是此代码无法运行并输出此错误:

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: java.lang.VerifyError: Illegal type at constant pool entry 67 in class wy2.SCCUtil
Exception Details:
  Location:
    wy2/SCCUtil.buildScc(Lwy/CallGraph;)V @51: invokeinterface
  Reason:
    Constant pool index 67 is invalid
  Bytecode:
    0x0000000: bb00 1f59 b700 204d bb00 1659 b700 174e
    0x0000010: 2bb4 0026 b900 2c01 003a 05a7 0029 1905
    0x0000020: b900 3401 00c0 0036 3a04 b200 3c19 04b4
    0x0000030: 003f 03b9 0043 0200 b600 492a 2b19 042c
    0x0000040: 2db6 004d 1905 b900 5101 009a ffd3 2db9
    0x0000050: 0054 0100 a700 6f2c b600 57c0 0036 3a04
    0x0000060: 2d19 04b9 005b 0200 9900 06a7 0058 bb00
    0x0000070: 5d59 b700 5e3a 052a 2b19 042d 1905 b400
    0x0000080: 61b6 0065 1905 b400 61b9 0066 0100 3a07
    0x0000090: a700 1d19 07b9 0034 0100 c000 363a 062a
    0x00000a0: b400 1419 0619 05b9 006c 0300 5719 07b9
    0x00000b0: 0051 0100 9aff df2a b400 1919 05b9 006f
    0x00000c0: 0200 572c b600 7299 ff90 2ab4 0019 b900
    0x00000d0: 6601 003a 05a7 0107 1905 b900 3401 00c0
    0x00000e0: 005d 3a04 1904 b400 61b9 0066 0100 3a07
    0x00000f0: a700 d319 07b9 0034 0100 c000 363a 0619
    0x0000100: 06b4 003f b900 2c01 003a 09a7 004c 1909
    0x0000110: b900 3401 00c0 0036 3a08 2bb4 0026 1908
    0x0000120: b900 7302 009a 0006 a700 2f2a b400 1419
    0x0000130: 08b9 0076 0200 1904 a600 06a7 001c 1904
    0x0000140: b400 782a b400 1419 08b9 0076 0200 c000
    0x0000150: 5db9 006f 0200 5719 09b9 0051 0100 9aff
    0x0000160: b019 06b4 007b b900 2c01 003a 09a7 004c
    0x0000170: 1909 b900 3401 00c0 0036 3a08 2bb4 0026
    0x0000180: 1908 b900 7302 009a 0006 a700 2f2a b400
    0x0000190: 1419 08b9 0076 0200 1904 a600 06a7 001c
    0x00001a0: 1904 b400 7e2a b400 1419 08b9 0076 0200
    0x00001b0: c000 5db9 006f 0200 5719 09b9 0051 0100
    0x00001c0: 9aff b019 07b9 0051 0100 9aff 2919 0419
    0x00001d0: 04b4 0078 b900 8201 00b5 0086 1905 b900
    0x00001e0: 5101 009a fef5 b1                      
  Stackmap Table:
    full_frame(@30,{Object[#2],Object[#34],Object[#31],Object[#46],Top,Object[#48]},{})
    same_frame(@68)
    chop_frame(@87,2)
    append_frame(@110,Object[#54])
    append_frame(@147,Object[#93],Top,Object[#48])
    same_frame(@173)
    full_frame(@195,{Object[#2],Object[#34],Object[#31],Object[#46]},{})
    append_frame(@216,Top,Object[#48])
    full_frame(@243,{Object[#2],Object[#34],Object[#31],Object[#46],Object[#93],Object[#48],Top,Object[#48]},{})
    full_frame(@270,{Object[#2],Object[#34],Object[#31],Object[#46],Object[#93],Object[#48],Object[#54],Object[#48],Top,Object[#48]},{})
    full_frame(@299,{Object[#2],Object[#34],Object[#31],Object[#46],Object[#93],Object[#48],Object[#54],Object[#48],Object[#54],Object[#48]},{})
    same_frame(@318)
    full_frame(@343,{Object[#2],Object[#34],Object[#31],Object[#46],Object[#93],Object[#48],Object[#54],Object[#48],Top,Object[#48]},{})
    same_frame(@368)
    full_frame(@397,{Object[#2],Object[#34],Object[#31],Object[#46],Object[#93],Object[#48],Object[#54],Object[#48],Object[#54],Object[#48]},{})
    same_frame(@416)
    full_frame(@441,{Object[#2],Object[#34],Object[#31],Object[#46],Object[#93],Object[#48],Object[#54],Object[#48],Top,Object[#48]},{})
    full_frame(@451,{Object[#2],Object[#34],Object[#31],Object[#46],Object[#93],Object[#48],Top,Object[#48]},{})
    full_frame(@476,{Object[#2],Object[#34],Object[#31],Object[#46],Top,Object[#48]},{})

    at wy2.Util.buildMethodHash2(Util.java:132)
    at wy2.Util.doIt(Util.java:29)
    at wy2.Main.genData(Main.java:68)
    at wy2.Main.main(Main.java:59)
    ... 5 more

我在做什么错?这是一个 JByteMod 错误吗?

编辑:

这里是链接到的类文件之前之后的修改。

2个回答

问题是常量池条目 67(用于 List.get() 的方法)具有 type Method,而不是InterfaceMethod,即使您尝试将其作为接口方法调用。使用时invokeinterface,需要对应的常量池条目InterfaceMethod

假设您没有指定类型本身,这可能是您使用的工具中的错误。您可能想尝试改用Krakatau 汇编器/反汇编器

使用 Krakatau 时,常量池类型在 invoke 指令之后指定。例如,在您类的反汇编的以下行中,Method应更改为InterfaceMethod.

L51:    invokeinterface Method java/util/List get (I)Ljava/lang/Object; 2 

关于您的评论(将作为评论回复,但还没有 50 代表)

我在修改前后添加了类文件的链接。还有其他更好的工具吗?

我开发了字节码编辑器Recaf重新实现了你的代码,它工作得很好。但是,假设您忘记了指令中isInterface标志(ASM: MethodInsnNode.itf boolean),那么您就有问题了。INVOKEINTERFACE

当我尝试使用此标志保存修改后的文件时,ASM 验证程序抛出了一个异常,给出了原因INVOKEINTERFACE can't be used with classes当您使用 Recaf 导出 jar 时,所有修改过的文件都经过预先验证,以确保它们的字节码有效。在验证器窗口弹出之前,我实际上忘了给自己贴上标志。如果我禁用验证过程然后导出 jar,那么我会得到与您刚刚给出的相同的 VerifyError。

所以重申这很可能是用户错误,但 JBytemod 没有发现