.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.
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.
javap
to Disassemble the Class File
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 }
.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.
xvi32
to Edit the Class Filexvi32
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.
Manually Creating a Simple Web ARchive (WAR) File
javap - The Java Class File Disassembler