The Nifty Coder
New member
- Joined
- Mar 7, 2020
- Location
- I'd like to keep that to me for now.
- Posts
- 12
- Points
- 3
- Reaction score
- 11
- Quality Posts
- 1
I'm glad you found it helpful!
As for your question, that's actually really hard to answer. I might get around to making a tutorial on that in the future, but I'm working on some other projects right now so I simply don't have the time.
Applying this knowledge and creating a fully functioning bot will require intricate knowledge on how the client works, which means you will have to spend quite some time deobfuscating and analyzing the code. Luckily, people have already done this so you can just check out the source code for other bot frameworks on Github. Parabot has a pretty decent framework that is also easy to understand. Unfortunately, there is a good chance you'll have to find which variable is which in the code of your target client, which will take some time unless you're very experienced already.
I don't know where the NPC IDs are usually stored, but I'm sure there are plenty of resources online that have valuable information on that in particular. I assume you want to create a bot for educational purposes, and if that's the case, I think it would be wise to explore this yourself. Reverse engineering is a whole different field, and it can be very time-consuming to do.Could you point me in the right direction and tell me how I'd go about and try implement something very small, e.g. where are the npc id's normally stored, how do I get that id, and once I have that id, do I use a different java library that interacts with the game somehow or send a packet to the rsps server that I clicked this npc?
I don't know where the NPC IDs are usually stored, but I'm sure there are plenty of resources online that have valuable information on that in particular. I assume you want to create a bot for educational purposes, and if that's the case, I think it would be wise to explore this yourself. Reverse engineering is a whole different field, and it can be very time-consuming to do.
When you have the IDs, you have several options for how to proceed. Sending packets is definitely an option, but you can also control the client by sending events directly to the client as shown in the tutorial. If you find some NPC object, I'm sure it stores some coordinates that you can convert into screen coordinates, and then send mouse click events at that particular coordinate.
I suggest you try out a few approaches, and see where it leads.
public Graphics getGraphics() {
Graphics g = super.getGraphics();
if (!threadStarted) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
g.setColor(Color.RED);
g.drawString("Some string here!", 100, 100);
}
});
threadStarted = true;
}
// We eventually have to return the Graphics object, since that's what the RSApplet class wanted in the first place
return g;
}
public class RSAppletClassTransformer extends ClassTransformer {
@Override
public void transform(ClassNode node) {
Objects.requireNonNull(node, "Node must not be null!");
node.interfaces.add("RSAppletInterface");
MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, "getGraphicsObject", "()Ljava/awt/Graphics;", null, null);
methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
methodNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, "RSApplet", "graphics", "Ljava/awt/Graphics;"));
methodNode.instructions.add(new InsnNode(Opcodes.ARETURN));
int size = methodNode.instructions.size();
methodNode.visitMaxs(size, size);
methodNode.visitEnd();
node.methods.add(methodNode);
}
public interface RSAppletInterface {
public Graphics getGraphicsObject();
}
Exception in thread "main" java.lang.NoClassDefFoundError: RSAppletInterface
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
NoClassDefFoundError
node.interfaces.add("RSAppletInterface");
it works fine, and the RSApplet has a method called getGraphicsObjectnode.superName = "BotApplet";
returns the same errorException in thread "main" java.lang.NoClassDefFoundError: BotApplet
For improving at reverse engineering, going by trial-and-error will probably help you gain experience the most. You can look up generic tutorials on how to reverse engineer programs in Java, those tutorials might have some useful information. But you should definitely just try out different things for yourself.I will definitely look at other resources and spend some time reverse engineering and digging deep into the code, would you recommend me anything to improve my knowledge around this area.
Also from your opinion what do you think is a better approach, sending packets or controlling the client by sending events directly?
Yes, for some reason, it's missing a start method call on the thread. So, you need to call the start method on the thread instance to see the text.The variable thread isn't being used, is this needed?
Java:public Graphics getGraphics() { Graphics g = super.getGraphics(); if (!threadStarted) { Thread thread = new Thread(new Runnable() { @Override public void run() { g.setColor(Color.RED); g.drawString("Some string here!", 100, 100); } }); threadStarted = true; } // We eventually have to return the Graphics object, since that's what the RSApplet class wanted in the first place return g; }
It's incredibly difficult to debug a program remotely, but I'll try anyways.I'm getting this weird error in the following file RSAppletClassTransformer.java
Java:public class RSAppletClassTransformer extends ClassTransformer { @Override public void transform(ClassNode node) { Objects.requireNonNull(node, "Node must not be null!"); node.interfaces.add("RSAppletInterface"); MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, "getGraphicsObject", "()Ljava/awt/Graphics;", null, null); methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); methodNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, "RSApplet", "graphics", "Ljava/awt/Graphics;")); methodNode.instructions.add(new InsnNode(Opcodes.ARETURN)); int size = methodNode.instructions.size(); methodNode.visitMaxs(size, size); methodNode.visitEnd(); node.methods.add(methodNode); }
This is what my RSAppletInterface file looks like
Java:public interface RSAppletInterface { public Graphics getGraphicsObject(); }
This is the error I'm getting
Java:Exception in thread "main" java.lang.NoClassDefFoundError: RSAppletInterface at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
There's a bunch more error but I think from that the important thing you can see isNoClassDefFoundError
If I comment outnode.interfaces.add("RSAppletInterface");
it works fine, and the RSApplet has a method called getGraphicsObject
Also same problem withnode.superName = "BotApplet";
returns the same error
Exception in thread "main" java.lang.NoClassDefFoundError: BotApplet
It's incredibly difficult to debug a program remotely, but I'll try anyways.
Have you made sure you've copied everything I've done in the tutorial to a T? It's very easy to gloss over some important details sometimes.
Can I see all of the errors, and also the code of the main class that is instantiating the RSAppletClassTransformer instance please?
public static void main(String[] args) throws IOException {
JarHelper helper = new JarHelper(new JarFile("client.jar"));
ClassNode rsApplet = helper.getClasses().get("RSApplet.class");
RSAppletClassTransformer ract = new RSAppletClassTransformer();
ract.transform(rsApplet);
helper.saveJar();
reflection(); // <---- this is what launches the client
}
reflection();
* when the instance of RSAppletClassTranser is commented out *Okay, I have some questions.Yeah I have copied everything to a T (I think)
This is the main.java that calls RSAppletClassTransformer
Java:public static void main(String[] args) throws IOException { JarHelper helper = new JarHelper(new JarFile("client.jar")); ClassNode rsApplet = helper.getClasses().get("RSApplet.class"); RSAppletClassTransformer ract = new RSAppletClassTransformer(); ract.transform(rsApplet); helper.saveJar(); reflection(); // <---- this is what launches the client }
Pastebin of RSAppletClassTransformer.java -> https://pastebin.com/0TAMjszZ
Pastebin with errors from RSAppletInterface -> https://pastebin.com/YnG4rMnc
Pastebin with the errors from BotApplet -> https://pastebin.com/rZkuxXXw
Pastebin of BotApplet.java -> https://pastebin.com/qxQZ6WNP
The client loads successfully when I callreflection();
* when the instance of RSAppletClassTranser is commented out *
node.interfaces.add("path/to/RSAppletInterface");
and see if that works. Also, if they are all in the same package, try replacing the add interface statement with this: node.interfaces.add("com/abdul/RSAppletInterface");
node.interfaces.add("com/abdul/RSAppletInterface");
worked!! I decompiled the new jar and it was implemented. Just a question, where would I print the graphics from the interface public Graphics getGraphicsObject();
node.superName = "com/abdul/BotApplet";
and the rest of code beneath it meant to be in this file along with the RSAppletInterface
because I'm receiving a new error. https://pastebin.com/wgiuN4kPI apologize if the tutorial is a bit confusing. Looking back on it, I'm unsure why I structured it this way. Oh well, you live and learn I guess.You sir... is a geniusnode.interfaces.add("com/abdul/RSAppletInterface");
worked!! I decompiled the new jar and it was implemented. Just a question, where would I print the graphics from the interfacepublic Graphics getGraphicsObject();
Also if you look at my Pastebin of RSAppletClassTransformer.java I sent from the previous post, is thenode.superName = "com/abdul/BotApplet";
and the rest of code beneath it meant to be in this file along with theRSAppletInterface
because I'm receiving a new error. https://pastebin.com/wgiuN4kP
Surprisingly it wasn't confusing at all, especially considering how hard this is and there's no other tutorial out here like this!I apologize if the tutorial is a bit confusing. Looking back on it, I'm unsure why I structured it this way. Oh well, you live and learn I guess.
The part of the tutorial that shows you how to add an interface was just an example to illustrate how injecting accessor methods into a jar works. You can remove the code in the RSAppletClassTransformer that has to do with adding the interface if you want because it won't be needed later in the tutorial, as it was just an example showing how to add interfaces, and we needed a use case, so I just used the example of getting the graphics object as a way to show how to do this.
And yes, that code is supposed to be there. I understand if it was a little confusing; I confused myself just now reading through the code again, haha.
Can I see the code of the BotApplet class? And also the code of the reflection method?
min.owner = "BotApplet";
to this min.owner = "com/abdul/BotApplet";
Oh right, I didn't think of that actually! Haha. I'm glad it works, mate! The world is your oyster now!Surprisingly it wasn't confusing at all, especially considering how hard this is and there's no other tutorial out here like this!
And I managed to fix the problem by also changing thismin.owner = "BotApplet";
to thismin.owner = "com/abdul/BotApplet";
Heres the BotApplet code incase your curious to see -> https://pastebin.com/Tg20208e
And here's the reflection method code -> https://pastebin.com/PnzentYe
Sweet it now works! *not an issue but I'm setting the colour to be BLUE in the BotApplet file but it's white*
View attachment 61
Just want to say thank you sm man! the tutorial was on point and everything was explained well to a newbie like meOh right, I didn't think of that actually! Haha. I'm glad it works, mate! The world is your oyster now!
Thank you for the kind words, that means a lot to me! I'll keep making tutorials. If your friends are curious to see how RS bots work on a core level, I hope you'll refer them to this tutorial.Just want to say thank you sm man! the tutorial was on point and everything was explained well to a newbie like meand the fast replies were superrrr helpful! Definitely keep tutorials like these coming if you can, I'll definitely be on the look out. Also whats your discord @
Thank you for the kind words, that means a lot to me! I'll keep making tutorials. If your friends are curious to see how RS bots work on a core level, I hope you'll refer them to this tutorial.
My discord handle is: Shenandoah#2403. Although I must tell you, my responses on Discord might be quite slow, so if things are urgent, DM'ing me on the forums would be your best bet. ^^
Some string here!
when the client is loaded. I think it appears a for a quick mili second and then disappears. I have a print statement to check if it entered the Graphics thread and it did. Is there a reason why it does this?It should work on Windows too; I wrote the tutorial on a Windows computer. It should show the string, although some flickering will happen. Not sure how to fix the flickering exactly, but I'd look into how double buffering to get some ideas on how to fix that.Most definitely will recommend them to this! Only tutorial out there like this. Absolutely amazing man! (won't spam you, just for future reference incase this forum goes down and whatnot)
I have a weird problem, so I was coding this on my Mac laptop, and with the exact same code, I tried to run it on my windows pc (since mac can only run the client and not the source) but it doesn't show the stringSome string here!
when the client is loaded. I think it appears a for a quick mili second and then disappears. I have a print statement to check if it entered the Graphics thread and it did. Is there a reason why it does this?
It should work on Windows too; I wrote the tutorial on a Windows computer. It should show the string, although some flickering will happen. Not sure how to fix the flickering exactly, but I'd look into how double buffering to get some ideas on how to fix that.
That's really strange if it's not showing at all. Remember that the client is drawing on the screen many times per second, so when you want to draw, ideally you'd want to be the last drawing call in the game loop. If the screen keeps getting reset too quickly, you might not be able to see the text otherwise.
I'm not sure what the problem could be, but I'd assume it's a problem with the threading somehow. I noticed just now that the code for rendering the string is really bad. It creates a new thread every time you want to draw the string. I'm sure there's a much better way to do it. Maybe Windows handles threading differently or something, but that's just me grasping at straws. It should work on Windows too. Make sure everything is as in the tutorial.