Home
+
Products
+
Services
+
Support
 
References
 
Downloads
 
Contact Us
 
Company Profile

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