English translation:
Introduction
In the following tutorial I am going to show how to reverse functions in metin2(the example of SG). So, first of all what are we getting out of it ? This is very simple: you can create a Bot/Hack with it.
First I will explain the fundamental basics, be sure you understand these!
Furthermore it would be an advantage if you ever dealed with Cheat Engine and programming before.
1.) Setting up environment
First of all you need the following programms:
Needed programs:
CheatEngine
Visual Studio 2015
Metin2Client
Small hint:
Go to settings in CheatEngine and set the Radiobutton VEH Debugger.
2.) Basics
Few lines before I told you we start with the basics of reversing and this is it. I will only exlain the terms stack, register and the "asm commands".
I hope it supports newcomer to getting started a little easier with reversing.
I.) Der Stack
The stack is a memory area inside the running process, that is (most) needed for temporary operations to store values or adresses. These operations for example can be function calls or simple arithmetic operations in a function(I will explain more later).
Basically it´s a data structure where you can hold some data. There are 2 main operations called pop and push. With command "push" you put data on top of the stack, and with pop you can get the element on the top.
The structure is also known as last-in-first-out.
II.) Die Register
III.)Commands(most important commands only)
call address
The call command is used for function calls in assembler. Mostly the call is followed by an address(Rarely by registers(EAX EDX..)). On the example of the following piece of code
I will explain what exactly happens, when a call instruction runs.
PHP Code:
Beispiel:
0x0034BA00 - call 0x0045DBAC
0x0034BA04 - anderer Code...
So, when the process reaches the line "call 0x0045DBAC" the first thing that happens is, that the returnaddress will be pushed on the stack! This is because the process needs to know where to jump back when the function is finally executed.
In our case the returnadress is 0x0034BA04. After pushing the address on top of stack the process jumps to the address 0x0045DBAC, executes the code inside the function, and jumps back to the returnadress that was pushed on the stack before.
mov dst, src
mov stands for "move" and is just moving data/bytes(often addresses and values) from source to destination.
There are basically 2 cases:
mov EAX, [adresse] <- the "[]" says "okay, the value located at this address you have to move to EAX pls"
Let me show you an example:
Within the memory of our process there is an address "0x00AB5690" which holds the value 00000001
If the following code gets executed:
PHP Code:
mov EAX, [0x00AB5690]
EAX should be 00000001 now.
If we remove the brackets "[]"
PHP Code:
mov EAX, 0x00AB5690
EAX holds the value 00AB5690 now.
ret
ret means return and is often located at the end of a function. In the previous I already told you, that the returnadress is pushed on the stack before calling a function.
So, when the ret command of the called function is reached, the ret command pops the return address from the stack and we jump back the main procedure.
Sometimes you will see combination like this:
ret 0x08
This is because sometimes the end of a function is reached, but the returnaddress is not on top of stack. If the address would be poped now an unexpected error occur.
The hexadecimal value after the ret command now increases(by 0x08) the pointer(ESP) so that it points to the top of stack.
3.) Find and analyse functions in memory
In this step I will present 3 possibilities to locate functions in the memory.
Option 1: Tool Ultimap
CheatEngine envolves a tool called Ultimap. With Ultimap you are able to count intended functions you are looking for by calling it again and again.
This method is very slow and needs the DBVM-function activated(for more use google, I will not use this method here)
Option 2: Looking for referenced strings
In CheatEngine we are able to search for strings in the assembler code. Often developer defining functions that print errormessages or something else in their source to get better error analysis and this is
where we take advantage of. While the metin2 sourcecode was released few years ago it is very simple to find functions, because we know the strings, and where they are placed.
I will use this method in the next step to show you how to find them.
Option 3: Value scan
I think everyone who ever dealed with CheatEngine before should know what you can do with valuescan. Primary it is used to get the static location of values like health or ammo
and to get the function that accesses these values(for example the decrease function when you shooting around with your weapon).
There are sure much more possibilites to find functions..
[How To]Reverse functions(SendItemUse)
While there are many examples of "PickUp"-Hacks and so on I will show you how to reverse the SendItemUsepacket function. With this function we are able to automatic use/equip items.
The client and server communicate with pakets sent over the internet, and the SendItemUsePacket tells the server which item we want to use. In sourcecode it looks like:
In the picture we can see some strings.
PHP Code:
BINARY_AppendNotifyMessage
CANNOT_EQUIP_EXCHANGE
BINARY_AppendNotifyMessage
CANNOT_EQUIP_SHOP
SendItemUsePacket Error
We use this strings to locate the function in the metin2 process as I explained in option 2 previously.
But before we start make sure you followed these steps:
1.) Start Metin2 and CheatEngine
2.) Attach the Metin2Process to CheatEngine and click MemoryViewer
3.) Go to Tools in the menubar of the MemoryViewer -> Dissect Code( or Shift+J) and press Start, wait until the searchprocess its finished
4.) Now click View->Referenced Strings(or Shift ALT J) in the menubar
Now press SHIFT+F to search for the string we are looking for: "SendItemUsePacket Error"
You could also search for other strings pictured below.
5.) if you mark the result, you will see an address in the right column, double click it to get to the memory location
Now the main-part.
Find the function
The place we were jumped after clicking the address shows this:
PHP Code:
"push 012C50AC" Comment: SendItemUsePacket Error
(Your address will be another address for sure! thats normal)
012C50AC is an address in memory of our process, where a string is located. To get a better understanding you can search for the address in hexview(rightclick in hexview and "Go to Address" to jump to the address)
Back to the push comment.
So the code pushes the address on the stack.
If we set a breakpoint(rightclick the line (push 012C50AC) and "toggle breakpoint") and use an item in metin2(for example a sword) the process will not trigger.
But why? This is because the string will only be pushed if an error occures. While it was succesfull the game is not freezed yet.
We need to set a breakpoint on the line below:
If you use an item again, the game should be freezed yet. It seems to be this is our function.
Taking a look at the sourcecode(first picture) we note that the function needs a parameter. The itemposition.
The struct of TItemPos is the following:
PHP Code:
struct TItemPos{
BYTE window_type;
WORD cell;
};
So what does that mean? It means to use the SendItemUsePacket function we must explicit tell which item we want to use. Makes sense hm.?
But before we can continue you need to know how the parametertransfer to a function works:
Before calling the function, the parameter must be pushed on the stack. To know what exactly needs to be pushed on stack we can set a breakpoint at the begin of the function.
In my case this is 0099A740.
If we use an item now the game should freeze again and we are able to see the registers. But we care for the stack atm. The stack is placed on the bottom right.
To get a better view of the stack rightclick and use "FullStack"-Option.
Should now look like this:
Explaination Stackview
What you see there is the actual stack or the place where the stackpointer(ESP Register) points to atm.
The first column is an address in the stacksegment, the second columns shows the value that is located at the address. This value can be a pointer, datastructure
or a 1-4 byte value.
Thats it for the stackview.
In our case the first value is an address. Its the returnaddress which points back to the main procedure.(This is where we jump back after function call)
(So to find out from where the SenditemUsepacket is called we could go to this address)
Small hint: The item I equiped in this tutorial was placed in first invetory on the top left(first slot)
The second row in the picture shows that a value has been pushed to the stack.
Pretty interesting.
If I run the game again and position the item in 2nd slot the pushed value is now 00000101 and not 00000001.
If I put it in slot 2 and use it, it will be 00000201 and so on.. blabla
It seems the last byte is always 01 and the second last is the slot starting with 0(0x00 = 1st Slot, 0x01 = 2nd Slot.....)
In the previous I showed you the structure of the parameter needed by the function.
window_type of type BYTE and cell of type WORD. Word has 2 bytes.
That´s nearly it. You need to push 2 bytes on the stack before calling the SenduseItempacket
If you want to equip slot 10 automatically for example, the value is:
PHP Code:
0x00000A01. (A is hexadecimal for 10)
Up to here our code looks like this:
PHP Code:
push 00000A01
call 0099A740
But that isn´t it at all.
We need to find the static class pointer.
Classpointer
The function SenditemusePacket is located in a class. The CPythonNetworkStream class as seen below. So what we need is the pointer that points to the class.
Before the function is called, the classpointer is moving in the ECX register! This is always the case!
Our job is now finally to find the classpointer.
To get the static pointer, we have to find out where our function is called and get the value that is moved into the ECX register.
First we set a breakpoint at the beginning of the function. Use an item and game should be freezed again. Now we are interested in the ECX register. In my case its 06CA9ED0.
Next you have to go in front of the function call. You can do this by double click on top of stack(after breakpoint triggered that is set at the beginning of the function).
It should now look like this:
After setting a breakpoint at 0098C49B I noticed that the EAX holds the value I am looking for.
The code after this call is only moving the eax value to the ecx register, so it seems to be I got the function that returns the classpointer.
Lets have a look into the function(Right click -> Follow).
That looks awesome!
We can see that a static address (01482190) is used in this function code. And thats our static pointer to the classpointer.
Vorwort
Im Folgenden geht es darum, am Beispiel von Metin2 Funktionen im Speicher zu reversen(ich zeige das am Beispiel von SG). Was bringt einem das? Nunja, man kann damit zum Beispiel Bots/Hacks programmieren.
Eingeleitet wird das ganze durch ein paar Basics, welchen man sich bewusst sein sollte, bevor man sich Assemblercode anschaut.
Ich setze hier einige Dinge vorraus. Ums kurz zu halten sollte man schon einmal irgendetwas programmiert haben und sich evtl mit CheatEngine auseinander gesetzte haben. Ist natürlich aber nicht zwingend notwendig. Verbesserungsvorschläge oder Ergänzungen, welche zu einem besseren Verständnis verhelfen, sind gerne gesehen. Ich werde als Beispiel die SendUseItemPacketFunktion nehmen. Wenn mehr gewünscht ist werde ich mit anderen Funktionen weitere Beispiele bringen.(z.B. NetzwerkStream Reader für den Client mit inline Hooking etc..)
1.) Umgebung einrichten
Zuerst einmal müssen wir die nötigen Programme herunterladen und diese konfigurieren.
Benötigte Programme:
CheatEngine
Visual Studio 2015
Irgendein Metin2Client
Zu CheatEngine:
Um Abstürze des Spiels zu vermeiden, hat es sich bei mir bewährt den VEH Debugger zu aktivieren.
2.) Basics
Bevor es losgeht werden hier noch einmal die "Basics" erläutert. Dabei wird auf die Begriffe Stack, Register und Befehle näher eingegangen. Dies trägt zum Verständnis des Assembler-Codes und der Arbeitsweise der CPU/RAM bei. Falls mehr Erklärung gewünscht ist bitte melden.
I.) Der Stack
Der Stack ist ein Speicherbereich im Prozessbereich selbst. Er ist ein Stapelspeicher auf dem Variablen und Adressen während Funktionsaufrufen oder Operationen gespeichert werden. Der Stack arbeitet nach dem LIFO-Prinzip(Last in first out). Man kann sich den Stack also wie ein Stapel von Daten vorstellen. Möchte man Daten auf den Stack legen, spricht man von "auf den Stack pushen". Wird etwas vom Stapel oben runtergenommen spricht man von "pop".
II.) Die Register
III.) Befehle(wichtigsten)
call address
call ruft, wie man schon vermuten kann, eine Funktion auf(bzw springt zu einer Funktionsadresse im Code und arbeitet diese ab). Hinter call steht meist eine Adresse, selten auch Register, welche Adressen beinhalten.
Was passiert nun bei einem call genau?
PHP Code:
Beispiel:
0x0034BA00 - call 0x0045DBAC
0x0034BA04 - anderer Code...
Bevor mit dem call an die Adresse(0x0045DBAC) gesprungen wird, wird die Adresse 0x0034BA04 auf den Stack gepusht. Dies ist die Rücksprungadresse, auf die nach dem Funktionsaufruf zurückgesprungen wird. Danach wird der Funktionscode an 0x0045DBAC ausgeführt.
mov dst, src
mov steht für move und bewegt Daten/Bytes von src(Source) nach dst(Ziel)
Dies kann folgendermaßen auftreten:
mov EAX, [adresse] <- die "[]" bedeuten es wird der Wert, der an der Adresse "adresse" steht, in EAX geschoben
Beispiel:
Im Speicher gibt es die Adresse 0x00AB5690 und diese hält die Value 00000001
Dann ist EAX nach folgendem Code:
PHP Code:
mov EAX, [0x00AB5690]
EAX = 00000001
Werden die Klammern weggelassen
PHP Code:
mov EAX, 0x00AB5690
so hält das EAX Register nun die Adresse des Wertes, EAX = 00AB5690.
ret
ret oder auch return steht meist am Ende einer Funktion(im Assemblercode) und bewirkt einen Rücksprung auf die Adresse nach dem call(In unserem Beispiel oben auf 0034BA04)
Oftmals tritt dies auch in Kombination mit einem Hex Wert auf.
Beispiel:
ret 0x8
Damit wird bewirkt, dass der Stackpointer(ESP) nun zusätzlich um 8 erhöht wird. Das wird gemacht, um Daten auf dem Stack automatisch zu löschen(bzw. zum Überschreiben freizugeben)
3.) Hauptteil/Funktionen im Speicher finden und analysieren
Wird ein Programmcode(z.B. c++, c#..) kompiliert, macht der Compiler grob gesagt nichts anderes, als den Code in Assemblercode zu wandeln.
(In Wirklichkeit ist das natürlich ein wenig anders, aber tut hier nichts zur Sache)
Führt man das kompilierte Programm aus, kann man sich in einem Disassembler bzw. MemoryViewer den Assemblercode anschauen. Je nach Ziel
ist die Aufgabe beim Reverse Engeenering die Funktionen im Speicher zu finden, da wir sie später unabhängig vom eigentlichen Programmablauf selbstständig aufrufen wollen.
Naja, wie findet man diese in dem ganzen Assemblercode nun..?
Möglichkeit 1: Tool Ultimap
CheatEngine bringt das Tool Ultimap mit sich. Damit ist es möglich die Funktionsaufrufe einer bestimmten Funktion in einem bestimmten Zeitraum aufzunehmen und sich diese anzeigen zu lassen.
Das wird solange wiederholt bis die gewünschte Funktion übrig bleibt(ähnlich wie beim Scannen nach Values etc..). Diese Methode fordert allerdings die DBVM-Funktion zu aktivieren, führt oftmals zu unerwünschten Bluescreens und ist zudem langsam und damit aufwendig.
Möglichkeit 2: Strings suchen
Die andere Methode wäre die Suche nach Strings innerhalb des Assembler-Codes, welche auf unsere gesuchte Funktion hinweist. Da der Sourcecode von Metin2 schon länger bekannt ist, können wir diese Methode nutzen, um sehr leicht zum Ziel zu gelangen. Dies wird auch später in den Beispielen Verwendung finden.
Möglichkeit 3: Value scan
Hierbei versucht man über bestimmte Werte die sich im Spiel ändern, wie beispielsweise die Anzahl der Items, die Funktion zu finden.
Diese Methode kann allerdings sehr aufwändig sein, da die Funktion fürs Inkrementieren oder Dekrementieren von Items nicht unbedingt in der Nähe
der gesuchten Funktion liegen muss.
Es gibt hierbei natürlich viel mehr Arten und Weisen eine Funktion zu finden. Das würde aber den Rahmen etwas sprengen.
[How To]Eine Funktion reversen(SendItemUse)
Da es bereits Tutorials über PickUp oder ähnliche Funktionen gibt, dachte ich mir ich nehme die SendItemUsePacket, welche es möglich macht, Items automatisch auszurüsten bzw. zu benutzen.
Der Client kommuniziert mit dem Server über Pakete und die SendItemUsePaket teilt dem Server mit, welches Item benutzt werden soll. Diese sieht im Sourcecode folgendermaßen aus:
In dem Bild/Source sind nun Zeichenketten/Strings zu sehen.
Diese wären:
PHP Code:
BINARY_AppendNotifyMessage
CANNOT_EQUIP_EXCHANGE
BINARY_AppendNotifyMessage
CANNOT_EQUIP_SHOP
SendItemUsePacket Error
Nach diesen Strings können wir den Speicher des Prozesses nun untersuchen.
Zuerst einmal müssen jedoch folgende Schritte durchgeführt werden:
1.) Starte Metin2 und CheatEngine
2.) MemoryViewer in CheatEngine anklicken
3.) Tools -> Dissect Code( oder STRG+J) und Start drücken, um nach Strings zu suchen
4.) Wenn die Stringsuche fertig ist, in der Menüleiste auf View->Referenced Strings( oder STRG-ALT+R) und dann mit STRG+F nach String suchen: "SendItemUsePacket Error"
Man könnte auch nach den anderen oben genannten Strings suchen und würde im Endeffekt auch auf die selbe Lösung kommen.
5.) Klickt man auf den String erscheint rechts eine Adresse. Diese mit Doppelklick anklicken.
Nun zum eigentlichen Part.
Die Funktion finden
Die Stelle an welche wir nun gesprungen sind zeigt:
PHP Code:
"push 012C50AC" Comment: SendItemUsePacket Error
(Natürlich wird die Adresse sehr wahrscheinlich anders bei euch aussehen!)
012C50AC ist eine Adresse im Speicher, an der ein String liegt. Um zu sehen, ob dies auch wirklich stimmt, kann man unten im MemoryViewer bei der Hexansicht einen Rechtsklick machen und mit "Got to Adress" zu dieser Adresse springen.
Es wird also die Adresse, an der die Errormeldung steht, auf den Stack gepusht.
Legen wir nun einen Breakpoint(Um einen Breakpoint zu setzen Rechtsklick auf die Zeile und Toggle Breakpoint auswählen) auf diese Zeile des push Befehls und benutzen ein Item in Metin2, werden wir feststellen, dass dieser nicht auslöst. Warum? Ganz einfach: Weil das Senden des Paketes erfolgreich war und dieser Codeabschnitt deswegen übersprungen wurde.Um ihn auszulösen müssen wir den Breakpoint auf die Zeile dadrüber legen:
Das Spiel ist nun eingefrohren und wir haben die Möglichkeit Schritt für Schritt durch den Code zu steppen(F8), um zu sehen wie sich die Funktion verhält und was für Werte auf dem Stack liegen, bzw in den Registern. Das ist an dieser Stelle jedoch erstmal nicht von Relevanz. Um das Spiel weiterlaufen zu lassen muss F9 gedrückt werden.
Wir haben also die Funktion fürs Erste gefunden.
Wie im Sourcecode zu sehen ist(Bild1), benötigt die Funktion einen Parameter. Und zwar die Position des Items.
Die Datenstruktur des Typs TItemPos sieht wie folgt aus:
PHP Code:
struct TItemPos{
BYTE window_type;
WORD cell;
};
Um die Funktion also benutzen zu können, müssen wir vorher auch angeben, welches Item/bzw Zelle wir benutzen möchten. Dazu muss man wissen wie die Parameterübergabe geschieht:
Bevor eine Funktion aufgerufen wird, werden die Parameter die an die Funktion übergeben werden sollen, auf den Stack gepusht. Wie kriegen wir nun raus, was wir später auf den Stack pushen müssen, um die Funktion zu benutzen? Wir setzen zunächst einen Breakpoint auf den Anfang der Funktion. Diese beginnt in diesem Beispiel bei 0099A740.
Rüsten wir uns nun mit einem Item aus, so freezt das Spiel wieder und wir sehen die Registerwerte. Uns interessiert hierbei nun aber der Stack. Dieser befindet sich im MemoryViewer unten rechts. Um diesen übersichtlicher darzustellen kann man per Rechtsklick in dem Stackfeld "Full Stack" auswählen.
Das sollte nun folgendermaßen aussehen:
Erklärung zum Stackview
Was ihr dort seht ist nun der aktuelle Stack, bzw die Stelle an dem der Stackpointer(ESP Register) momentan steht.
Address(Spalte 1) ist die Addresse, an der ein Wert(Spalte 2) steht. Dieser Wert kann nun ein Pointer auf eine Datenstruktur sein, oder ein 1-4 Byte Wert.
Ende Erklärung Stackv
Der erste Wert ist eine Addresse, und zwar nicht irgendeine Addresse sondern die Returnadresse, welche uns nach dem Durchlauf der Funktion wieder zum eigentlichen Programmablauf bringt.
(Um zu sehen von wo aus diese Funktion also gecalled wird, könnten wir dort hinspringen und evtl weitere interessante Dinge herrausfinden.)
Vorerst noch: Das Item welches ich angezogen habe liegt im Inventar I oben links.
Schauen wir 4Bytes weiter, also die nächste Zeile, sehen wir, dass dort der ein Wert gepusht wurde(Siehe Bild oben).
Das sieht doch schonmal interessant aus.
Gucken wir was passiert, wenn ich das Item in den 2. Platz von links im Inventar platziere, und den Breakpoint erneut auslösen.
Der gepushte Wert, der eben bei 00000001 lag, liegt nun bei 00000101. Lege ich das Item daneben und ziehe es an wird es 00000201 sein, lege ich es in den 5. Slot und benutze es, wird es 00000401 sein... und so weiter. Ihr könnt ja ein wenig testen.
Auffällig ist auf jeden Fall, dass das Byte 01 am Ende immer gleich zu sein scheint und das andere Byte(bzw WORD) die Zelle im Inventar angibt, wobei bei 0 angefangen wird zu zählen(Zelle 1 = Wert 0, Zelle 2 = Wert 1 usw..).
Blicken wir im Tutorial nach oben steht dort die Struktur des Parameters. window_type vom Typ BYTE und cell vom Typ WORD. Word ist ein Datentyp mit 2Bytes.
Alles was wir also vor dem Funktionsaufruf machen müssen, ist die Datenstruktur auf den Stack zu pushen.
Wollen wir also das Item des Slots 10 benutzen, so muss der Wert wie folgt aussehen:
PHP Code:
0x00000A01. (A ist Hexadezimal für 10)
Vom Prinzip sieht unser Code nun folgendermaßen aus:
PHP Code:
push 00000A01
call 0099A740
Das ist jedoch leider noch nicht alles.
Der Klassenpointer
Die Funktion SendItemUsePacket(TItemPos pos) befindet sich in einer Klasse. Und zwar der CPythonNetworkStream class. Der Pointer(Zeiger) auf diese Klasse muss in diesem Fall ebenfalls bekannt sein. Wenn Funktionen aus anderen Klassen aufgerufen werden, wird der Pointer zu dieser Klasse mit angegeben. Dazu ist in der Regel das ECX Register.
Kurz gesagt: Vor dem Aufruf der Funktion SendUseItemPacket wird der Klasspointer in ECX gemoved. Dies müssen wir ebenfalls tun.(Das ist fast immer so!)
Um zu wissen wie der Pointer lautet müssen wir nur wieder einen Breakpoint auf den Anfang! der Funktion legen und ein Item benutzen. Der Wert, welcher sich nun im ECX Register befindet, ist unser gesuchter Klassenpointer. Dies ist jedoch kein statischer Pointer, heißt er wird nur für diesen Prozess funktionieren. Startet ihr das Spiel neu, ist der Pointer ebenfalls neu und euer Code wird nächstes mal nicht mehr hinhauen.
Wie findet man also den statischen Pointer?
Ganz einfach: Man reversed das Ganze ein wenig mehr.Wir wollen also nun herrausfinden, wo der Wert des ECX Registers herkommt. Dazu müssen wir allerdings vor den Aufruf der Funktion. Ich hatte vorher ja schon davon gesprochen, dass sich auf dem Stack, wenn der Breakpoint auslöst, die Rücksprungadresse befindet. Dort machen wir einfach einen Doppelklick drauf und schon landen wir bei dem Funktionsaufruf(call).
Scrollen wir nun etwas hoch sieht man in meinem Beispiel folgendes:
Durch Breakpoints setzen(über dem call) kann man nun herrausfinden, wo das ECX Register geladen wird, wenn es nicht vorher schon offensichtlich ist.
Es kann vorkommen, dass vor dem Funktionsaufruf direkt folgendes steht:
PHP Code:
mov ECX, [0035BD78]
Dann habt ihr den statischen Pointer direkt gefunden.
Da das hier nicht offensichtlich ist, müssen wir ein wenig rumprobieren. Wir wissen also das ECX 06CA9ED0 sein muss, also setzen wir Schritt für Schritt Breakpoints(über dem eigentlichen Funktionscall) und warten bis unsere Addresse in den Registern auftaucht.
Ich habe mal auf die Addresse 0098C49B (siehe Bild oben) einen Breakpoint gesetzt und gemerkt, dass das EAX Register nach diesem call den gesuchten Wert hält.(EAX ist das return Register, wo nach dem Funktionsaufruf (meistens) das Ergebnis einer Funktion landet)
Nachfolgender Code(damit ist der Code nach dem call auf 0090BD70 gemeint) schiebt den EAX Wert dann nur noch in das ECX Register. Der call auf 0090BD70 scheint uns also den gesuchten Klassenpointer zu liefern.
Schauen wir uns diese nun genauer an (Rechtsklick auf call 0090BD70 und Follow).
Ahh! Perfekt. Wir sehen einen mov ins EAX Register. Und zwar mov eax, [01482190]. 01482190 ist hierbei eine Adresse im Speicher, an welcher unsere gesuchte Adresse steht.
Sucht man nach der Adresse unten wieder im HexViewer, so findet man an der Stelle 06CA9ED0(bzw D09ECA06-> Im Speicher steht es verkehrt herrum).
4.) Programmierung
Ich werde dazu demnächst mehr schreiben.
Programmcode dazu:
PHP Code:
void UseItem()
{
DWORD callToUseItem = 0x099A740;
_asm{
MOV ECX, DWORD PTR DS : [0x01482190]
PUSH 0x0A01
CALL callToUseItem
}
}
Bei Fragen Skype: marcel.metin2