Default Skins: Default | Black | Red | Green | Brown | Lavender

Techno Skins: Black | Blue | Brown | Green | Orange | Pink | Purlple | Red | Turquoise

Light Skins: Blue | Brown | Golden | Lilac | Navy | Olive | Red | Rose | Silver | Turqouise | Violet

Other Skins: Helios Blue | Helios Green | Helios Purple | Helios Red | Blue Mousse | Camo | Chronicles | Red Fire | Rusted | Grey and Blue | Grey and Green | igOH Mimic | Vista Mimic
Supernovadelta
December 06, 2024, 06:05:35 pm
Welcome, Guest. Please login or register.

Login with username, password and session length
News:
 
  Home   Forum   Help Search Arcade Gallery Links Staff List Login Register  

Bcel Tutorial

Pages: [1]
  Print  
Author Topic: Bcel Tutorial  (Read 1383 times)
Revival Jam
Supernovadelta Vet
Community Member
Member
*****

Rep: +132/-1
SG:
Posts: 63

Supernovadelta Vet


View Profile
« on: June 13, 2008, 01:35:49 am »

This is a tutorial about the Bytecode Engineering Librarythis is a group of classes which help you view and change java bytecode.
It can read and write this bytecode in a object-oriented java sort-of-way, so normal people like us can edit bytecode in a simpler way,

You probably all want to make bots for runescape, and I bet you'll all be annoyed and angry when I go on about detectable things, or not related to runescape at all.
well listen to this, have you ever seen that film called "The Karate Kid", an old karate teacher tells his student to run around doing chores, cutting the grass, sweeping the floor, painting the fence. Eventually he gets really annoyed and asks the teacher why he makes him do that stuff.
Mr. Miyagi: "listen Daniel-san, you have learned defensive blocks while painting my fence" (not the exact dialog, but you get the idea) Moral of the story: Everything I teach you has a purpose, even if you dont see it immediately.

For this tutorial, you should know about java, and I really suggest you read up a little about bytecode, no 12-month crash course is needed, just a look around on google or something. Find out what the Constant Pool is, read up on the Stack-Machine idea and how the JVM uses it, find out what instructions are, maybe get a bytecode viewer and see what some simple classes look like in it.
It would also be good if you had a java decompiler, I recommend Jad for this since it decompiles a class as much as it can, even if there are mistakes (doesnt crash like JODE). Knowing a little bit about deobs and the rs2 client is useful, but not nesseccary.

in terms of capibilites, I like to think of bcel as a little like Reflection, but works in a differant way, and can do more things (reflection just tells the JVM what to do)
for example, java.lang.Class is mostly used as the starting point for reflection, in bcel, its equivalent is org.apache.bcel.classfile.JavaClass

so a good place to start would be with the JavaClass class, this class is an Immutable object, we'll get on to editing it later.
its in the package org.apache.bcel.classfile, this package normally has things about examining and viewing bytecode, not so much editing it.

these are the constructors
Code:
JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, int minor, int access_flags, ConstantPool constant_pool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes)
          Constructor gets all contents as arguments.
JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, int minor, int access_flags, ConstantPool constant_pool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes, byte source)
          Constructor gets all contents as arguments.

ugly arn't they? and i know you're thinking it all looks really complicated, but we're not going be using them
theres other ways of getting a JavaClass instance, the best right now would be the org.apache.bcel.Repository
this has many static methods for handling classes, the most useful one for us is
lookupClass(String class_name) JavaClass
this looks for the named class in your classpath (when you set -cp on the command line)

a useful method with JavaClass, is the dump(String) void, this creates a file and places the class in it, its normally used so when you finish, you can put the class back where you found it.

remember how org.apache.bcel.classfile was for examining bytecode? well org.apache.bcel.generic is for changing it.
the most important class in this is ClassGen, this one is not immutable, so you can mess around with it how much you want, which is of course the whole point.

it has a few constructors, but the only ones which really matters is
Code:
ClassGen(JavaClass clazz)
          Initialize with existing class.

quite simple, you have a JavaClass, you use that to make a ClassGen from it. ClassGen also has the method getJavaClass(), which you will be using once you finish.

quite a lot of bcel programs look something like this
Code:
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;
import java.io.IOException;

public class SomeBcelClass {

public static void main(String[] args) {

ClassGen myClassGen;

try {
JavaClass myClass = Repository.lookupClass("MyClass");
myClassGen = new ClassGen(myClass);
}
catch(ClassNotFoundException ex) {
ex.printStackTrace();
return;
}

//this is where you mess around with the classes

try {
myClassGen.getJavaClass().dump("MyClass.class");
}
catch(IOException ex) {
ex.printStackTrace();
}
}
}

