Come posso trovare la struttura dati che rappresenta la miniera di layout di prato fiorito in memoria?
-
06-09-2019 - |
Domanda
Sto cercando di imparare a reverse engineering, usando prato fiorito come un esempio di applicazione.Ho trovato questo Articolo di MSDN su un semplice WinDbg comando che si rivela in tutte le miniere, ma è vecchio, non è spiegato in ogni dettaglio e davvero non è quello che sto cercando.
Ho IDA Pro disassembler e il WinDbg debugger e ho caricato winmine.exe in tutte e due.Qualcuno può fornire alcuni consigli pratici per uno di questi programmi in termini di trovare la posizione della struttura dati che rappresenta il campo minato?
In WinDbg posso impostare punti di interruzione, ma è difficile per me immaginare a che punto per impostare un punto di interruzione e in quale locazione di memoria.Allo stesso modo, quando l'ho vista la statica del codice in IDA Pro, io non sono sicuro di dove iniziare a trovare la funzione o la struttura dati che rappresenta il campo minato.
Ci sono Reverse engineer su Stackoverflow che mi punto nella giusta direzione?
Soluzione
Parte 1 di 3
Se siete seriamente in reverse engineering - dimenticare formatori e cheat engine.
Buona decodificare deve prima conoscere OS, le funzioni API di base, programma di struttura generale (anello ciò che viene eseguito, strutture finestre, le routine di gestione degli eventi), formato di file (PE). classici "Programming Windows" di Petzold può aiutare (www.amazon.com/exec/obidos/ISBN=157231995X), così come in linea di MSDN.
In primo luogo si dovrebbe pensare a dove routine di inizializzazione campo minato può essere chiamato. Ho pensato di seguire:
- Quando si avvia il gioco
- Quando si fa clic faccia felice
- Quando si sceglie Game-> Nuovo o premere F2
- Quando si modifica il livello di difficoltà
Ho deciso di controllare il comando F2 dell'acceleratore.
Per trovare il codice di gestione di acceleratore si è di trovare procedura di gestione dei messaggi finestra (WndProc). Si può essere fatta verso il basso da chiamate CreateWindowEx e RegisterClass.
Per leggere:
- http://msdn.microsoft.com /en-us/library/ms632680%28VS.85%29.aspx
- http://msdn.microsoft.com /en-us/library/ms633586%28VS.85%29.aspx
- Petzold capitolo 3 "di Windows e messaggi"
Aprire IDA, la finestra Imports, trovare "CreateWindow *", saltare e utilizzare "Jump xref all'operando (X)" il comando per vedere dove è chiamato. Ci dovrebbe essere una sola chiamata.
Ora guarda soprattutto per la funzione RegisterClass ed è parametro WndClass.lpfnWndProc. Ho già chiamato 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
Hit Invio sul nome di funzione (usare 'N' per rinominarlo in qualcosa di meglio)
Ora date un'occhiata a
.text:01001BCF mov edx, [ebp+Msg]
Questo è il messaggio id, che in caso di tasto F2 stampa dovrebbe contenere il valore WM_COMMAND. Tu sei per trovare dove si è confrontato con 111h. Esso può essere fatto sia tracciando giù edx in IDA o modificando breakpoint condizionale in WinDbg e premendo F2 nel gioco.
In entrambi i casi conduce a qualcosa di simile
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Fare clic destro su 111h e l'uso "costante simbolica" -> "Usa livello costante simbolica", tipo WM_ e Invio. Si dovrebbe ora avere
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
Si tratta di un modo semplice per scoprire i valori ID messaggio.
Per capire la gestione dell'acceleratore check out:
- Utilizzando tastiera acceleratori
- Resource Hacker ( http://angusj.com/resourcehacker/ )
E 'un bel po' di testo per una sola risposta. Se siete interessati posso scrivere un altro paio di post. Per farla breve campo minato memorizzato come un array di byte [24x36], 0x0F dimostra che di byte non è utilizzato (campo di gioco più piccolo), 0x10 - campo vuoto, 0x80 -. mine
Parte 2 di 3
Ok, andiamo avanti con il tasto F2.
Utilizzando tastiera acceleratori funzione WndProc quando si preme il tasto F2
... riceve un WM_COMMAND o WM_SYSCOMMAND Messaggio. La parola di ordine del parametro wParam contiene il identificatore dell'acceleratore.
Ok, abbiamo già trovato dove WM_COMMAND viene elaborato, ma come determinare corrispondente valore del parametro wParam? Questo è dove Resource Hacker entra in gioco. Alimentarlo con binario e vi mostra tutto. Come tabella di acceleratori per me.
alt text http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Si può vedere qui, che il tasto F2 corrisponde a 510 in wParam.
Ora torniamo al codice, che gestisce WM_COMMAND. Esso mette a confronto 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
menu Usa contestuale o 'H' scorciatoia da tastiera per visualizzare i valori decimali e si può 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
Si porta a pezzo di codice che chiama alcuni proc ed esce WndProc.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
è che la funzione che avvia nuovo gioco? Trova che nell'ultima parte! Restate sintonizzati.
Parte 3 di 3
Diamo uno sguardo alla prima parte di tale 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, Valore U) in lettura nei registri eax e ecx e rispetto ad altri due valori (dword_1005164, dword_1005338).
Date un'occhiata a valori reali utilizzando WinDBG ( 'BP 01.003.696'; in pausa 'p EAX; p ecx') - sembravano dimensioni campo minato per me. Giocando con dimensioni campo minato personalizzato ha dimostrato che prima coppia sono nuove dimensioni e la seconda - dimensioni attuali. Fissiamo 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 nuovi valori sovrascrivono attuale e subroutine si chiama
.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 del tutto sicuro che ho trovato matrice campo minato. Causa di ciclo che INITs lunghezza byte 360h array (dword_1005340) con 0xF.
Perché 360h = 864? Ci sono alcuni spunti sotto quella riga richiede 32 byte e 864 può essere diviso per 32, quindi array può contenere 27 * 32 cellule (sebbene UI permette max 24 * 30 campo, c'è un'imbottitura byte intorno array per bordi).
A seguito di codice genera alto campo minato e bordi inferiori (0x10 byte). Spero che si può vedere iterazione del ciclo 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 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
Utilizzo intelligente di WinDBG comandi in grado di fornire la pelle fresca discarica campo minato (formato 9x9 personalizzato). Controlla le frontiere!
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 io avrò bisogno un altro post per chiudere l'argomento
Altri suggerimenti
Sembra che si sta tentando di smontare la fonte, ma quello che dovete fare è guardare lo spazio di memoria del programma in esecuzione. L'editor esadecimale HxD ha una caratteristica che ti permette proprio questo.
Una volta entrato nello spazio di memoria, si tratta di una questione di prendere istantanee della memoria, mentre si scherza con la scheda. Isolare cosa cambia rispetto a ciò che non lo fa. Quando si pensa di avere una maniglia su cui la struttura di dati risiede in memoria esadecimale, provare a modificare mentre è nella memoria e vedere se i cambiamenti di bordo di conseguenza.
Il processo che si desidera non è dissimile la costruzione di un 'allenatore' per un videogioco. Coloro che sono di solito basate sulla ricerca in cui i valori come la salute e munizioni vivono in memoria e cambiare al volo. Si può essere in grado di trovare alcuni buoni tutorial su come costruire formatori di gioco.
Dai un'occhiata a questo articolo del progetto di codice, è un po 'più in profondità rispetto al post sul blog che lei ha citato.
http://www.codeproject.com/KB/trace/minememoryreader.aspx
Modifica
E questo articolo, anche se non si tratta di Minesweeper direttamente, ti dà una buona guida passo passo sulla caccia attraverso la memoria utilizzando WinDbg:
http://www.codingthewheel.com/archives/extracting- nascosto-text-con-windbg
Modifica 2
Anche in questo caso, non si tratta di campo minato, ma mi ha sicuramente dato alcuni spunti di riflessione per il mio debug di memoria, c'è una ricchezza di tutorial qui:
http://memoryhacking.com/forums/index.php
Inoltre, scarica cheat engine (citato da Nick D.) e di lavoro attraverso il tutorial si tratta con.
"In WinDbg posso impostare i punti di interruzione, ma è difficile per me immaginare a che punto per impostare un punto di interruzione e al quale posizione di memoria. Analogamente, quando Considero il codice statico in IDA Pro, sono Non sai da dove cominciare, anche per trovare la funzione o che datastructure rappresenta il campo minato ".
Esattamente!
Beh, si può guardare per le routine come Random () che verranno chiamati durante la costruzione del tavolo miniere. Questo libro mi ha aiutato molto quando stavo sperimentando con il reverse engineering. :)
In generale, buoni posti per l'impostazione di punti di interruzione sono chiamate a finestre di messaggio, invita a riprodurre un suono, timer e altre routine API Win32.
BTW, sto a scannerizzare campo minato in questo momento con OllyDbg .
Aggiornamento: nemo mi ha ricordato un grande strumento, Trucchi motore da Eric "dark Byte" Heijnen.
Cheat Engine (CE) è un grande strumento per la visione e la modifica di altri processi di spazio di memoria. Al di là che base struttura, CE ha caratteristiche speciali come la visualizzazione della memoria smontato di un processo e l'iniezione di codice in altri processi.
( reale il valore di quel progetto è che si può scaricare il codice sorgente -Delphi- e vedere come sono stati attuati quei meccanismi - ho fatto molti anni fa: o)
Un buon articolo su questo argomento sono disponibili all'indirizzo Uninformed . Esso copre inversione Minesweeper (come introduzione al reverse engineering Win32 apps) in abbastanza grande dettaglio ed è tutto intorno a un grazioso grande risorsa.
Questo sito web potrebbe essere più utile:
http://www.subversity.net/reversing/hacking-minesweeper
Il modo per farlo è:
- In qualche modo ottenere il codice sorgente.
- Smontare e speranza avanzi di simboli può aiutare.
- Indovinare il tipo di dati e cercare di manipolare e utilizzare uno scanner della memoria a limitare le possibilità.
In risposta a Bounty
Beh, in seconda lettura, sembra come se si voleva una guida su come utilizzare un debugger come WinDBG, piuttosto che la solita questione di come decodificare.Ho già mostrato il sito che ti dice i valori è necessario per la ricerca, quindi la domanda è, come si cerca?
Sto usando il blocco note in questo esempio perché non ho Dragamine installato.Ma l'idea è la stessa.
Si tipo
s <options> <memory start> <memory end> <pattern>
Premere il tasto "?"e poi "s" per vedere la guida in linea.
Una volta trovata la memoria il modello che si desidera, è possibile premere alt+5 per visualizzare il visualizzatore di memoria per un bel display.
WinDBG prende un po per abituarsi, ma è buono come qualsiasi altro debugger là fuori.
Un buon punto per iniziare la traccia nel debugger sarebbe il mouse verso l'alto. Così trovare procedura di finestra principale (credo strumenti come spyxx può ispezionare finestre proprietà e l'indirizzo di gestore di eventi è uno di loro). Rodare ad esso e trovare dove gestisce gli eventi del mouse - ci sarà un interruttore, se si può riconoscere in assembler (vedi valore del WM_XXX per il mouse in windows.h)
.Mettere un punto di interruzione e iniziare a fare un passo. Da qualche parte tra il momento in cui rilasciato il pulsante del mouse e schermo in fase di aggiornamento del victum accederà al datastructure che stai cercando.
Sii paziente, cercare di individuare cosa si sta facendo in un dato momento, ma non preoccupatevi guardare troppo in profondità nel codice si sospetta di essere poco interessante per il vostro obiettivo attuale. Si potrebbe prendere diverse piste in debugger per inchiodare giù.
La conoscenza del normale flusso di lavoro di applicazioni Win32 aiuta anche.
Le miniere saranno probabilmente conservati in una sorta di matrice bidimensionale. Ciò significa che è o un array di puntatori o di un singolo array stile C di booleani.
Ogni volta che il modulo riceve un evento mouse-up questa struttura di dati viene fatto riferimento. L'indice verrà calcolato utilizzando la coordinata mouse, probabilmente mediante divisione intera. Ciò significa che probabilmente si dovrebbe cercare un cmp
o un'istruzione simile, in cui uno degli operandi viene calcolato utilizzando un offset e x
, dove x
è il risultato di un calcolo che coinvolge divisione intera. L'offset sarà poi il puntatore all'inizio della struttura dati.
È abbastanza ragionevole supporre che le informazioni relative mine è spiegate in modo contiguo in memoria almeno per righe (cioè è un 2D-array, o una matrice-di-array). Così, proverei aprire più celle adiacenti sulla stessa riga, facendo dump di memoria del processo come vado, e poi li diff e cercare eventuali cambiamenti ripetuti nella regione stessa memoria (cioè 1 byte modifica del primo passo, il successivo byte cambiato esattamente lo stesso valore sul passo successivo, ecc).
C'è anche la possibilità che si tratta di una matrice di bit al sacco (3 bit per miniera dovrebbero essere sufficienti per registrare tutti gli stati possibili - chiuso / aperto, il mio / no-mina, contrassegnato / non contrassegnato), quindi mi piacerebbe guardare fuori per anche questo (i modelli sarebbe anche ripetibile, anche se più difficili da individuare). Ma non è una struttura comoda da affrontare, e non credo che l'utilizzo della memoria è stato un collo di bottiglia per Minesweeper, quindi è improbabile che questo genere di cose sarebbe stato utilizzato.
Anche se non strettamente "strumento di reverse engineering" un, e più di un giocattolo, anche un idiota come me potrebbe utilizzare, controlla cheat Engine . Lo rende un po 'facile rintracciare quali parti della memoria sono cambiate, quando, e ha anche disposizioni per il monitoraggio delle parti di memoria modificata tramite puntatori (anche se probabilmente non avete bisogno di questo). Un bel tutorial interattivo è incluso.