Synopsis
Java bytecode programs reside in .class files, which in turn may reside in
.jar or .war files.
This document describes locating and editing byte codes within .class files.
If the .class file of interest resides in .jar or .war files,
it will have to be extracted first, edited, then put back into the .jar or .war files.
Extracting a Class File from a JAR or WAR File
You can use pkunzip or similar tools to extract the .class file.
If you change the extension .jar or .war to .zip,
modern versions of Windows will also allow you to drag and drop the .class files in the .zip
file.
Use javap to Disassemble the Class File
The Java disassembler is available from Sun Microsystems, as part of the Java SDK.
Use javap -c -private -verbose -l to extract the most information from your
class file. You will need the details.
For example, the following hello.java is compiled into hello.class and mainframe.class:
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class mainframe extends JFrame
implements ActionListener
{
mainframe()
{
super("K500i Hello World"+1);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btn;
btn = new JButton("Exit");
btn.addActionListener(this);
getContentPane().add(btn);
pack();
}
public void actionPerformed(ActionEvent e)
{
dispose();
}
}
public class hello
{
public static void main(String args[])
{
mainframe f;
f = new mainframe();
f.show();
}
}
Using C:\classlib>javap -private -verbose -c -l mainframe,
the mainframe.class is disassembled to:
Compiled from "hello.java"
class mainframe extends javax.swing.JFrame implements java.awt.event.ActionListener
SourceFile: "hello.java"
minor version: 0
major version: 49
Constant pool:
const #1 = String #23; // K500i Hello World1
const #2 = Method #13.#24; // javax/swing/JFrame."":(Ljava/lang/String;)V
const #3 = Method #12.#25; // mainframe.setDefaultCloseOperation:(I)V
const #4 = class #26; // javax/swing/JButton
const #5 = String #27; // Exit
const #6 = Method #4.#24; // javax/swing/JButton."":(Ljava/lang/String;)V
const #7 = Method #4.#28; // javax/swing/JButton.addActionListener:(Ljava/awt/event/ActionListener;)V
const #8 = Method #12.#29; // mainframe.getContentPane:()Ljava/awt/Container;
const #9 = Method #30.#31; // java/awt/Container.add:(Ljava/awt/Component;)Ljava/awt/Component;
const #10 = Method #12.#32; // mainframe.pack:()V
const #11 = Method #12.#33; // mainframe.dispose:()V
const #12 = class #34; // mainframe
const #13 = class #35; // javax/swing/JFrame
const #14 = class #36; // java/awt/event/ActionListener
const #15 = Asciz ;
const #16 = Asciz ()V;
const #17 = Asciz Code;
const #18 = Asciz LineNumberTable;
const #19 = Asciz actionPerformed;
const #20 = Asciz (Ljava/awt/event/ActionEvent;)V;
const #21 = Asciz SourceFile;
const #22 = Asciz hello.java;
const #23 = Asciz K500i Hello World1;
const #24 = NameAndType #15:#37;// "":(Ljava/lang/String;)V
const #25 = NameAndType #38:#39;// setDefaultCloseOperation:(I)V
const #26 = Asciz javax/swing/JButton;
const #27 = Asciz Exit;
const #28 = NameAndType #40:#41;// addActionListener:(Ljava/awt/event/ActionListener;)V
const #29 = NameAndType #42:#43;// getContentPane:()Ljava/awt/Container;
const #30 = class #44; // java/awt/Container
const #31 = NameAndType #45:#46;// add:(Ljava/awt/Component;)Ljava/awt/Component;
const #32 = NameAndType #47:#16;// pack:()V
const #33 = NameAndType #48:#16;// dispose:()V
const #34 = Asciz mainframe;
const #35 = Asciz javax/swing/JFrame;
const #36 = Asciz java/awt/event/ActionListener;
const #37 = Asciz (Ljava/lang/String;)V;
const #38 = Asciz setDefaultCloseOperation;
const #39 = Asciz (I)V;
const #40 = Asciz addActionListener;
const #41 = Asciz (Ljava/awt/event/ActionListener;)V;
const #42 = Asciz getContentPane;
const #43 = Asciz ()Ljava/awt/Container;;
const #44 = Asciz java/awt/Container;
const #45 = Asciz add;
const #46 = Asciz (Ljava/awt/Component;)Ljava/awt/Component;;
const #47 = Asciz pack;
const #48 = Asciz dispose;
{
mainframe();
LineNumberTable:
line 11: 0
line 12: 6
line 16: 11
line 18: 21
line 20: 26
line 22: 35
line 23: 39
Code:
Stack=3, Locals=2, Args_size=1
0: aload_0
1: ldc #1; //String K500i Hello World1
3: invokespecial #2; //Method javax/swing/JFrame."":(Ljava/lang/String;)V
6: aload_0
7: iconst_3
8: invokevirtual #3; //Method setDefaultCloseOperation:(I)V
11: new #4; //class javax/swing/JButton
14: dup
15: ldc #5; //String Exit
17: invokespecial #6; //Method javax/swing/JButton."":(Ljava/lang/String;)V
20: astore_1
21: aload_1
22: aload_0
23: invokevirtual #7; //Method javax/swing/JButton.addActionListener:(Ljava/awt/event/ActionListener;)V
26: aload_0
27: invokevirtual #8; //Method getContentPane:()Ljava/awt/Container;
30: aload_1
31: invokevirtual #9; //Method java/awt/Container.add:(Ljava/awt/Component;)Ljava/awt/Component;
34: pop
35: aload_0
36: invokevirtual #10; //Method pack:()V
39: return
LineNumberTable:
line 11: 0
line 12: 6
line 16: 11
line 18: 21
line 20: 26
line 22: 35
line 23: 39
public void actionPerformed(java.awt.event.ActionEvent);
LineNumberTable:
line 27: 0
line 28: 4
Code:
Stack=1, Locals=2, Args_size=2
0: aload_0
1: invokevirtual #11; //Method dispose:()V
4: return
LineNumberTable:
line 27: 0
line 28: 4
}
Searching for a Particular Code Fragment
You know the class name, and the function name, but where is it in the .class file?
One way to look for the code fragment you are interested in is by following the constant table.
For example, we will use the constant string "K500i Hello World" as a guide. This is constant #1 in the disassembled
code. The actual string itself is a null terminated ("Asciz") string at constant #23. The byte code that uses
this string is ldc #1, and we can see this quite easily in function mainframe.
But, where is ldc #1 in the .class file? First, by using the Mnemonics
table, ldc is 0x12. ldc uses one byte for the constant 1. So we can look for the
ldc #1 by searching for the byte string 0x12 0x01. This sequence is in fact quite unique
for the fact that the constant numbers in the constant table is unique. That is to say,
if another string was being loaded, for example the string "Exit", the disassembled code is ldc #5, and
the byte sequence is 0x12 0x05.
Use xvi32 to Edit the Class File
xvi32 is a hex file editor. XVI means "16", but there appears to be another pun: hex vi.
vi is a popular file editor on Unices, and numbers starting with 0x are hex numbers,
so this makes xvi a hex visual editor.
We can use xvi32 to look for the required byte sequences discussed above, and modify them
to change the behaviour of the java class file.
Pay particular attention how modified instructions affect the stack, or your modified program won't work anymore.
References
JAR File Specification
Manually Creating a Simple Web ARchive (WAR) File
javap - The Java Class File Disassembler
Freeware Hex Editor XVI32
Opcode Mnemonics by Opcode
Last updated on 1 Sep 2007
|