so there's your first bcel program, doesn't do much, only loads the class, then dumps it again. If you want to edit stuff, you put your stuff on my comment there.

As there is JavaClass which is immutable, with its mutable ClassGen, there is also Method and MethodGen, and Field and FieldGen.

First off, to get the constant pool, call aClassGen.getConstantPool(), that returns an object of type ConstantPoolGen

to find our Method object, I normally just iterate through all of them, something like
Code:
Method mainMethod = null;
for(Method m : theClass.getMethods())
if(m.getName().equals("main")) {
mainMethod = m;
System.out.println("Found main Method");
break;
}

Lets say you want to change the instructions in a method, for that you'd need the MethodGen, this is its constructor
Code:
MethodGen(Method m, String class_name, ConstantPoolGen cp)
We should get our MethodGen object

Code:
ConstantPoolGen theCPool = theClassGen.getConstantPool();
MethodGen mainMethodGen = new MethodGen(mainMethod,theClassGen.getClassName(),theCPool);


SIMPLE INSERTING INSTRUCTIONS

Now we get to a good part, you know how stuff in java is broken down into instructions, they store their stuff in the stack.
In bcel, they are represented by objects of type Instruction, an abstract class, all instructions actually have their own class, there is also a InstructionHandle class, this is like a referance to an Instruction.
Well, each method has its own store of instructions, there is a special object for that, called InstructionList, its a bit like a glorified Instruction[], (really its an array of InstructionHandle)

Lets start a challange now, lets insert our own instruction in a class,
when I make something with bcel, I always try it on my own class, then try it on the real client

Code:
public class SomeClass {

public static void main(String[] args) {

String myStr = "Boo!";
System.out.println(myStr);
}
}

The task is to add my own method in there, to examine that string,
Something like this I hope

Code:
String myStr = "Boo!";
Bot.examineString(myStr);
System.out.println(myStr);

first off, lets have a look at the bytecode for the original method, im using JBE, but you can use anything that can view the bytecode, a lot of people use CFParse as well



As you can see, the ldc pushes "Boo!", stores it, gets System.out, loads the string again, and invokes PrintStream.println(),
so what we need to do is insert our own instruction to invoke our own method, it will have a single parameter, the String myStr, it will take it from the stack, so its important to give back to the stack as well, so the method also has to return a string which is placed back on the stack.

This is the class we'll use, the only reason iv placed the System.out.println there, is so I can check it works.
Code:
public class Bot {

public static String examineString(String str) {
System.out.println("called examineString("+str+")");
return str;
}
}

Remember InstructionList, these contain all the instruction in that method, we need to find the right one, then insert our own thing
To get an object of type InstructionList, call aMethodGen.getInstructionList(); we should iterate through that list and look for any sort of pattern.
The instruction I'm going to insert behind is the InvokeVirtual which calls PrintStream.println()

Code:
Instruction getFieldInstruction = null;
InstructionHandle[] iHandles = iList.getInstructionHandles();
for(int f=0;f<iHandles.length;f++) {
if(iHandles[f].getInstruction() instanceof INVOKEVIRTUAL) {
getFieldInstruction = iHandles[f].getInstruction();
System.out.println("found the invoke virtual");
break;
}
}

So now we have the instruction from the method, lets create our own instruction to insert.
We need to make an InvokeStatic, to call Bot.examineString(), bcel has a little tool for this, the InstructionFactory class, this class creates instruction for us, but it also needs access to the ClassGen and ConstantPoolGen of the instruction.

There is a class called Type, this represents a type of variable, which can be a primative type, null, array type or object type. Type itself is an abstract class, its decendants are the real stuff.

The method we'll use is createInvoke(), this asks for the name of the class which contains the method, the name of the method, the type it returns, an array of types for the parameters, and the kind of invoke.
for the kind of invoke, we look in the org.apache.bcel.Constants class, it contains many static methods, the one which intrest us the most are INVOKESTATIC, INVOKEVIRTUAL and INVOKESPECIAL, for our purpose, we shall use InvokeStatic.
the Type class already has a constant which represents String, we can just use Type.STRING,

so the next part of our code will be a little like this
Code:
InstructionFactory iFactory = new InstructionFactory(theClassGen,theCPool);
InvokeInstruction callStringExamine = iFactory.createInvoke("Bot","examineString",Type.STRING,new Type[]{Type.STRING},Constants.INVOKESTATIC);

So now we have our instruction-to-be-inserted, and the instruction we'll insert it behind. The InstructionList class has a method just for that insert(Instruction,Instruction);
so we call
iList.insert(getFieldInstruction,callStringExamine);

