Hello, and welcome to my tutorial on how to write an Injection Bot for Runescape. The other tutorials that I've seen on other forums are pretty bad in my opinion, mainly because they don't explain how crucial aspects of the bot architecture works, leaving it up to the reader to figure out exactly how and why something works in the first place. This is my attempt to explain everything in detail, from how bytecode works, how to manipulate bytecode with the ASM library, to how the classloaders can be used to make the injection work, and why it works. This tutorial will be very detailed, so if you're looking for a quick explanation, you're probably in the wrong place. This tutorial will follow a bottom-up teaching approach, meaning that I'll start talking about the core basics of what you need to know to write your own bot, and then things will get increasingly more advanced until we've got a working prototype of our very own bot. I will assume that you already know Java, or at least the basics. If you don't know Java, you might as well stop reading now unless you like reading gibberish that doesn't make any sense. Anyways, let's get started!
IMPORTANT: If you have any questions or if you need help, make a new thread describing your specific problem. I won't be able to answer questions on Discord unless they are very minor.
1. How do injection bots work?
2. Bytecode Manipulation, what is it?
3. Creating our own Runescape loader
4. Bytecode Basics
5. ASM Basics
6. Accessor methods & interfaces
7. The ClassLoader Hierarchy
8. Hijacking the canvas and drawing our own stuff
9. Creating our own mouse events and keyboard events
10. Conclusion
As you might have guessed already, the thing we are injecting into the class files is called bytecode.
However, before we can get started actually using the ASM library, we need to download the jar file(s) and add them to our project. You can start out by downloading the required jar files.
Links:
mvnrepository.com
mvnrepository.com
When you're done downloading the jar files, open up your IDE of choice and add the jar files to your external libraries folder. If you're using Eclipse, check out this tutorial on how to do it. If you're on Intellij IDEA like me, you can add the jar files to the project by doing the following:
1. Click File -> Project Structure...
2. Click Modules in the sidebar to the left.
3. Click the "Dependencies" tab.
4. Click the plus symbol right beside "Scope", and click "JARs or directories..."
5. Locate the two jar files on your system, and pick both.
Done!
Before we can get started with making our loader, we first need to actually download the client. Because I'm a bit paranoid, I'll be using a Runescape Private Server client to demonstrate bytecode injection instead of the real deal. However, the same concepts still apply for the real thing. If you want to try on the real thing, proceed at your own risk!
Click here to download the client.
You might be asking yourself: what is Reflection? Well, we can use bytecode injection and reflection to accomplish the same thing. The only difference is that bytecode injection obviously involves changing the class files, while reflection simply copies them so we can retrieve the data we want. For loading the applet into our own JFrame, reflection is sufficient. But once we start getting into things like overlaying the canvas and stuff, bytecode injection can make our job a whole lot easier. With reflection, you're limited to manipulating the attributes of class files, interfaces, and so on. Bytecode injection is a little faster too.
Are you ready? If so, start by creating a new project in your IDE of choice. Make sure you don't forget about importing the ASM jars to your project. Even though we won't be using them quite yet, it's best to just get it over with.
Alright. Before we start, let me explain just what we're going to be doing exactly. We're going to be creating our own JFrame object, and we'll be adding the applet of our target client into our JFrame object. To illustrate further, let's open up the client in jd-gui, which is a Java decompiler so we can see the Java code of the class files in the Jar file. I always like to do this first because we need a general idea of the architeccture of the program before we can start thinking about ways to manipulate it. This rings true for other programs that aren't java programs.
Okay, so we're greeted with this window.
If we look in the manifest of the JAR file, we can see that the class called "Main" is the main class. How appropriate! Let's take a look, shall we?
Interesting... As we investigate further, we quickly realize that the Game class is where everything happens. The Game class' superclass is RSApplet. Hmm, I think we're getting close. I wrote earlier about how we wanted to add the client's applet to our own JFrame object. Well, take a look at the RSApplet class code:
This class extends the Applet class. That means we can basically treat this class like an applet. This is great news! To make things easier for us, however, we're going to be mimicking the Main class. We'll be creating the Game object and configuring the Signlink class, all of this with reflection, so we can set the same values that are present in the Main class file. We're going to do almost exactly the same thing as the Main class, with one exception: the last piece of code. We want to avoid calling the createClientFrame method because this creates its own JFrame. But if you take a look in the RSApplet class (where the createClientFrame code actually resides), you can see another interesting method right beside it. The initClientFrame method which does everything the createClientFrame method does, except for actually creating the JFrame object (RSFrame). This is amazing, this is just what we need. Let's get started with the basics of Reflection, so we can start creating our loader!
IMPORTANT: If you have any questions or if you need help, make a new thread describing your specific problem. I won't be able to answer questions on Discord unless they are very minor.
Table of Contents
1. How do injection bots work?
2. Bytecode Manipulation, what is it?
3. Creating our own Runescape loader
4. Bytecode Basics
5. ASM Basics
6. Accessor methods & interfaces
7. The ClassLoader Hierarchy
8. Hijacking the canvas and drawing our own stuff
9. Creating our own mouse events and keyboard events
10. Conclusion
How do injection bots work?
I'm sure you already have some idea of what an injection is, and what it does. And, you're correct! An injection bot is a bot that automates gameplay through injecting accessor and mutator methods, along with additional logic, into various classes, and using these methods at runtime to control the behaviour of the client. Have you ever seen those puppets that are controlled by pieces of string? Well, you can think of the client as the puppet, and the injection process as you attaching your own strings to a puppet that's already being controlled by someone else. Here is what the entire injection process looks like:As you might have guessed already, the thing we are injecting into the class files is called bytecode.
Bytecode Manipulation, what is it?
The Java Virtual Machine, the platform on which Java programs are ran, does not understand Java code. The JVM only understands bytecode. Bytecode for the JVM is like assembly for the processor. Java code must at some point be compiled into bytecode, and only then can it be ran on the JVM. This is what happens when you turn a Java file into a class file. Bytecode manipulation must then be the manipulation of the bytecode in a class file. We accomplish this by either using the Instrumentation API or depending on third-party libraries like ASM, JavaAssist or any other library. For this tutorial, we'll be using the ASM library. Because it is based on the Visitor design pattern and it's quite low-level, it might have a steep learning curve for you. However, if you're already familiar with JVM bytecode and the Visitor design pattern, this will probably be much easier for you. I'll be explaining how everything works nevertheless.However, before we can get started actually using the ASM library, we need to download the jar file(s) and add them to our project. You can start out by downloading the required jar files.
Links:
Maven Repository: org.ow2.asm » asm » 7.2
Maven Repository: org.ow2.asm » asm-tree » 7.2
When you're done downloading the jar files, open up your IDE of choice and add the jar files to your external libraries folder. If you're using Eclipse, check out this tutorial on how to do it. If you're on Intellij IDEA like me, you can add the jar files to the project by doing the following:
1. Click File -> Project Structure...
2. Click Modules in the sidebar to the left.
3. Click the "Dependencies" tab.
4. Click the plus symbol right beside "Scope", and click "JARs or directories..."
5. Locate the two jar files on your system, and pick both.
Done!
Creating our own Runescape loader
I lied. I said this would be an injection bot, but in truth, it's a hybrid bot. The truth is, we're going to be using the Reflection library to actually load the client inside our own JFrame. Sorry for lying! To make it even worse, I won't be explaining the actual bytecode injection part until we're done loading the client. We absolutely need to do this before we can start changing the bytecode, since we obviously need class files to change in the first place.Before we can get started with making our loader, we first need to actually download the client. Because I'm a bit paranoid, I'll be using a Runescape Private Server client to demonstrate bytecode injection instead of the real deal. However, the same concepts still apply for the real thing. If you want to try on the real thing, proceed at your own risk!
Click here to download the client.
You might be asking yourself: what is Reflection? Well, we can use bytecode injection and reflection to accomplish the same thing. The only difference is that bytecode injection obviously involves changing the class files, while reflection simply copies them so we can retrieve the data we want. For loading the applet into our own JFrame, reflection is sufficient. But once we start getting into things like overlaying the canvas and stuff, bytecode injection can make our job a whole lot easier. With reflection, you're limited to manipulating the attributes of class files, interfaces, and so on. Bytecode injection is a little faster too.
Are you ready? If so, start by creating a new project in your IDE of choice. Make sure you don't forget about importing the ASM jars to your project. Even though we won't be using them quite yet, it's best to just get it over with.
Alright. Before we start, let me explain just what we're going to be doing exactly. We're going to be creating our own JFrame object, and we'll be adding the applet of our target client into our JFrame object. To illustrate further, let's open up the client in jd-gui, which is a Java decompiler so we can see the Java code of the class files in the Jar file. I always like to do this first because we need a general idea of the architeccture of the program before we can start thinking about ways to manipulate it. This rings true for other programs that aren't java programs.
Okay, so we're greeted with this window.
If we look in the manifest of the JAR file, we can see that the class called "Main" is the main class. How appropriate! Let's take a look, shall we?
Code:
public final class Main
{
public static void main(String[] args) {
if (args.length > 1) {
System.out.println("Running local");
ClientSettings.SERVER_IP = "127.0.0.1";
}
try {
Game game = new Game();
Game.nodeID = 10;
Game.portOff = 0;
Game.setHighMem();
Game.isMembers = true;
Signlink.storeid = 32;
Signlink.startpriv(InetAddress.getLocalHost());
game.createClientFrame(503, 765);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
Code:
public class RSApplet
extends Applet
implements Runnable, MouseListener, MouseMotionListener, KeyListener, FocusListener, WindowListener {
Last edited: