Reverse Engineering hat eine Menge mit Raten zu tun. Man findet eine Funktion, und muss eine Annahme treffen, welche Aufgabe diese hat und zu welchen Zeitpunkt sie aufgerufen wird. Man findet weitere Funktionen und trifft weitere Annahmen. Man betrachtet Parameter und Rückgabewerte.
Man analysiert den Code durch ausführen und anhalten an entsprechnden Breakpoints.
Bei der Chat-Funktion beispielsweise findet man durch eine Stringsuche zunächst unter anderem diese Position:
[Only registered and activated users can see links. Click Here To Register...]
Mit dem vorhrigen Patch hat man diesen Code sogar noch erreicht. Mit dem aktuellen haben wir pech :D. Der Breakpoint wird nie erreicht. Aber das macht nichts, denn wir können ja auch so den Code näher betrachten. Wir treffen hier also die erste Annahme: Dieser Code hat mit dem Chat zu tun.
Überblickt man den Code, sieht man, dass hier der Wert hinter EAX auf 0x2F (/) geprüft wird. Mit / beginnen die Befehle im Chat. Hier könnte also eine Verarbeitung von Befehlen sein. (Schon wieder eine Annahme).
Wir setzen testweise einen Breakpoint auf die CMP Anweisung:
[Only registered and activated users can see links. Click Here To Register...]
Im Code sieht man schon die Kommentare, und ein Blick auf die Register Verrät entgültig:
[Only registered and activated users can see links. Click Here To Register...]
Diese Funktion bekommt unsere Chat Nachricht ab.
Nun wäre es interessant zu wissen, wann diese aufgerufen wird, und was ihre Parameter sind. Also setzt man einen Breakpoint auf die erste Anweisung der Funktion.
Wenn wir nun eine Chatnachricht absenden, sollte der Breakpoint ja erreicht werden. Sollte er schon vorher erreicht werden, ist dieser Teil der Funktion bereits zu generisch und nicht ausschließlich für das Verarbeiten von Chatnachrichten zuständig.
[Only registered and activated users can see links. Click Here To Register...]
In diesem Fall haben wir Glück. Der Breakpoint wird erreicht, nachdem wir die Nachricht abgesendet haben.
[Only registered and activated users can see links. Click Here To Register...]
Im Stack können wir die Parameter sehen. In diesem Fall scheinbar nichts spannendes. Vielleicht gibt es auch keine Parameter. In der Disassembly-Ansicht sieht man bereits, dass die Register EDI und EAX den eigebenen Text beinhalten. Register werden allerdings nur in Spezialfällen zur Parameterübergabe eingesetzt, daher ist diese Information eher unwichtig.
Wir riskieren mal einen Blick auf die Rücksprungadresse. Die liegt ebenfalls auf dem Stack.
[Only registered and activated users can see links. Click Here To Register...]
Was uns hier als aller erstes auffällt: Der Aufruf der Funktion ist statisch. Daraus schließen wir, dass auch diese Funktion, zumindest teilweise mit dem Verarbeiten von Chatnachrichten beschäftigt ist. Würden wir hier einen dynamischen Aufruf wie z.B. CALL EAX finden, hat dieser Teil des Codes ganz sicher noch einige andere Aufgaben und es lohnt nicht wirklich, sich damit zu beschäftigen.
Dann sollte auffallen, dass es vor dem CALL keine PUSH-Anweisungen gibt. Möglicherweise hat diese Funktion wirklich keine Parameter. Aber es wird ECX unmittelbar vor dem CALL gesetzt. Dies deutet auf einen thiscall, also eine Funktion die Bezug zu einer Objektinstanz hin.
Code:
instanz->funktion(); // So in der Art wirds wohl ausgesehen haben
Anhand der beiden JMPs oben und unten erkennt man außerdem, dass es sich hier um einen Zweig handelt. Betrachtet man die Funktion als ganzes, dann könnte das hier das Case eines Switch gewesen sein. (Annahme!)
Da auch diese äußere Funktion offensichtlich etwas mit dem Chat zu tun hat, setzen wir einfach noch einmal auf die erste Anweisung einen Breakpoint.
Nun stellen wir fest, dass dieser Breakpoint nicht nur auf das Absenden der Nachricht, sondern auch auf das Öffnen des Chatfensters reagiert. Damit hat diese Funktion noch weitere Aufgaben. Annahme: Ein Event-Handler des ChatFensters. Betrachten wir mal die Rücksprungadresse:
[Only registered and activated users can see links. Click Here To Register...]
CALL EAX, hier werden also dynamisch Funktionen aufgerufen. Wenn man hier einen Breakpoint setzt, bekommt man noch viele andere Funktionen ab. Hier ist also nichts zu holen. Interessant sind scheinbar nur die beiden anderen Funktionen.
Die "äußere Funktion" vermute ich, wie gesagt, als eine Art EventHandler des ChatFensters. Die innere Funktion verarbeitet anscheinend die eingegebene Nachricht. Vielleicht reicht es schon, diese per DLL direkt aufzurufen. Stellt sich nur die Frage, woher die Nachricht kommt. Vielleicht gibt es eine Funktion, die den Text erst aus dem ChatFenster ausließt ... (Annahme).
In der "inneren Funktion" sollte man auf jeden Fall mal die Nachricht weiter verfolgen.
Nachtrag:
Im Grunde ist es Schema F. Code finden > Vermutungen aufstellen > Beweise finden > weiteren Code finden > Vermutungen aufstellen > Beweise finden > ... und so weiter
Mit der Zeit erkennt man natürlich gewisse Strukturen wie z.B. das Switch-case, den thiscall, etc. Da muss man einfach dran bleiben. Zur Not auch mal eigenen (C/C++)-Code kompilieren und schauen was hinten rauskommt. Oder wenns nur Bahnhof ist, natürlich auch mal Fragen stellen.