Next call aMethodGen.setInstructionList, to replace the list there with your modified one
Code:
mainMethodGen.setInstructionList(iList);

then there are these "clean-up" methods, I admit I dont know why they are used, but everyone else uses them, I find it hard to belive they are wasting their time, so here they are
Code:
iList.setPositions();
mainMethodGen.setMaxStack();
mainMethodGen.setMaxLocals();
mainMethodGen.removeLineNumbers();

finally, we have to replace our modified method, with the method that was already there, we use ClassGen.replaceMethod
theClassGen.replaceMethod(mainMethod,mainMethodGen.getMethod());

Now we'll compile and run, we use Jad to decompile the dumped class, and see whats happened, it now looks like this

Code:
// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) nonlb
// Source File Name:   SomeClass.java

import java.io.PrintStream;

public class SomeClass {

public SomeClass() {
}

public static void main(String arg0[]) {
String s = "Boo!";
System.out.println(Bot.examineString(s));
}
}

some people get surprised that the inserted method turns out like that, System.out.println(Bot.examineString(s)); but when you think about it, it makes total sence, the java language doesnt have a stack, the only way it would fit is if it was inside the same line.

we have total control by simply changing the method Bot.examineString(), but right now it only prints out a message to let us know it was called,
This setup has many possibilities, we could examine that string, perhaps fill our own variables, this sounds useless now because its a string, but I'v used exactly the same technique in making a hp announcer bot, except it examined an Entity instead and took its hp.
we could also change the object, here we could return some other string, the main() method would print out something totally different to what the author intended, we can use the same idea on the RS2 client.

MORE ADVANCED INSERTING INSTRUCTIONS

Now in the previous part, we took our information from things which were already on the stack, but sometimes we need more information,
for example, we want to draw something, for that we need to Graphics object, and the x and y.
heres the class we will be working on

Code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class PushClass {

private static int x;
private static int y;

public static void main(String[] args) {

BufferedImage img = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
x = 50;
y = 50;

g.setColor(Color.RED);
g.drawString("Hey guys",x,y);

System.out.println("g.color = "+g.getColor().toString()+" x = "+x+" y = "+y);
}
}

lets add this here

Code:
g.drawString("Hey guys",x,y);
Bot.drawSomething(g,x,y);
System.out.println("g.color = "+g.getColor().toString()+" x = "+x+" y = "+y);

To do this, we'll have to push the variables onto the stack,

First off, lets have a look at the bytecode of main(), specifically around that part from getGraphics() to drawString()


As you can see, the graphics object is stored in the local variable number of 2 (see the astore_2 and aload_2), the x and y are pushed with GetStatic
we need to get our InstructionFactory like before, create all the pushes, and finally put an InvokeStatic to our method

to push the graphics object, we need the instruction ALOAD, and the number where that object is stored, in this case 2.
InstructionFactory has the method createLoad(Type,int) for this purpose, to get the type, we can call Type.getType(Graphics.class)

Code:
InstructionFactory iFactory = new InstructionFactory(theClassGen,theCPool);
Instruction loadGraphics = iFactory.createLoad(Type.getType(Graphics.class),2);
Instruction pushX = iFactory.createGetStatic(theClassGen.getClassName(),"x",Type.INT);
Instruction pushY = iFactory.createGetStatic(theClassGen.getClassName(),"y",Type.INT);
Instruction callHook = iFactory.createInvoke("Bot","drawSomething",Type.VOID,new Type[]{Type.getType(Graphics.class),Type.INT,Type.INT},Constants.INVOKESTATIC);

then we can just insert them in as before,
note: getStaticOut is an instruction which gets System.out
Code:
iList.insert(getStaticOut,loadGraphics);
iList.insert(getStaticOut,pushX);
iList.insert(getStaticOut,pushY);
iList.insert(getStaticOut,callHook);

compile, run and decompile, the code looks like this
Code:
g.setColor(Color.RED);
g.drawString("Hey guys", x, y);
Bot.drawSomething(g, x, y);
System.out.println((new StringBuilder()).append("g.color = ").append(g.getColor().toString()).append(" x = ").append(x).append(" y = ").append(y).toString());

you might notice that our instruction is there on its own, we dont need to return anything, it returns void.

CAUSING A CLIENT TO CONNECT

now we can put our bcel knowledge into some (almost) useful work,
you know when starting a client through main(), it tries to connect to localhost, here is the specific line
Code:
rd.m = "127.0.0.1";

in this, we're going to try to replace it so it says this,
Code:
rd.m = Bot.getWebAddress();

