Obtaining the source code of GetAmped
Any online game, at some point, will go offline. Most commonly due to a decline in player base. When these games go offline, the developers tend not to publish any server binaries or source code.
We’re talking about a 3D fighting game called GetAmped (or FogsFighters / SplashFighters). It was in development since 2002 by Cyberstep, a Japanese company. The game is popular in the Asian market, which lead up to a couple of releases in the west.
The Dutch release of this game was shut down in 2013, then got a couple of releases in different countries, but now only exists in Asia.
I was able to obtain the source code of said game, 10 years after shutdown. If you have some technical knowledge, you should be able to perform the steps mentioned in this post yourself.
Want to download the game yourself? Try the Internet Archive.
Observing the client files
These are the available client files after installing the game:
We can make some assumptions:
- The
jre
folder indicates that there’s some involvement of Java (Java Runtime Environment). - The
amped.exe
andamped_launcher.exe
indicate that not all binaries are Java. - The
amped.exe
binary is only ~200 KB in size, which is very small for a game like this. - The
keel
related files might hint towards the game’s engine. - After opening the
keel.dat
,amped.kar
andresources.kar
files, it’s clear that these are encrypted.
The game has 2 executables: amped.exe
and amped_launcher.exe
.
The launcher was the intended way of booting up the game, it opens up an interface that originally was used to update the game. The server has been long gone, so any connection attempts fail.
Luckily for us, the game boots up just fine when running amped.exe
directly.
Analyzing amped.exe
I always start with checking if there are any interesting strings present in the binary. Usually strings will give away a lot of information on what the binary does.
Windows comes with a handy strings
command that extracts strings from a binary.
After a quick search, the string "JNI_CreateJavaVM"
indicates that it’s using the Java Native Interface (JNI) to
create
the JVM.
The JNI is a library you can use in C to manage a JVM and interact with it.
At this point, I’ve opened up my disassembler to see what’s going on.
We can locate one of the xrefs to the "JNI_CreateJavaVM"
string and see where it’s called.
Although this only gets the address to "JNI_CreateJavaVM"
function, after analyzing the sub_421a30
function we
actually
start seeing some JNI calls in action:
Oracle has some documentation
about The Invocation API which covers
the call to JNI_CreateJavaVM
.
JNI_CreateJavaVM
has the following signature:
So from the above assembly, we know var_150
holds a pointer to a JavaVM
struct and var_164
holds a pointer to a JNIEnv
struct.
After renaming these variables, we can find them easier in the disassembly.
Not much further down, the "java/lang/ClassLoader"
string is referenced.
After reading some more JNI documentation, it becomes clear that this is a call to the FindClass
function.
Any Java installation comes with header files for the JNI. If we’d import these, we’d get rid of those pesky “random” offsets.
I’m using Binary Ninja, so I can very easily retype JNIEnv*
to its actual type, and the assembly will make a lot more sense:
Finding the compiled Java classes
The JNI is able to load compiled Java classes during runtime.
There’s a function called DefineClass
that takes in a class loader
and a buffer containing raw bytes representing the compiled Java class.
Looking at the xrefs to DefineClass
, we can see 10 calls to this function.
The xref takes us to a function where some data is being pushed onto the stack. 1 byte at a time…
It does this approximately 17,000 times. These bytes often don’t even represent characters, so it’s likely encrypted.
Reverse engineering the decryption algorithm is one option,
but why bother when we can simply put an old-fashioned breakpoint on the DefineClass
call?
The DefineClass
function should still be called with valid bytes that represent a Java class after all,
so the data must be decrypted before that.
Take this call for example:
and the DefineClass
signature:
Binary Ninja already renamed some variables for us according to the header files of the JNI,
so we know that the class name is stored in name_5
, and the class data in buf_5
.
There aren’t any anti-debugging techniques in place, so we can run the binary and wait until the breakpoint is hit.
After that, we can dump the decrypted class data from buf_5
.
I’ve gone ahead and did this to all classes, and it gave me the following files:
In Java, inner classes will result in a separate .class file. The hierarchy is denoted with a $, e.g.:
Decompiling the classes
Java .class files contain bytecode, which can be easily decompiled using the FernFlower decompiler. The community edition of IntelliJ IDEA comes with this decompiler built-in. All we simply need to do is store all these .class files in a single folder and open it in IntelliJ:
It’s obvious that this is not the source code of the game, but from now on its easy game as the assembly is not needed much longer.
Decrypting the keel.dat file
The implementation of KarSource
contains a constructor that takes in 2 arguments:
After reading the source code, I’m renaming the arguments to:
There’s not much of the assembly left to reverse, but 2 strings are being referenced:
and
isn’t that suspicious?
We can include these compiled Java classes into our own Java program and use the KarSource
class ourselves,
and plug in these 2 strings:
and… it works! The keel.dat
file is decrypted and the contents is all ours. The KarSource
implementation exposes
a simple API to extract the contents, so I’ve just done that.
It appears that keel.dat
contains encrypted byte code of the game’s engine. The file contained 707 classes in total.
But what about the amped.kar
and resources.kar
files? We still need to find the decryption keys for those.
Decrypting the amped.kar file
The “Keel” engine expects an "-entrypath"
argument to be passed, at least that’s what their source is hinting towards:
and it so happened that the -entrypath
is set to "kar:program_getamped:kar"
.
but… the password is nowhere to be found and from the KarSource
implementation, we know that a password is required.
After looking through the Keel source code, I’ve stumbled across this snippet:
See that var3
being passed as the 2nd argument to KarSource
? That’s the password, and we need it.
After analyzing the source code, it seems that the password is simply "program_getamped"
.
That’s it.
Remember that old KarSource
implementation we used to decrypt the keel.dat
file?
I tried using it on amped.kar
, but it didn’t work. It seemed to be able to extract the class names, but not the contents.
It appears that a newer version of the KarSource
implementation is present in the keel.dat
file.
So… here we go again:
and that’s it!
After dumping the contents of amped.kar
, the game’s source code has been restored.
There are over 7000 classes to be found in this one file.
Decrypting the rest of the kar files
Sorry folks, this one is rather anti-climatic. All the other passwords were super easy to find in the source code.
Go crazy!
Conclusion
Having the source code allows reverse engineers to learn how the game was built. It allows us to easily create our own server emulator from scratch, which is easier with source code than reading assembly.
This game offers a lot of content, albeit by pay-walling most of the weapons and classes, there were hundreds of them.
After looking through resources.kar
, I’m quite blown away by how much scripting work went into this game.
If you feel like picking up on this project, please reach out to me. I’d love to keep an eye on it!
Fun fact: The code contains server related files that definitely shouldn’t be on the client-side.