Teil 1 von 3
Wenn Sie sich ernsthaft mit Reverse Engineering beschäftigen, vergessen Sie Trainer und Cheat-Engines.
Ein guter Reverse Engineer sollte zuerst das Betriebssystem, die Kernfunktionen der API, die allgemeine Programmstruktur (was ist eine Ausführungsschleife, Windows-Strukturen, Routinen zur Ereignisbehandlung) und das Dateiformat (PE) kennenlernen. Petzolds Klassiker "Programming Windows" können helfen (www.amazon.com/exec/obidos/ISBN=157231995X) sowie Online-MSDN.
Zuerst sollten Sie sich überlegen, wo die Minenfeld-Initialisierungsroutine aufgerufen werden kann. Ich dachte an Folgendes:
- Wenn Sie das Spiel starten
- Wenn Sie auf glückliches Gesicht klicken
- Wenn Sie auf Spiel-> Neu klicken oder F2 drücken
- Wenn Sie den Schwierigkeitsgrad ändern
Ich beschloss, den F2-Beschleunigerbefehl zu überprüfen.
Um den Code für die Handhabung von Beschleunigern zu finden, müssen Sie die Prozedur für die Behandlung von Fensternachrichten (WndProc) suchen. Es kann durch CreateWindowEx- und RegisterClass-Aufrufe zurückverfolgt werden.
Lesen:
Öffnen Sie das IDA-Fenster "Importe", suchen Sie "CreateWindow *", springen Sie dorthin und verwenden Sie den Befehl "Jump xref to operand (X)", um zu sehen, wo es aufgerufen wird. Es sollte nur einen Anruf geben.
Suchen Sie oben nach der RegisterClass-Funktion und ihrem Parameter WndClass.lpfnWndProc. In meinem Fall habe ich bereits die Funktion mainWndProc benannt.
.text:0100225D mov [ebp+WndClass.lpfnWndProc], offset mainWndProc
.text:01002264 mov [ebp+WndClass.cbClsExtra], edi
.text:01002267 mov [ebp+WndClass.cbWndExtra], edi
.text:0100226A mov [ebp+WndClass.hInstance], ecx
.text:0100226D mov [ebp+WndClass.hIcon], eax
.text:01002292 call ds:RegisterClassW
Drücken Sie die Eingabetaste für den Funktionsnamen (verwenden Sie 'N', um ihn in etwas Besseres umzubenennen).
Nun schauen Sie sich an
.text:01001BCF mov edx, [ebp+Msg]
Dies ist die Nachrichten-ID, die bei Drücken der Taste F2 den Wert WM_COMMAND enthalten sollte. Sie müssen herausfinden, wo es mit 111h verglichen wird. Dies kann entweder durch Aufspüren von edx in IDA oder durch Festlegen eines bedingten Haltepunkts erfolgen in WinDbg und Drücken von F2 im Spiel erfolgen.
So oder so führt zu so etwas
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Klicken Sie mit der rechten Maustaste auf 111h und verwenden Sie "Symbolische Konstante" -> "Standardmäßige symbolische Konstante verwenden", geben Sie WM_ und Enter ein. Das solltest du jetzt haben
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
Es ist eine einfache Möglichkeit, Nachrichten-ID-Werte herauszufinden.
Informationen zum Handling des Gaspedals finden Sie unter:
Es ist ziemlich viel Text für eine einzelne Antwort. Wenn Sie interessiert sind, kann ich noch ein paar Beiträge schreiben. Langes, kurzes Minenfeld, gespeichert als Array von Bytes [24x36], 0x0F zeigt, dass Byte nicht verwendet wird (kleineres Feld spielen), 0x10 - leeres Feld, 0x80 - Mine.
Teil 2 von 3
Ok, lass uns mit der F2-Taste weitermachen.
Gemäß Verwenden von Tastaturbeschleunigern, wenn die Taste F2 gedrückt wird, wndProc-Funktion
... empfängt eine WM_COMMAND- oder WM_SYSCOMMAND-Nachricht. Das niederwertige Wort des Parameters wParam enthält die Kennung des Beschleunigers.
Ok, wir haben bereits gefunden, wo WM_COMMAND verarbeitet wird, aber wie kann der entsprechende wParam-Parameterwert ermittelt werden? Hier kommt der Resource Hacker ins Spiel. Füttere es mit Binär und es zeigt dir alles. Wie Beschleunigertisch für mich.
Alternativtext http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Sie können hier sehen, dass die F2-Taste 510 in wParam entspricht.
Kommen wir nun zum Code zurück, der WM_COMMAND behandelt. Es vergleicht wParam mit verschiedenen Konstanten.
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 210h
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 1FEh
.text:01001DD8 jz loc_1001EC8
Verwenden Sie das Kontextmenü oder die Tastenkombination 'H', um Dezimalwerte anzuzeigen, und Sie können unseren Sprung sehen
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 528
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 510
.text:01001DD8 jz loc_1001EC8 ; here is our jump
Es führt zu einem Codeblock, der einen Prozess aufruft und wndProc beendet.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
Ist das die Funktion, die ein neues Spiel initiiert? Finden Sie das im letzten Teil heraus! Bleib dran.
Teil 3 von 3
Werfen wir einen Blick auf den ersten Teil dieser Funktion
.text:0100367A sub_100367A proc near ; CODE XREF: sub_100140C+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, dword_10056AC
.text:0100367F mov ecx, uValue
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, dword_1005334
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, dword_1005338
.text:0100369E jnz short loc_10036A4
Es gibt zwei Werte (dword_10056AC, uValue), die in die Register eax und ecx eingelesen und mit zwei weiteren Werten verglichen werden (dword_1005164, dword_1005338).
Sehen Sie sich die tatsächlichen Werte mit WinDBG an ('bp 01003696'; bei Pause 'p eax; p ecx') - sie schienen mir Minenfelddimensionen zu sein. Das Spielen mit der benutzerdefinierten Minenfeldgröße zeigte, dass das erste Paar neue Dimensionen und das zweite aktuelle Dimensionen sind. Setzen wir neue Namen.
.text:0100367A startNewGame proc near ; CODE XREF: handleButtonPress+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, newMineFieldWidth
.text:0100367F mov ecx, newMineFieldHeight
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, currentMineFieldWidth
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, currentMineFieldHeight
.text:0100369E jnz short loc_10036A4
Wenig später werden neue Werte zum Überschreiben von Strom und Unterprogramm aufgerufen
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
Und als ich es sah
.text:01002ED5 sub_1002ED5 proc near ; CODE XREF: sub_1002B14:loc_1002B1Ep
.text:01002ED5 ; sub_100367A+38p
.text:01002ED5 mov eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA: ; CODE XREF: sub_1002ED5+Dj
.text:01002EDA dec eax
.text:01002EDB mov byte ptr dword_1005340[eax], 0Fh
.text:01002EE2 jnz short loc_1002EDA
Ich war mir völlig sicher, dass ich ein Minenfeld-Array gefunden habe. Ursache des Zyklus, der ein Array mit einer Länge von 360 Stunden (dword_1005340) mit 0xF einleitet.
Warum 360h = 864? Es gibt einige Hinweise darunter, dass die Zeile 32 Bytes benötigt und 864 durch 32 geteilt werden kann, sodass das Array 27 * 32 Zellen enthalten kann (obwohl die Benutzeroberfläche maximal 24 * 30 Felder zulässt, wird das Array für Ränder mit einem Byte aufgefüllt).
Der folgende Code generiert obere und untere Minenfeldränder (0x10 Byte). Ich hoffe, Sie können Schleifeniteration in diesem Durcheinander sehen;) Ich musste Papier und Stift verwenden
.text:01002EE4 mov ecx, currentMineFieldWidth
.text:01002EEA mov edx, currentMineFieldHeight
.text:01002EF0 lea eax, [ecx+2]
.text:01002EF3 test eax, eax
.text:01002EF5 push esi
.text:01002EF6 jz short loc_1002F11 ;
.text:01002EF6
.text:01002EF8 mov esi, edx
.text:01002EFA shl esi, 5
.text:01002EFD lea esi, dword_1005360[esi]
.text:01002EFD
.text:01002F03 draws top and bottom borders
.text:01002F03
.text:01002F03 loc_1002F03: ; CODE XREF: sub_1002ED5+3Aj
.text:01002F03 dec eax
.text:01002F04 mov byte ptr MineField?[eax], 10h ; top border
.text:01002F0B mov byte ptr [esi+eax], 10h ; bottom border
.text:01002F0F jnz short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11: ; CODE XREF: sub_1002ED5+21j
.text:01002F11 lea esi, [edx+2]
.text:01002F14 test esi, esi
.text:01002F16 jz short loc_1002F39
Und der Rest des Unterprogramms zeichnet linke und rechte Grenzen
.text:01002F18 mov eax, esi
.text:01002F1A shl eax, 5
.text:01002F1D lea edx, MineField?[eax]
.text:01002F23 lea eax, (MineField?+1)[eax+ecx]
.text:01002F23
.text:01002F2A
.text:01002F2A loc_1002F2A: ; CODE XREF: sub_1002ED5+62j
.text:01002F2A sub edx, 20h
.text:01002F2D sub eax, 20h
.text:01002F30 dec esi
.text:01002F31 mov byte ptr [edx], 10h
.text:01002F34 mov byte ptr [eax], 10h
.text:01002F37 jnz short loc_1002F2A
.text:01002F37
.text:01002F39
.text:01002F39 loc_1002F39: ; CODE XREF: sub_1002ED5+41j
.text:01002F39 pop esi
.text:01002F3A retn
Durch die intelligente Verwendung von WinDBG-Befehlen erhalten Sie einen coolen Minenfeld-Dump (benutzerdefinierte Größe 9x9). Schauen Sie sich die Grenzen an!
0:000> db /c 20 01005340 L360
01005340 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005360 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005380 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053a0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053c0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053e0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005400 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005420 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005440 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005460 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005480 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054a0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054c0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054e0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
Hmm, es sieht so aus, als würde ich einen weiteren Beitrag brauchen, um das Thema zu schließen