4

Say I want to take a java class file, disassemble it, tweak the java bytecode output, and then reassemble it again.

I need to rename a symbol in the constant pool table. I also don't have access to the source code, and using a decompiler seems like overkill for this. I'm not trying to optimize anything - java does a fine job at that.

Is there... a simple way to do this? I've found several tools for either disassembly or reassembly, but none for both; or no pairs of tools which seem to use the same format for representing the bytecode in text.

Kelly S. French
  • 12,198
  • 10
  • 63
  • 93
Lunpa
  • 151
  • 2
  • 9

5 Answers5

6

Did you check the ASM API?

Here is a code sample (adapted from the official documentation) explaining how to modify a class bytecode:

ClasssWriter cw = new ClassWriter();
ClassAdapter ca = new ClassAdapter(cw); // ca forwards all events to cw
// ca should modify the class data
ClassReader cr = new ClassReader("MyClass");
cr.accept(ca, 0);
byte[] b2 = cw.toByteArray(); // b2 represents the same class as MyClass, modified by ca

Then b2 can be stored in a .class file for future use. You can also use the method ClassLoader.defineClass(String,byte[],int,int) to load it if you define your own classloader.

Guillaume
  • 5,535
  • 1
  • 24
  • 30
  • I'd +1 this answer if you'd add some example code, a link to a tutorial or just a descriptive sentence or two. – Sean Patrick Floyd Nov 15 '10 at 16:59
  • Conceptually, it looks promising. The documentation is quite dense though... and leaves me confused: is this a tool? is it a library? I don't see a straight forward way of using it... could you shed some light on this? – Lunpa Nov 15 '10 at 17:13
5

Krakatau provides an open source disassembler and assembler that make this very easy. Krakatau is designed to be a replacement for Jasmin. It uses a Jasmin like syntax for backwards compatibility but extends the format to support all the obscure features in the classfile format and fix bugs in Jasmin. It also lets you easily disassemble, modify, and reassemble classes.

The only real downside to Krakatau is that it currently doesn't documented very well. But if you have any questions, feel free to ask. (Disclosure: I wrote Krakatau).

Antimony
  • 37,781
  • 10
  • 100
  • 107
5

This question is a bit older now, but as I don't find this answered anywhere on stackoverflow, let me put it on record:

There's the standard jasper/jasmin combo that I have successfully used in the past:

  • jasper for disassembly to a jasmin-compatible format
  • jasmin which will reassemble jasper's output

The only annoyance with jasper is that it forgets to create a label for the switch default clause, and then jasmin will give you errors like

Main.j:391: JAS Error Label: LABEL0x48 has not been added to the code.

Which then means you have to go into the .j file, and manually fix it. "javap -c" might assist you there. For that bug I'd suggest you jasper and immediately jasmin, before any modifications, just to make sure that works.

You can actually fix that label bug by applying this patch to jasper:

--- Code_Collection.java.orig   1999-06-14 14:10:44.000000000 +0000
+++ Code_Collection.java        2011-02-05 07:23:21.000000000 +0000
@@ -1210,6 +1210,7 @@
     -----------------------------------------------------------------------*/
    void getLabel(Code_Collection code) {
       for (int i = 0; i < count; i++) code.setLabel(pc+branch[i]);
+      code.setLabel(pc+tableDefault);
    }

    /*-----------------------------------------------------------------------

I submitted it to the author, but I got a feeling the project has not been worked on for many years, so I don't know if it'll get merged in.

Edit: Jasper with the above patch applied is now available at https://github.com/EugenDueck/Jasper

And then there's Eclipse Bytecode Outline, as described in this answer: java bytecode editor?

Community
  • 1
  • 1
Eugen Dück
  • 192
  • 1
  • 9
  • For those not clear, or unsure how to use the above patch -- open Code_Collection.java, go to line 1210 (ctrl+g in notepad), add a second line to the getLabel method: code.setLabel(pc+tableDefault); then recompile (you'll need the JDK installed & pathes setup properly): javac *.java then rename jasper.jar to jasper.zip In the zip there is a jasper folder, open it, in that folder, replace Code_tableswitch.class with the Code_tableswitch.class you just made during the compile step. from there, rename the .zip back to .jar and you're good to go. – BrainSlugs83 May 17 '12 at 04:14
  • Unfortunately Jasmin has poor support for more obscure or unusual classfile features. Personally, I'd recommend using Krakatau, though Jasmin is probably good enough for ordinary classes. – Antimony Jul 02 '13 at 14:52
  • There's a similar line missing after line 1013. Add code.setLabel(pc+lookupDefault) – user2543253 Oct 09 '14 at 11:48
0

Wouldn't it just be easier to find the original source code, modify it, then recompile it? Or is this from some binary code you don't have the source to?

Pro tip: The source code to the built-in Java Class Library is available as part of the OpenJDK project, specifically in the OpenJDK 6 Source.

Powerlord
  • 87,612
  • 17
  • 125
  • 175
0

You are describing what modern compilers do already. In addition to that, most JVMs can (and try to) keep optimizing the byte code while the app is running.

Start with studying what existing compilers/JVM's are doing with the byte code. The best case is that you can improve on the the JVM's optimizer which is possible but a low probability and either way you may be reinventing the wheel. The worst case is your changes actually interfere with the the runtime optimizer and cause overall performance to go down.

  1. Study compilers and JVMs
  2. Benchmark
  3. Benchmark
  4. Benchmark

[EDIT] Found a related post: Bytecode manipulation patterns

Community
  • 1
  • 1
Kelly S. French
  • 12,198
  • 10
  • 63
  • 93
  • Your assumptions on what I am doing are false: I need to rename a symbol in the constant pool table. I also don't have access to the source code, and using a decompiler seems like overkill for this (and probably not terribly legal). I'm not trying to optimize anything - java does a fine job at that. – Lunpa Nov 15 '10 at 18:05
  • This tool accomplishes pretty much what I needed to do from a practical standpoint: http://classeditor.sourceforge.net/index.html - but it doesn't do anything fancy with disassembly/reassembly. Oh well. – Lunpa Nov 15 '10 at 18:25
  • @Lunpa, You are right, I jumped to a conclusion about why you were wanting to modify byte code. Have you tried manually tweaking a .class file? What you describe sounds like what people have used 'sed' for on Unix boxes. That might work if the search/replace is straight forward enough and there are no problems with renaming a symbol (like alignment). – Kelly S. French Nov 15 '10 at 18:47
  • @Lunpa, if you are only doing a symbol rename, the classeditor from your link may be all you need – Kelly S. French Nov 15 '10 at 18:50