Parte 1 di 3
Se sei seriamente interessato al reverse engineering, dimentica i trainer e i cheat engine.
Un buon reverse engineer dovrebbe prima conoscere il sistema operativo, le funzioni API di base, la struttura generale del programma (cos'è il ciclo di esecuzione, le strutture di Windows, le routine di gestione degli eventi), il formato dei file (PE). I classici "Programming Windows" di Petzold possono aiutare (www.amazon.com/exec/obidos/ISBN=157231995X) così come MSDN online.
Per prima cosa dovresti pensare a dove può essere chiamata la routine di inizializzazione del campo minato. Ho pensato di seguire:
- Quando avvii il gioco
- Quando fai clic su faccina felice
- Quando fai clic su Gioco-> Nuovo o premi F2
- Quando cambi livello di difficoltà
Ho deciso di controllare il comando dell'acceleratore F2.
Per trovare il codice di gestione dell'acceleratore devi trovare la procedura di gestione dei messaggi della finestra (WndProc). Può essere rintracciato dalle chiamate CreateWindowEx e RegisterClass.
Leggere:
Apri IDA, finestra Imports, trova "CreateWindow *", salta ad esso e usa il comando "Jump xref to operand (X)" per vedere dove viene chiamato. Dovrebbe esserci solo una chiamata.
Ora guarda sopra per la funzione RegisterClass e il suo parametro WndClass.lpfnWndProc. Ho già chiamato la funzione mainWndProc nel mio caso.
.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
Premi Invio sul nome della funzione (usa 'N' per rinominarlo in qualcosa di meglio)
Ora dai un'occhiata
.text:01001BCF mov edx, [ebp+Msg]
Questo è l'ID del messaggio, che in caso di pressione del pulsante F2 dovrebbe contenere il valore WM_COMMAND. Devi trovare dove si trova rispetto a 111h. Può essere fatto tracciando edx in IDA o impostando il punto di interruzione condizionale in WinDbg e premendo F2 nel gioco.
In ogni caso porta a qualcosa di simile
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Fare clic con il tasto destro su 111h e utilizzare "Costante simbolica" -> "Usa costante simbolica standard", digitare WM_ e Invio. Ora dovresti avere
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
È un modo semplice per scoprire i valori degli ID dei messaggi.
Per comprendere la gestione dell'acceleratore, controlla:
È un bel po 'di testo per una singola risposta. Se ti interessa posso scrivere un altro paio di post. Campo minato lungo e breve memorizzato come array di byte [24x36], 0x0F mostra che il byte non è utilizzato (campo più piccolo), 0x10 - campo vuoto, 0x80 - mio.
Parte 2 di 3
Ok, andiamo avanti con il tasto F2.
Secondo Utilizzo degli acceleratori da tastiera quando si preme il pulsante F2 funzione wndProc
... riceve un messaggio WM_COMMAND o WM_SYSCOMMAND. La parola di ordine inferiore del parametro wParam contiene l'identificatore dell'acceleratore.
Ok, abbiamo già trovato dove viene elaborato WM_COMMAND, ma come determinare il valore del parametro wParam corrispondente? È qui che entra in gioco l' hacker di risorse . Alimentalo con binario e ti mostra tutto. Come la tabella degli acceleratori per me.
testo alternativo http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Puoi vedere qui, che il pulsante F2 corrisponde a 510 in wParam.
Ora torniamo al codice, che gestisce WM_COMMAND. Confronta wParam con diverse costanti.
.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
Usa il menu contestuale o la scorciatoia da tastiera "H" per visualizzare i valori decimali e puoi vedere il nostro salto
.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
Porta a un blocco di codice che chiama alcuni proc ed esce da wndProc.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
È questa la funzione che avvia il nuovo gioco? Scoprilo nell'ultima parte! Rimanete sintonizzati.
Parte 3 di 3
Diamo un'occhiata alla prima parte di quella funzione
.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
Ci sono due valori (dword_10056AC, uValue) letti nei registri eax ed ecx e confrontati con altri due valori (dword_1005164, dword_1005338).
Dai un'occhiata ai valori effettivi usando WinDBG ('bp 01003696'; in pausa 'p eax; p ecx') - mi sembravano dimensioni di campo minato. Giocare con le dimensioni personalizzate del campo minato ha mostrato che la prima coppia sono nuove dimensioni e la seconda - dimensioni attuali. Impostiamo nuovi nomi.
.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
Un po 'più tardi i nuovi valori sovrascrivono la corrente e viene chiamata la subroutine
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
E quando l'ho visto
.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
Ero completamente sicuro di aver trovato la matrice del campo minato. Causa del ciclo che inits array di 360h byte di lunghezza (dword_1005340) con 0xF.
Perché 360h = 864? Ci sono alcuni segnali sotto quella riga che richiede 32 byte e 864 può essere diviso per 32, quindi l'array può contenere 27 * 32 celle (sebbene l'interfaccia utente consenta un massimo di 24 * 30 campi, c'è un byte che riempie l'array per i bordi).
Il codice seguente genera i bordi superiore e inferiore del campo minato (0x10 byte). Spero che tu possa vedere l'iterazione del loop in quel casino;) Ho dovuto usare carta e penna
.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
E il resto della subroutine disegna i bordi sinistro e destro
.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
L'utilizzo intelligente dei comandi WinDBG può fornire un fantastico dump del campo minato (dimensioni personalizzate 9x9). Controlla i confini!
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, sembra che avrò bisogno di un altro post per chiudere l'argomento