lets think about this in terms of bytecode for a minuite,
there must be something which pushes "127.0.0.1" onto the stack, then something which stores it, so if you replaced the push "127.0.0.1" with our own thing, it would store what we control into the field.
the instruction which pushes strings is called ldc, in bcel, there is the LDC class,
remember how InstructionList is really a glorified InstructionHandle[], well MethodGen actually contains only instruction handles, so you can easily change what those handles contain, to replace one instruction with another, get the instruction handle, and call setInstruction(Instruction).
so we should get the InstructionHandle of the ldc, then replace it with our own method which returns a string
to find the instruction handle, we iterate through iList.getInstructionHandles() and find the LDC, but theres loads of LDCs, we should check what value is contained in them, is we type-cast the Instruction to a LDC, we can call getValue(ConstantPoolGen) to find out

the ldc insturction handle finding would look something like this
Code:
InstructionHandle ldcHandle = null;
InstructionHandle[] iHandles = iList.getInstructionHandles();
for(int f=0;f<iHandles.length;f++)
if(iHandles[f].getInstruction() instanceof LDC && ((LDC)iHandles[f].getInstruction()).getValue(theCPool).equals("127.0.0.1")) {
ldcHandle = iHandles[f];
System.out.println("Found the LDC which pushes \"127.0.0.1\" onto the stack");
break;
}

then we'll create the instruction which will be replacing it
Code:
InvokeInstruction getWebAddressCall = iFactory.createInvoke("Bot","getWebAddress",Type.STRING,Type.NO_ARGS,Constants.INVOKESTATIC);

and we replace it
Code:
ldcHandle.setInstruction(getWebAddressCall);
System.out.println("Replaced the instruction");

then compile, run and decompile, you get this
Code:
rd.m = Bot.getWebAddress();

run the client, hey prestio, it connects!

USING INTERFACES AS HOOKS IN A CLIENT

you know how in deobs, you change the names of classes when you find out what they do, so like wB or Class33_Sub2_Sub3_Sub4 becomes Entity, when you find some fields, you rename them, like hf or anInt454 becomes currentHp.
But in bcel, we dont have that luxury, because any renaming is detectable, however, there are other ways to change what a class is, by implementing an interface

if you have a class called ClassNameWhichMakesNoSence, that implements ActionListener, it is perfectly legal to do
ActionListener al = new ClassNameWhichMakesNoSence(), but the only method you can legally call is actionPerformed(ActionEvent)

the idea is, we make an interface with a name that makes sence, and some methods we can use, for example, I'm calling it entity, and a method it has is getCurrentHp()
this would be my Entity hook,
Code:
public interface Entity {

public int getCurrentHp();
}

and this is a pretend rs2 client class, with all the meaningless names

Code:
//this class is like one from the rs2 client
public class wB {

public int kg; //current hp field
}

well for our bot, we will use bcel to make the source file look something like this

Code:
public class wB implements Entity {

public int kg;

public int getCurrentHp() {
return kg;
}
}

this means it makes much more sence when writing a bot, you can just call anEntity.getCurrentHp(), instead of awB.kg, it also doesnt need to be changed with updates, you only change the actual client, not the code which uses it.
so now you hopefully understand why we add interfaces to classes, you know the why, lets look at the how.

adding your interface is quite simple, call addInterface(String) on an instance of ClassGen
we now have to add the method, for this, we'll use the MethodGen class, we use this really big long constructor

Report Spam   Logged

Share on Facebook Share on Twitter

Revival Jam
Supernovadelta Vet
Community Member
Member
*****

Rep: +132/-1
SG:
Posts: 63

Supernovadelta Vet


View Profile
« Reply #1 on: June 13, 2008, 01:36:55 am »

If there is any complaints please do not post here,Private Message me.As this will result to spamming.
Report Spam   Logged
thepure_ofswizy
First Time Poster
*

Rep: +0/-0
Posts: 4


View Profile
« Reply #2 on: January 27, 2010, 06:03:19 pm »

Holy ****! Grin Grin Grin ty Tongue
Report Spam   Logged
Pages: [1]
  Print  
 
Jump to:  

Elaborate Search Engine

Directories
Yahoo
DMOZ
Snap

Search Engines
Alta Vista
Direct Hit
Lycos
Excite

Webcrawler
Go.com
DejaNews
Google
Meta Searches
Go2Net
Search.Com
Mamma
DogPile

Enter text to find:

AquaAngular was created by deathwilldie of Ultimate Graphics
Shoutbox
[Open]


Fill your Birth-Date in in the below fields

Month Day Year Hour



This is how long you live:

Months :
Weeks :
Days :
Hours :
Minutes :
Seconds :
Milliseconds :

Your next birthday is over:

Bookmark this site! | Upgrade This Forum
SMF For Free - Create your own Forum

Powered by SMF | SMF © 2016, Simple Machines
Privacy Policy