Creating Custom JAR Loaders With ClassLoaders

[Note] This article is part one of a two part series on making a bot for a java game [/Note]

[Intro]

As part of being in the trial team we were given a game called Objection! which is a really old/DOS-looking kind of game with horrible graphics that allows you to hone your objection skills.  It gets really tough after a while, so I thought it would be fun to inject a dll and dump the questions and make a simple bot. If anything, it would be a good exercise in reverse engineering.

Since it comes bundled in an exe, and it looks old as hell, I assumed the game was written in C and using the WinAPI.  But after popping up IDA and looking inside the exe, I quickly realized that it was nothing more than a JNI class loader, and the game itself came bundled in a jar file called tmgames.jar.  This changes everything, instead of injecting a dll to detour functions from the process, I can build a custom loader to load the jar, and instrument the client’s code at runtime.

The first step in this whole process is taking control of the loading process of the game.  After that we can instrument it.  And so this tutorial is born.

[>>>>>]

The process breaks down in six steps:

  1. Build a classloader from the gamejar.
  2. Load the class that has the game’s main method.
  3. Get the constructor that you want to call of that class.
  4. Instantiate the class with the constructor and parameter(s) you need.
  5. Find the game’s main method.
  6. Invoke the main method.
package runtime;
 
import java.net.URLClassLoader;
import java.net.URL;
import java.lang.reflect.Method;
import java.io.*;
import java.lang.reflect.Constructor;
 
public class Main 
{
	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		URL[] url = new URL[1];
		try
		{
			url[0] = new URL("file:////C://Users//emist//workspace//tmloader//bin//runtime//tmgames.jar");
			verifyValidPath(url[0]);
		}
		catch (Exception ex)
		{
			System.out.println("URL error");
		}
		Loader l = new Loader();
		l.loadobjection(url);
 
	}
 
	public static void verifyValidPath(URL url) throws FileNotFoundException
	{
		    File filePath = new File(url.getFile());
		    if (!filePath.exists()) 
		    {
		      throw new FileNotFoundException(filePath.getPath());
		    }
	}
 
}
 
class Loader
{
	public void loadobjection(URL[] myJar)
	{
		try 
		{
			//Create a classloader.  myJar holds the full path to the game's jar file. 
			URLClassLoader child = new URLClassLoader(myJar, this.getClass().getClassLoader());
 
			//tmcore.game is the class that holds the main method in the jar
			Class<?> classToLoad = Class.forName("tmcore.game", true, child);
			if(classToLoad == null)
			{
				System.out.println("No tmcore.game");
				return;
			}
 
			//game doesn't have a default constructor, so we need to get the reference to public game(String[] args)
			Constructor ctor = classToLoad.getDeclaredConstructor(String[].class);
			if(ctor == null)
			{
				System.out.println("can't find constructor");
				return;
			}
 
			//Instantiate the class by calling the constructor
			String[] args = {"tmgames.jar"};
			Object instance = ctor.newInstance(new Object[]{args});
			if(instance == null)
			{
				System.out.println("Can't instantiate constructor");
			}
 
			//get reference to main(String[] args)
			Method method = classToLoad.getDeclaredMethod("main", String[].class);
			//call the main method
			method.invoke(instance);
		}	
		catch (Exception ex)
		{
			System.out.println(ex.getMessage());
			ex.printStackTrace();
		}
	}
}

Something to note about this code is that there are many hidden pitfalls.  For example, if you call getDeclaredMethod(“main”) you will have a methodnotfoundexception.  The reason being that you have to match the method declaration.  getDeclaredMethod(“main”, String[].class) matches main(String[] args), while getDeclaredMethod(“main”) looks for main(), which doesn’t exist.

Another thing that can trip you up is that classToLoad.getDeclaredConstructor is required if the class doesn’t have a default constructor.  If you forget to do this, you will get an exception to the effect that the class cannot be instantiated.

[Epilogue]

If you’re wondering how you find out what methods you need to call and what parameters they take, there’s many ways of going about it.  Personally, since its java I extracted the jar and ran the classes through jad.  Once decompiled its a simple process to figure out what code you need to be calling.

[End]

So now you have a class loader to load your jar.  This is the first step in making a working bot.  In the next article I will show you how this fits into a working bot.

Leave a Reply

Your email address will not be published. Required fields are marked *