English translation
Hey epvp,
in the following im going to show you how to locate the function which is for sending packets + what you are getting out of it.
I will use metin2 client as example, but also independently of metin2.
That means you can also use this methods to reverse other games.
I know the metin2 source is already public and with that there are much more easy ways to locate the send function in this game, but in this tutorial I dont care about that and do it the hard way reversing it my own.
This tutorial is not for people who never dealed with CE, OllyDBG, x32dbg or other debuggers before!
Requirements: ASM + C++ knowledge!
Indroduction
Microsoft windows provides librarys that makes it possible to build tcp-streams in networkapplications. The lib we are looking for is WS2_32.
If a gameclient is using multiple functions of there librarys, the gameclient imports these librarys to access it's functions.
What also comes with the lib's is the program database(.pdb)(of nearly every windows api). These files holding debuginformation about the librarys.
Based on the .pdb file we are able to easy get the start-addresses of the functions imported by the dll/lib. They are also known as "symbols".
To get to the point: We can set a breakpoint to the function that is sending packets and easy trace back from where it comes from.
To send packets over tcp games using: WS2_32.send()
MSDN says:
PHP Code:
int send(
__in SOCKET s,
__in const char *buf,
__in int len,
__in int flags
);
We don't care about the parameters SOCKET s and int flags.
The ones we are looking for are char Buffer(__in const char *buf) and the length (__in int len).
__in const char *buf & __in int len
char* buf contains, as the definition suggests, the bytes to be sent. The len indicates how much bytes needs to be read.
Knowing the buffer-pointer, we are able to eazy locate(with CheatEngine) the function that writes to the buffer.
We trace back the function until we get something useful out of it.
What else is possible?
1.) Sooner or later, every event that is triggered, caused by the player, needs to access the sendpacketfunction. That means we are able
to locate these functions too.
2.) If you leave enought time, you are able to rebuild the complete networkstream and write clientlessbots.
Difficulty:
There is nearly no game without encryption. We have to bypass the encryption or write a decrypt algorithm.
The tutorial
Structure of tutorial:
1.) locate WS2_32.send function
2.) locate packet-buffer
3.) locate the function that writes to the buffer
4.) bypass encryption
5.) send your own packets in c++
Okay, let´s reverse tha code.
Step 1: locate WS2_32.send function
First of all metin2 needs to be attached to CheatEngine. Next we have to open the MemoryViewer of CheatEngine. In the menupoint "View" your are able to
enumerate the DLL'S and Symbols. Click "Enumerate DLL'S and Symbols"
Search for WS2_32.dll in the list. If you double-click WS2_32.dll the functiontree opens.
Look for WS2_32.send and double-click it to show the function in the memview.
You have to be jumped to the function now. In my case it is 75A21F60.
Step 2: locate packet-buffer
Next we have to set a breakpoint at WS2_32.send
Hint: use VEH or kernel debugger when normal widows debugger crashes
Our breakpoint now needs to be triggerd. We can do this by using skill, items, or just moving around ingame.
I made a sign at the parameters on the picture above. There you can see the passed parameters.
Next add the bufferpointer to the Cheattable of Cheatengine by manually adding it(click the manuall add button).
Choose Array of bytes as type and a size of for example 10.
Should look like the following:
Step 3: locate the function that writes to the buffer
After adding the pointer successfully to the cheattable, leftclick it
and press F6 or rightclick it and choose "Find out what writes to this address".
Following window opens:
Now let the bp trigger by using skill, items, or just moving ingame again:
Now the hard part. We have to find out which functions writes to our buffer.
The following explains how to better imgine the topic we are dealing with.
If the client wants to send a packet, it is first stored unencrpted. Before finally sending the packet, the gameclient encrypts the packet/buffer.
Here an example code of how to imagine:
PHP Code:
byte sendBuffer[2048];
int sendBufferSize = 0;
void UseItem(byte slot)
{
UseItem ias;
ias.header = 0x123;
ias.slot = slot;
send(&ias,sizeof(ias))
}
void send(char * paketptr, int size)
{
memcpy(sendBuffer+sendBufferSize, paketptr, size);
sendBufferSize+=size;
}
running in another thread:
void finalSend()
{
encrypt(&sendBuffer,sendBufferSize);
WS2_32.send(sendBuffer, sendBufferSize);
sendBufferSize = 0;
}
The example shown above is the case of most of metin2 clients. In the client I'm reversing here there is some difference. We will see later.
Back to the last picture.
The 2 instructions shown there have identical address, which suggests that they are in the same function.
Let's click on the first entry/address.
Bild6
Jumping to the function:
Shown by picture 6, we can take out that EAX holds our wanted bufferpointer. Our job is now to find out where the eax values comes from.
For that we have to analyze the operation-codes. I already did it:
1.) in this case, 2 DWORDS get encrypted and were moved to the buffer at the end
2.) the for/while loop used to encrypt the DWORDs in esi and edi
3.) this means pieces of our packet laying in EDI and ESi register
After a while a realized that there must be one more function before, that splits the packets in DWORDs and calls the function for each 2 dwords to decrypt them.
Since we dont want to write a clientless bot, we just bypass the encryption.
Step 4: Bypass encryption
If we setup breakpoint at begin of function and let it trigger, we are able to jump to the return address and see where it get called from.
doubleclick top of stack:
In the picture above we can see a loop that splits the packet into DWORDS. So I were right with my assumption.
[esi] and [esi+4] were pushed to the stack before calling the function. That means esi points to the packetbuffer to be encrypted.
After calling the function(call 06c6500), lea esi, [esi+0x08] increases the pointer by 8 (2DWORD = 8Byte).
This is the first time we see the packet unencrypted.
Anyway, after setting breakpoint againe here, we realize 3 pointers and 1 dword in top of stack.
The function aparrently looks like this:
bool CryptPacket(char * sendBuffer(Destination), char* packetUnencrypted(src), void * unknown, DWORD sizeofpacket);
This enables the following 3 points:
1.) set an inline hook at this place and analyze the packets
2.) write packets to the buffer by your own/modify them
3.) trace back one more time the pointer that is pointing to the unencrypted packets, to get the function that handles these packets.
We will follow step 3 here.
Add address manually to cheattable again, Find out what write to this address and use items/ move ingame to trigger.
Jumping to the red signed address shown in Extra info window above, we realize that the bp triggers all the time.
It seems to be we reached a function that is used by several other functions too, to copy bytes.
We have a problem right now. We want to trace back the function call to find the send function, but it gets called by thousand of functions.
2 Options:
1.) analyze the complete function to know where the addresses come from(too much timewasting)
2.) apply a little trick to get the function:
I.) Scroll up to the begin of the function
II.) Click a point ingame that is far away, to cause the character moving
III.) while the character is moving, place a breakpoint at begin of function.
If we are looking to the stack now we may have luck and see our pointer on the stack.
Lead back to my luck I see the pointer(06C4A310) on the stack after the first try.
now I can follow the returnaddress on top of stack.
If this isn't work after first try, remove bp, let the character move again, set bp and check stack again.
The more advanced people could also setup inline hook there, check if the parameter is on the stack, and return the [esp] to get the returnaddress.
If we got the address, we can jump to it and set a bp on top of the function. To trigger we have to move ingame again or do sth else like equip items.
I will try to equip an item:
In the picture above you can see a pointer(esp+8) and a dword(esp+4).
If we jump to the pointer, we can see a array of bytes. This is our packet to equip items.
How do I know that?
I checked the buffer after each event that I performed ingame. Doing this I noticed that the first byte was always the same when performing same events.
The other bytes sometimes changed.
The first byte of the packet is also known as header. Thats how the server can assign the packets.
Jumping to the pointer in the picture above I can see the following bytes:
Why do I just show the first 4 Bytes? Because the DWORD on the stack is 4 byte, it tells how much bytes the packet is.
Analyze the packet
Now we have to find out the structure of the packet.
This first is, like I already said, the header.
0x0B seems to be the header for useitem-packet.
What about the other 3 bytes?
The item I tried to equip was stored in slot 3.
Ater I tried the same with slot4, the packet looks like:
So, the 3rd byte seems to be the cell of inventory window, starting by 0(= Slot 1).
After several trys i noticed that the 2nd byte is always 01 and the last byte is always 00.
Putting it all together:
1.) Size of our UseItem packet is 4 byte
2.) header is 0x0b
3.) 3rd byte is the slot, starting by 0
4.) 2nd and 4th byte we dont care about
Step 5: send your own packets in c++
Based on the anlaysis we can write the following code, by doing these steps:
1.) create an object 4 bytes long
2.) create function with the functionpointer and the parameter, with the pointer to our object listed above and it's size(4)
First we have to create a struct
PHP Code:
struct ItemUsePacket{
BYTE header;
BYTE unknown;
BYTE slot;
BYTE unknown2;
};
For 2nd point we need something more:
I.) Address to the sendfunction(we already got it).
II.) Static class pointer to the class that holds the sendfunction
III.) parameters
The address can be taken from last picture above(006E0250).
The static class pointer is the one we don't found yet, but I think you can do it by your own. If not, read the first tutorial.
Since the class register is ECX we can also take the non-static out of the picture.
Remember that the nonstatic ecx will not work after programrestart
The parameters are the ptr to the struct + the size of packet(4).
If we got all that, we can call the function by it's address.
If you dont understand the code, google for that
PHP Code:
typedef void(__thiscall *tSendUseItem)(DWORD thisPTR, unsigned int* pointerToStruct, unsigned int size);
tSendUseItem SendUseItem = (tSendUseItem)0x006E0250;
DWORD classPTR = 03BA0878;
void OurSendFunction(BYTE slot)
{
ItemUsePacket iup;
iup.header = 0x0B;
iup.unknown = 0x01;
iup.slot = slot;
iup.unknown2 = 0x00;
SenduseItem(classPTR ,&iup, 4);
}
Hey epvp,
in diesem Tutorial zeige ich euch, wie man die Funktion ausfindig machen kann, welche für das Senden der Pakete zuständig ist.
Das Ganze zeige ich hierbei
unabhängig vom Metin2 Client, aber am Beispiel von Metin2.
D.h. es kann ebenfalls auf andere Spiele angewendet werden.
Natürlich kann die Send Funktion bei Metin2 viel einfacher gefunden werden, da der Source public ist, aber so lernt man auch nichts, also hier the hard way
Für Leute die sich noch nie mit CE, OllyDBG, x32dbg oder sonstigen Debuggern beschäftigt haben, ist das hier leider nichts!
Ich setze Grundkenntnisse in ASM vorraus.
Vorwort/Die Theorie
Die Kommunikation von Client und Server in Online-Games wird, wie in allen Client-Server Anwendungen, über den Austausch von Paketen(in dem Fall TCP) realisiert. Die Pakete teilen dem Server/Client mit, wie er sich verhalten soll, bzw welche Funktionen ausgeführt werden sollen.
Windows stellt hierfür eine Bibliothek zur Verfügung, mit der TCP-Verbindungen aufgebaut werden können. Diese wird beim Start des Spiels mitgeladen.
Microsoft liefert außerdem die Programmdatenbank(.pdb)(von ziemlich allen API's), in welcher Debug - und Projektinformationen über die jeweilige Bibliothek
gespeichert sind. Darunter die genau Position von Funktionen, welche durch die dll/lib implementiert werden bzw. zur Verfügung stehen. Auch Symbole genannt.
Naja ich red mal nicht lang drum rum: Dies ermöglicht den Debuggern wie CE, OllyDBG, x32dbg etc. die Funktionen, die für die TCP-Verbindung zuständig sind, später im Speicher zu lokalisieren.
Die Funktion die wir suchen ist folgende: WS2_32.send()
MSDN says:
PHP Code:
int send(
__in SOCKET s,
__in const char *buf,
__in int len,
__in int flags
);
Die Parameter SOCKET s und int flags sind hierbei nicht von Bedeutung für uns.
Vielmehr jedoch der char Buffer(__in const char *buf) und die Länge(__in int len).
__in const char *buf & __in int len
Der Parameter char * buf enthält hierbei, wie man sich denken kann, den Pointer zu dem Buffer, welcher unsere Pakete beinhaltet, die gesendet werden sollen.
Die Länge gibt an wie viele Bytes aus dem Buffer geladen werden/gesendet werden sollen.
Ich komm an der Stelle mal auf den Punkt:
Durch den Bufferpointer können wir mit CheatEngine herausfinden, welche Funktionen den Buffer beschreiben/ändern.
Wenn die Stelle gefunden ist, tracet man den Funktionsverlauf so weit zurück, bis man eine Funktion gefunden hat, mit welcher man selbst Pakete senden kann,
oder diese bearbeiten kann.
Was ist noch möglich?
1.) Alle Funktionen die im Spiel eine höhere Bedeutung für Bots/Hacks haben(PickUp, Useitem...), müssen früher oder später die Pakete in den Buffer schreiben, bzw. die Sendpacket Funktion
aufrufen. D.h. wenn wir diese ausfindig machen, können wir die Hauptfunktionen ebenfalls backtracen.
2.) Wenn man genügend Zeit hat, kann man den Netzwerkstream sogar emulieren und sogenannte Clientlessbots erstellen.
Schwierigkeit:
Ihr werdet kein Spiel finden, was die Pakete nicht verschlüsselt. Wir müssen also ebenfalls herausfinden, an welcher Stelle die Pakete encoded werden.
Sonst bringt uns das Ganze rein gar nichts, da wir den Inhalt der Pakete später nicht analysieren können.
Die Umsetzung
genug Theorie, auf zur Praxis. Hier einmal die Steps in der Übersicht:
1.) Send Funktion der WS2_32 Lib ausfindig machen
2.) Paket-Buffer lokalisieren
3.) Funktion des Spiels finden, welche den Buffer beschreibt
4.) Verschlüsselung umgehen
5.) Eigene Pakete senden + C++ Source
Okay, let´s reverse tha code.
Step 1: Send Funktion der WS2_32 Lib ausfindig machen
Zuerst einmal muss das Spiel in CheatEngine attached werden. Zunächst muss der Memory Viewer geöffnet werden. Oben im Menü des Memory Viewer findet man unter dem Menüpunkt "View"-> "Enumerate DLL's and Symbols".
In der Liste befindet sich eine DLL namens WS2_32.dll. Selektiert man den Eintrag, so öffnet sich ein Funktionsbaum.
Dort sucht ihr nach WS2_32.send und klickt diese mit einem Doppelklick an.
Ihr solltet nun im Assembler-Code an den Funktionsanfang gesprungen sein. In meinem Fall 75A21F60.
Step 2: Paket-Buffer lokalisieren
Zunächst wird ein Breakpoint auf die WS2_32.send Funktion gesetzt.
Achtung: Sollte der Gameclient crashen, nutzt den VEH Debugger von CE.
Die send Funktion muss nun zum Auslösen gebracht werden. Das kann durch sämtliche Aktionen im Spiel geschehen. Sei es eine Bewegung, Skill aktivieren oder das Ausrüsten eines Items. Ist der Breakpoint ausgelöst, so sehen wir die auf den Stack gepushten Parameter(SOCKET, buffer*, len, flags).
Ich habe die Parameter in dem Bild mal makiert und beschriftet.
Der BufferPointer wird nun zur CE Cheattable hinzugefügt. Als Typ stellt ihr Array of Bytes ein, mit einer Größe von 10 z.b.
Sieht dann so aus:
Step 3: Funktion des Spiels finden, welche den Buffer beschreibt
Nachdem der Pointer zur CheatTable hinzugefügt wurde, kann man diesen makieren
und drückt F6 oder macht einen Rechtsklick und wählt "Find out what writes to this address".
Folgendes Fenster öffnet sich:
Bewegt man sich nun Ingame oder löst andere Events aus, sollte dies nun so aussehen:
Nun eine nicht sehr einfache und meistens zeitraubende Arbeit. Wir müssen herausfinden, welche Funktionen in unseren Buffer schreiben.
Dabei kann man sich folgendes Konzept vorstellen:
Wird ein Paket gesendet, so muss es vorerst unentschlüsselt irgendwo erstellt werden(Objekt), und wird dann in den Buffer geschoben.
Soll der Buffer/bzw das Paket nun verschickt werden, wird er verschlüsselt und über die WS2_32.send rausgeschickt.
Hier ein C++ Beispiel-Code wie das aussehen kann, um sich das einmal vorzustellen:
PHP Code:
byte sendBuffer[2048];
int sendBufferSize = 0;
void ItemAusrüsten(byte slot)
{
ItemAusrüstenStruct ias;
ias.header = 0x123;
ias.slot = slot;
senden(&ias,sizeof(ias))
}
void senden(char * paketptr, int size)
{
memcpy(sendBuffer+sendBufferSize, paketptr, size);
sendBufferSize+=size;
}
running in another thread:
void finalSend()
{
verschlüssel(&sendBuffer,sendBufferSize);
WS2_32.send(sendBuffer, sendBufferSize);
sendBufferSize = 0;
}
Dies ist bei Metin2 der Normalfall, bei dem Client den ich hier reverse allerdings etwas anders. Die Pakete werden sofort verschlüsselt in den Buffer gelegt, wie wir später sehen werden.
Zurück zum letzten Bild.
Die ersten 2 Instructionen oben im Screenshot liegen ziemlich nahe beieinander(von der Adressrange her).
Klickt man einer dieser Adressen an(Doppelklick), erhält man folgendes Fenster:
Bild6
Springen wir zuerst einmal zur ersten Adresse aus dem Screenshot Bild6 :
Oben im Bild6 steht, dass EAX unseren Buffer Pointer hält. Also müssen wir zuerst einmal schauen wo dieser herkommt.
Dazu schaut man sich die OP-Codes über unserer jetzigen Funktion an. Ich habe das schon getan und dabei folgendes festgestellt:
1.) In meinem Fall werden hier in einer Schleife(im Bild makiert), 2 DWORDS verschlüsselt und am Ende in den Buffer gemoved.
2.) Die Schleife holt sich dabei das zu verschlüsselnde DWORD aus dem EDI und ESI Register(Siehe Anfang while-Schleife).
3.) Dies weißt darauf hin, dass unser unentschlüsseltes Paket, bzw Stücke davon, vorher in EDI/ESI gemoved wurden.
Es muss also vorher eine Funktion existieren, die das Paket in DWORDS(4Byte Stücke) zerteilt, und dann die Funktion solange called, bis alle DWORD verschlüsselt sind.
Ich gehe hier nicht auf den Encrypt-Algorithmus ein, wir wollen hier ja kein Packet-Decrypter schreiben, sondern machen es uns einfach und suchen die Stelle, an der das ganze Paket übergeben wurde.
Step 4: Verschlüsselung umgehen
Setzen wir einen Breakpoint auf den Funktionsanfang können wir durch die Returnadresse(im Bild unten makiert) auf dem Stack zum Aufruf springen.
Doppelklick top of stack:
Dort sehen wir wieder Schleifen, meine Vermutung hat sich also bestätigt. Dort sieht man, dass [esi] und [esi+04] auf den Stack gepusht werden
(die 2 dwords die zu verschlüsseln sind) und anschließend durch lea esi,[esi+0x08](2xsizeof(DWORD)= 0x8), um genau die Größe der 2 DWORDs erhöht wird. ESI hält also den Pointer zum unencrypted Packet.
Danach wird die Verschlüsselungsfunktion gecalled.(call 006C6500)
Hier taucht also unsere Paket das erste Mal unverschlüsselt auf.
Wie auch immer, setzen wir einen BP auf den Funktionsanfang hier, realisieren wir 3 Pointer und ein DWORD.
In meinen Augen sieht die Funktion folgendermaßen aus:
bool CryptPacket(char * sendBuffer(Destination), char* packetUnencrypted(src), void * unknown, DWORD sizeofpacket);
Wir haben nun 3 Möglichkeiten:
1.) Einen InlineHook an dieser Stelle setzen, und die Pakete mitlesen und analysieren.
2.) Selbst Pakete in den buffer schieben und versuchen einen Packet-Sender zu schreiben.
3.) Schauen was die unencrypted Packets in den unencrypted Buffer schreibt und dazu einen "Find out what writes to this address" auf die Adresse setzen,
welche die unverschlüsselten bytes enthält.
Ich folge hierbei dem 3. Punkt, weil wir durch Bearbeitung der Pakete an dieser Stelle evtl andere Pakete ungewollt modifizieren könnten.
Wenn wir nun wie oben einst, die Adresse zur Cheattable hinzufügen und gucken was an diese Adresse schreibt(Find out what writes to this address), und bewegen uns Ingame, bekommen wir einen Eintrag.
Springen wir dorthin und setzen ein BP sehen wir, dass dieser sofort auslöst ohne, dass wir ein Paketsenden veranlasst haben.
Wir scheinen also in einer Funktion zu sein, welche von anderen Funktionen ebenfalls zum Kopieren von Bytes verwendet wird.
An dieser Stelle wird es schwer einen Breakpoint zu setzen und zur Calladresse zu springen, da diese von Tausenden anderen Funktionen gecallt wird.
Da es sich hierbei um eine riesige Funktion handelt, kann man, bevor man den ganzen ASM Code analysiert, vorerst einfach etwas versuchen.
Dazu scollen wir eine Weile nach oben und setzen einen Breakpoint, während unser Character läuft!
Dazu klickt man im Spiel einen weit entfernten Punkt an und setzt während er läuft schnell einen Breakpoint.
Ich habe hierbei Glück und sehe den Pointer(06C4A310), der auf das unencrypted Paket zeigt, direkt auf dem Stack nach dem 1. Versuch,
und kann ohne probleme der Returnadresse folgen:
Falls das nicht der Fall sein sollte, Breakpoint wieder rausnehmen, Character wieder laufen lassen, erneut BP setzen und wieder Stack überprüfen.
Fortgeschrittene können auch eine InlineHook setzen und die Parameter auf dem Stack nach der gesuchten Adresse durchsuchen
und dann den [ESP+0] returnen.
Setzen wir in dieser Funktion(anfang) nun einen Breakpoint, löst dieser nicht sofort aus. Soweit sogut. Wir müssen uns im Spiel nun wieder bewegen oder andere Events wie Item anziehen etc auslösen.
Ich zieh an dieser Stelle mal ein Item an und schaue wie der Stack aussieht() nach dem auslösen des BP's).
Im Bild sieht man, dass auf dem Stack ein Pointer(esp+8) und ein DWORD(esp+4) liegt.
Springt man zu dem Pointer, findet man das Paket vor, welches gesendet wird, um ein Item auszurüsten.
Woher weiß ich das?
Führt man verschiedene Aktionen Ingame aus und checkt dabei immer wieder den Pointerinhalt, merkt man, der (Pointer)Bufferinhalt ändert sich.
Das erste Byte jedoch bleibt bei gleichen Aktion ebenfalls gleich.
An dem ersten Byte, auch Header genannt, identifiziert der Server das Paket.
Springe ich zum Pointer, welcher im letzten Bild sichtbar ist, so sieht das an der Stelle folgendermaßen aus:
Warum nehm ich nur die ersten 4 Byte? Weil auf dem Stack ein DWORD übergeben wurde, welches den Wert 4 hat. Dieses gibt die Größe des Paketes an.
Analyse des Paketes:
Nun zum schwierigen Teil, wir müssen herausfinden, wofür die Bytes des Paketes stehen.
Das erste ist einfach: Wie ich oben gesagt habe ist das erste Byte immer der Header, d.h. der muss immer gleich bleiben für diese Aktion.
Da ich ein Item ausgerüstet habe, wir 0x0B der Header des "UseItem"-paketes sein.
Was ist mit den anderen 3?
Das Item was ich vorhin angezogen habe, lag auf dem Slot nr 3 im Inventar.
Versuch ich das gleich doch mal auf Slot 4. Der BP schlägt an und ich seh folgendes Paket an der Stelle des Pointers:
Das 3. Byte scheint also die Zelle im Inventar anzugeben, welche ich angeklickt habe.
Durch mehrmaligem Ausprobieren habe ich festgestellt, dass das letzte Byte immer 0 bleibt, und das 2. immer 01.
Wir fassen also zusammen:
1.) Paket für das benutzen von Items besteht aus 4 Byte.
2.) Der Header ist 0x0B
3.) Der 3 Byte ist für den Slot, wobei dieser bei 0 anfängt
4.) Byte 2 und 4 sind für uns erstmal nicht von Bedeutung.
Step 5: Eigene Pakete senden + C++ Source
Auf Basis der Analyse des Paketes oben, können wir nun programmtechnisch folgendes festhalten:
1.) Wir benötigen ein Objekt(Das Paket), was die Bytes enthält, und die Größe(beim UseItem = 4).
2.) Alles was wir dann noch machen müssen ist, den Pointer zu dem Objekt und die Größe(4) an die Funktion zu übergeben.
Für Punkt 1.) erstellen wir uns ein struct.
PHP Code:
struct ItemUsePacket{
BYTE header;
BYTE unknown;
BYTE slot;
BYTE unknown2;
};
Für Punkt 2.) benötigen wir folgendes:
I.) Die Adresse zu unserer Sendfunktion.
II.) Den statischen Pointer zur Klasse der Send Funktion.
III.) Die Parameter
Die Adresse der Funktion sehen wir oben im letzten Bild(006E0250).
Den statischen Pointer haben wir noch nicht gefunden, ich gehe aber davon aus, dass ihr das selber könnt, ansonsten mein erstes Tutorial gucken.
Das Klassenregister ist immer das ECX Register, und da ich diesen Wert ebenfalls auf dem Bild oben habe, kann man zu Testzwecken auch diesen nichtstatischen nehmen.
Achtung: Der wird nach dem Programmneustart nicht mehr funktionieren.
Die Parameter sind einmal unser oben definiertes Struct und die Größe(in unserem Fall 4).
Haben wir das alles, können wir nun die Funktion mit dem Funktionspointer definieren, und ganz einfach in unserer Entwicklungsumgebung aufrufen:
PHP Code:
typedef void(__thiscall *tSendUseItem)(DWORD thisPTR, unsigned int* pointerToStruct, unsigned int size);
tSendUseItem SendUseItem = (tSendUseItem)0x006E0250;
DWORD classPTR = 03BA0878;
void OurSendFunction(BYTE slot)
{
ItemUsePacket iup;
iup.header = 0x0B;
iup.unknown = 0x01;
iup.slot = slot;
iup.unknown2 = 0x00;
SenduseItem(classPTR ,&iup, 4);
}
Wenn ihr die OurSendFunction nun aufruft, solltet ihr das Item in dem gewünschten Slot benutzen/ausrüsten.