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

4 comments:

Nuwan Armabage said...

yeah... thanks very much.clear steps makes the article more interesting.

MDale said...

Thanks so much for taking the time to write this tutorial. It was very helpful for a noob trying to navigate Javassist!

Batoul Hocine said...

Hello thank's for this tutorial

is it possible withe javassist to inject anything before calling a specific method and delete this adding also like this
m.insertBefore("method1()");
how i can delete it in other times?

Charith Wickramarachchi said...

You might have to check it with the javaassist user community. See https://community.jboss.org/en/javassist?view=discussions