Sunday, December 26, 2010

Play with your byte-code using Javassist

I came to know about this nice tool named javassist which is a cool java byte code manipulation tool.It provides users with a very easy to use API to modify / create java classes in the Runtime. It provides some API to do that using a Java like syntax so that we can easily hack the byte code without knowing any thing in-depth about the byte code structure.

In this blog post I'll explain you a simple example on how to use this tool.This will show how we can use javassist to change the byte code of a compiled class to change a method implementation in Runtime.

Step 1

Step 2

Create a new directory and copy javassist.jar to that directory.

Step 3

Create Two java source file named HelloWorld.java and ByteCodeInjector.java in that directry

HelloWorld.java


public class HelloWorld {


public static void main(String[] args) {
new HelloWorld().sayHello();
}

public void sayHello(){
System.out.println("Hello!!! This is the original version!!!");
}
}


ByteCodeInjector.java



import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

import java.io.IOException;

import static javassist.ClassPool.getDefault;


public class ByteCodeInjector {

public static final String CLASS_NAME = "HelloWorld";
public static final String METHOD = "sayHello";

public static void main(String[] argos) throws Exception{
modifyByteCode(CLASS_NAME,METHOD);
}

public static void modifyByteCode(String className ,String methodName)
throws NotFoundException, CannotCompileException, IOException {
//Get the Class implementation byte code
CtClass ctClass = getDefault().get(className);

//Get the method from the Class byte code
CtMethod method= ctClass.getDeclaredMethod(methodName);

/**
* Creating the new Method implementation
*/
StringBuffer content = new StringBuffer();
content.append("{\n System.out.println(\"Hello!!! This is the Modified version!!!\");\n } ");

/**
* Inserting the content
*/
method.setBody(content.toString());
System.out.println("Replacing Method \' sayHello\' s body with new implementation : " + content);
//modify the actual class File
ctClass.writeFile();
}
}

Step 4

Compile the two java sources adding the javassist.jar to your class path
$javac -cp javassist.jar:. HelloWorld.java ByteCodeInjector.java 

Step 5

Run the HelloWorld class and see the out put
$java HelloWorld

Hello!!! This is the original version!!!

Step 6

Now Run the ByteCodeInjector class. That class will change the method implementation of the Helloworld:sayHello()

$java -cp javassist.jar:. ByteCodeInjector
Replacing Method ' sayHello' s body with new implementation : {
System.out.println("Hello!!! This is the Modified version!!!");
}

Now if you run the HelloWorld class you must see a output like
Hello!!! This is the Modified version!!!

Enjoy!!!

References
[1]http://www.csg.is.titech.ac.jp/~chiba/javassist/tutorial/tutorial.html