1

To debug a jar file, i tried to modify java bytecode using JByteMod tool and print some variable to standard output. The variable i'm trying to print is an ArrayList. Specifically, it's a public attribute of class MethodNode, named outgoings_. The code is something like this:

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)

The above code works fine and actually prints the list. For some reasons, i needed to print the first element of that list, so i changed the code:

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)

But this code fails to run and outputs this error:

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

What i'm doing wrong? Is it a JByteMod bug?

EDIT:

Here are the links to the class file before and after modification.

  • Most likely it is a JByteMod bug, but there's no way to know for sure unless you post the (binary) classfiles before and after modification. – Antimony Apr 19 at 15:48
  • @Antimony I added links to the class file before and after modification. Is there any other better tool around? I also tried JBE but it seems have problems saving newly added bytecodes. – Mehran Torki Apr 19 at 16:49
  • 3
    Pelase report this issue to the tool author, they're in better position to determine if it's bug or not. In the meantime you can try Krakatau. – Igor Skochinsky Apr 20 at 12:54
4

The issue is that constant pool entry 67 (the one for your List.get()) method has the type Method, rather than InterfaceMethod, even though you are trying to invoke it as an interface method. When using invokeinterface, the corresponding constant pool entries need to be InterfaceMethod.

Assuming you didn't specify the type itself, this is likely a bug in the tool you used. You may want to try using the Krakatau assembler/disassembler instead.

When using Krakatau, the constant pool type is specified after the invoke instruction. For example, on the following line of the disassembly for your class, Method should be changed to InterfaceMethod.

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

Regarding your comment (Would respond as a comment, but don't have the 50 rep yet):

I added links to the class file before and after modification. Is there any other better tool around?

I develop the bytecode editor Recaf. I reimplemented your code and it worked just fine. However lets say you forgot the isInterface flag on your INVOKEINTERFACE instruction (ASM: MethodInsnNode.itf boolean), then you have a problem.

When I attempted to save the modified file with this flag missing the ASM verifier threw an exception, giving the reason INVOKEINTERFACE can't be used with classes. When you export a jar with Recaf all your modified files are pre-verified to ensure their bytecode is valid. I actually forgot to put the flag on myself until the verifier window popped up. If I disable the verification process and then export the jar then I get the same VerifyError you just gave.

So to reiterate this is very likely to have been user-error, but JBytemod didn't catch that.

  • You are right, but there is no checkbox or anything else for setting the isInterface flag when adding a invokeinterface instruction in JByteMod. – Mehran Torki Apr 22 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.