Tutorial 30 - Debug API 3 parte
From UIC
Tutorial 30: Win32 Debug API Part 3
Contents |
| Infos | |
|---|---|
| Author: | Iczelion |
| Email: | Translate: Antelox |
| Website: | Mirror |
| Date: | 09/08/2009 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Formattazione Wiki: Antelox |
Introduzione
In questo tutorial, continuiamo l'esplorazione delle API Win 32 di Debug. In particolare, impareremo come "tracciare" il debuggee.
Tools
Essay
Se avete usato un debugger, dovreste avere familiarità con il tracing [ NdT ovvero l'operazione di "tracciamento" del debuggee ]. Quando si "traccia" un programma, il programma si blocca dopo l'esecuzione di ogni istruzione, dando la possibilità di esaminare i valori dei/della registri/memoria. Il tracing è chiamato: Single-Stepping. La modalità Single-Step [ NdT tradotto letteralmente significa "singolo passo", ovvero quello che effettua il processo di debug con il debugge ] è fornita dalla CPU stessa. L'ottavo bit del flag register è chiamato trap flag. Se questo flag ( bit ) è stato impostato, la CPU viene eseguita in modalità single-step. La CPU genererà un eccezione di debug dopo ogni istruzione. Dopo che l'eccezione di debug è stata generata, il trap flag viene cancellato automaticamente. Nel debuggee noi possiamo fare anche un single-step usando le API Win32 di Debug. I passi sono i seguenti:
- Chiamare GetThreadContext, specificando CONTEXT_CONTROL in ContextFlag, per ottenere il valore del flag register;
- Impostare il bit trap nel membro regFlag della struttura CONTEXT;
- Chiamare SetThreadContext;
- Come al solito attendere gli eventi di debug. Il debuggee sarà eseguito nella modalità single-step. Dopo che ogni istruzione viene eseguita, avremo un EXCEPTION_DEBUG_EVENT con il valore EXCEPTION_SINGLE_STEP in u.Exception.pExceptionRecord.ExceptionCode;
- Se c'è bisogno di tracciare la prossima istruzione, bisogna impostare di nuovo il bit trap.
Esempio
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\user32.lib
.data
AppName db "Win32 Debug Example no.4",0
ofn OPENFILENAME <>
FilterString db "Executable Files",0,"*.exe",0
db "All Files",0,"*.*",0,0
ExitProc db "The debuggee exits",0Dh,0Ah
db "Total Instructions executed : %lu",0
TotalInstruction dd 0
.data?
buffer db 512 dup(?)
startinfo STARTUPINFO <>
pi PROCESS_INFORMATION <>
DBEvent DEBUG_EVENT <>
align dword
context CONTEXT <>
.code
start:
mov ofn.lStructSize,SIZEOF ofn
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.lpstrFile, OFFSET buffer
mov ofn.nMaxFile,512
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
invoke GetOpenFileName, ADDR ofn
.if eax==TRUE
invoke GetStartupInfo,addr startinfo
invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi
.while TRUE
invoke WaitForDebugEvent, addr DBEvent, INFINITE
.if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
invoke wsprintf, addr buffer, addr ExitProc, TotalInstruction
invoke MessageBox, 0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION
.break
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
mov context.ContextFlags, CONTEXT_CONTROL
invoke GetThreadContext, pi.hThread, addr context
or context.regFlag,100h
invoke SetThreadContext,pi.hThread, addr context
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
.continue
.elseif DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_SINGLE_STEP
inc TotalInstruction
invoke GetThreadContext,pi.hThread,addr context or context.regFlag,100h
invoke SetThreadContext,pi.hThread, addr context
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,DBG_CONTINUE
.continue
.endif
.endif
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
.endw
.endif
invoke CloseHandle,pi.hProcess
invoke CloseHandle,pi.hThread
invoke ExitProcess, 0
end start
Analisi
Il programma mostra la dialog box per aprire il file. Quando l'utente sceglie un file eseguibile, quest'ultimo viene eseguito in modalità single-step, contando il numero di istruzioni eseguite fino a quando il programma non esce.
Cogliamo questa occasione per impostare il debuggee in modalità single-step. Ricorda che Windows invia un EXCEPTION_BREAKPOINT non appena che la prima istruzione del debuggee venga eseguita.
invoke GetThreadContext, pi.hThread, addr context
Chiamiamo GetThreadContext per riempire la struttura CONTEXT con i valori contenuti nei registri del debuggee. Più precisamente, abbiamo bisogno del valore corrente nel flag register.
Settiamo il bit trap ( 8° bit ) nell'image del registro flag.
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
.continue
Poi chiamiamo SetThreadContext per sovrascrivere il valore nella struttura CONTEXT con un nuovo valore o più, e chiamiamo ContinueDebugEvent con il flag DBG_CONTINUE per riprendere il debuggee.
inc TotalInstruction
Quando viene eseguita un istruzione nel debugge, riceviamo un EXCEPTION_DEBUG_EVENT. Dobbiamo così esaminare il valore di u.Exception.pExceptionRecord.ExceptionCode. Se il valore è EXCEPTION_SINGLE_STEP, allora viene generato questo evento di debug a causa della modalità single-step. In questo caso, noi siamo in grado si incrementare la variabile TotalInstruction di uno perchè sappiamo per certo che è stata eseguita un istruzione nel debuggee.
invoke SetThreadContext,pi.hThread, addr context
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,DBG_CONTINUE
.continue
Poichè il trap flag viene cancellato dopo che viene generata un'eccezione di debug, dobbiamo impostare di nuovo il trap flag se vogliamo continuare in modalità single-step.
Attenzione: Non usate l'esempio in questo tutorial con programmi grandi: il tracing è LENTO. Potrebbe essere necessario attendere una decina di minuti prima di poter chiudere il debuggee.
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.