This brief tutorial will (hopefully) introduce you to a method of Java code injection. This tutorial is aimed at the free Java mmorpg Wurm Online. Its an mmorpg.
We will look at a simple example which will inject code into the games console, allowing us to intercept commands typed and call our own Java code.
You will need:
First. Wurm online is a JNLP app, so you run the JNLP file and it will download the client, storing its graphics and sound assets in the folder you choose.
We are not interested in these files, we are interested in to game client, which gets shoved in your Java temporary directory.
The first task is to locate the jar file containing the game client.
On windows 7, the Java client gets downloaded to somewhere in C:\Users\yourname\AppData\LocalLow\Sun\Java\Deployment\cache\
Check each of these folders until you find an file named something like 51d43a93-5922d81c that is around 1.1mb.
If you open it in your archive program of choice (it is a JAR[zip]) you will see the game client files.
You are looking for the one with wurm_banner.jpg, among other things.
Once you have found this file, have a look inside, particular the class folder. This contains the compiled, obfuscated Java class files.
Extract the bf.class file, this is the file that contains the console related code. Decompile it with Java Decompiler and disassemble it with Ida. Have a read.
We are interested in the huge if..elseif section at around line 190 in Java Decompiler.
If it’s not obvious, this peice of code checks the console input and calls appropriate functions based on what is typed.
First off, we will prove that we can modify the bytecode and have the game still run. To do this, we will remove the final else of the if..elseif to remove the message that appears when a command is not recognised.
Search for Unknown in ida pro, and you will land here:
getstatic java/lang/System.out Ljava/io/PrintStream;
ldc “Unknown command: “
This is where the game prints the “Unknown command: x” to the console.
We want to go ahead and remove this.
As with x86 machine code, Java bytecode has a NOP instruction, which is a byte that tells the virtual machine to do nothing (No Operation).
In Java bytecode, NOP is 0×00 (it is 0×90 in x86 asm).
So theoretically, if we replace the above code with lots of NOPS we will remove the console print out without breaking the rest of the program.
Lets try it.
In Ida, highlight the first getstatic line and switch to hex view, note the file offset (2892). Now highlight the final invokevirtual line and notice the offset of the last byte (28AB).
We will nop this section of code. Open up bf.class in a hex editor and replace each byte between the two offsets with 0×00. Save it, and reopen it in Ida.
If you go to the same section of code in Ida, you will now see:
Cool. Now we need to put the class back into the Jar container.
NOTE: Jar files are case sensitive, but windows is not, which causes problems.
To put bf.class back into the Jar file, use Java’s JAR command from a command prompt:
Make a directory called class in the temp directory where the Jar file resides and copy bf.class into it.
jar -uf 51d43a93-5922d81c class/bf.class
Verify that the file was replaced correctly by opening the jar file in an archive tool.
Now start the wurm client.
Open the console and type some gibberish, notice no “Unknown command” message.
Now that we know that our code changes will be used by the game, we can work on actually doing something useful.
It is important to have a basic understanding of the basic layout of a Java class file, in addition to compiled code, a class file contains a section known as the Constant Pool, which is a list of references to classes, methods, strings and other data types.
When the bytecode in a class calls a method in Java, it uses a reference to the method in the Constant Pool.
For example, we have a class Foo, with a method bar:
public class Foo
public static void bar()
To call this method, the constant pool needs 6 entries:
a utf8_info string “bar” – the method name;
a utf8_info string “()V” – the type info for the method (this one is no arguments, and void return type)
a NameAndType_info linking the above name and type
a utf8_info string “Foo” – the name of the class
a class_info linking to the above name
a methodref_info linking the class_info and NameAndType_info – Foo/bar()V
The methodref_info can now be used to call the method, in the above example using invokestatic. The bytecode for invokestatic is b8 followed by the two byte index of the methodref index in the constant pool.
To call this example method from our example code, we need to create the Constant Pool entries in bf.class. The easiest way to do this is with the Java Bytecode Editor app.
Open bf.class in the Java Bytecode Editor and add a methodref, this will create the other entries in the Constant Pool Table. Note the number of the methodref we added, we will need it later.
Now we have the constant pool entries added, we can change some of the nops to call the method in our example Foo class.
Go to the nops, and replace the first with B8 (this is invokestatic), then replace the next two bytes with the methodref index in HEX, mine was 02 E7. Save.
Open bf.class in Ida again, the old area of nops should now look like this:
Replace the bf.class in the jar with the modified one.
Now compile the Foo.java, and add the Foo.class to the JAR:
jar -uf 51d43a93-5922d81c Foo.class
Make sure the class files are in the correct place.
Now run Wurm, open the console and type some gibberish.
Wurm replies with “Hello Wurm” in the console.
Now, we could go on to add an argument to Foo.bar and pass the console command string in (shouldn’t be too hard).
The good thing about this approach, is that once you have your methods being called, you can code straight into Java anything that you want the game to execute, with a bit of investigation, it should be possible to do a lot with it.
Hope this was helpful.