Tutorial 28: Win32 Debug API Teil 1
In diesem Tutorial werden Sie lernen, was Win32 Entwicklern an Debugging-Möglichkeiten bietet. Sie werden wissen, wie Sie ein Programm debuggen können, wenn Sie mit diesem Tutorial durch sind.
Laden Sie das Beispiel herunter.
Theorie:
Win32 hat verschiedene APIs, welche dem Programmierer es erlauben ein wenig die Macht eines Debuggers zu benutzen. Sie werden Win32 Debug APIs oder ähnlich gennant. Mit ihnen können Sie:
- ein Programm laden oder an ein laufendes Programm sich anhängen, um es zu debuggen.
- Low-Level Informationen über das Programm, dass Sie debuggen herausfinden, so wie Prozess ID, Adresse des Einsprungspunkt, und so weiter.
- Debugging-relevante Ereignisse bemerken, wie wenn ein Prozess/Thread startet/endet, DLLs geladen werden/entfernt werden, etc.
- Den Prozess/Thread, der debugged wird, modifizieren.
Kurz gesagt, Sie können einen einfachen Debugger mit diesen APIs programmieren. Da dieses Thema sehr umfassend ist, werde ich es in verschiedene Teile teilen: Dieses Tutorial beginnt mit dem erste Teil. Ich werde die Basis-Konzepte und das generelle Framework erklären, um Win32 Debug APIs nutzen zu können.
Die Schritte, um das Win32 Debug API zu nutzen, sind:
- Erzeugen Sie einen Prozess oder hängen Sie ihr Programm an einen laufenden Prozess. .
Das ist der erste Schritt um die Win32 Debug APIs zu nutzen. Da sich Ihr Programm wie ein Debugger verhält, brauchen Sie ein Programm zum debuggen. Das Programm das debugged wird wird auch Debuggee genannt. Sie können ein Debugge auf zwei Arten erhalten:
- Sie erzeugen selbst einen Prozess mit CreateProcess . Um einen Prozess zum debuggen zu erstellen, müssen Sie das DEBUG_PROCESS
Flag spezifizieren. Dieses Flag teil Windows mit, dass wir den Prozess debuggen wollen. Windows wird dann Benachrichtigungen wichtiger Debugging-relevanten Ereignisse (Debug-Ereignisse), die im Debugge auftreten, an ihr Programm leiten. Der Debuggee Prozess wird unverzüglich angehalten, bis Ihr Programm fertig ist. Wenn der Debuggee Prozess auch Child-Prozesse erzeugt hat, wird Windows auch Debug-Ereignisse, die in Child-Prozessen auftreten, an Ihr Programm weiterleiten. Dieses Verhalten ist in der Regel unbefriedigend. Sie können dieses Verhalten unterbinden, indem Sie das DEBUG_ONLY_THIS_PROCESS
Flag in Kombination mit dem DEBUG_PROCESS
Flag angeben.
- Sie können mit DebugActiveProcess Ihr Programm an einen laufenden Prozess anhängen.
- Auf Debug-Ereignisse warten . Nachdem Ihr Programm ein Debuggee hat, wird der Haupt-Thread des Debuggee's angehalten und zwar so lange, bis Ihr Programm WaitForDebugEvent aufruft.
Diese Funktion arbeitet wie die anderen WaitForXXX-Funktionen, z.B. wird der aufrufende Thread geblockt, bis das Ereigniss, auf das gewartet wird, auftritt. In diesem Fall, wird auf ein Debug-Ereignis von Windows gewartet. Schauen wir uns die Definition an:
WaitForDebugEvent proto lpDebugEvent:DWORD, dwMilliseconds:DWORD
lpDebugEvent
ist die Adresse einer DEBUG_EVENT Struktur, die mit den Informationen über das Debug-Ereigniss gefüllt wird, welches im Debuggee auftritt.
dwMilliseconds
ist die Zeitspanne in Millisekunden, die die Funktion auf das Debug-Ereignis wartet. Wenn diese Spanne überschritten wurde und kein Debug-Ereignis aufgetreten ist, kehrt
WaitForDebugEvent zum Aufrufer zurück. Wenn Sie andererseits aber, INFINITE als Parameter angeben, wird die Funktion so lange nicht zurückkehren, bis ein Debug-Ereignis aufgetreten ist.
Nehmen wir die DEBUG_EVENT Struktur genauer unter die Lupe.
DEBUG_EVENT STRUCT
dwDebugEventCode dd ?
dwProcessId dd ?
dwThreadId dd ?
u DEBUGSTRUCT
DEBUG_EVENT ENDS
dwDebugEventCode
enthält den Wert, der die Art des Debug-Ereignisses näher spezifiziert. Kurz gesagt gibt es jede Menge Arten von Ereignissen, Ihr Programm muss den Wert in diesem Feld überprüfen um zu wissen welche Art von Debug-Ereigniss aufgetreten ist, um angemessen zu reagieren. Mögliche Werte sind:
Value |
Meanings |
CREATE_PROCESS_DEBUG_EVENT |
Ein Prozess wurde erzeugt. Dieses Ereigniss wird gesendet, wenn der Debuggee Prozess (und noch nicht läuft) oder wenn das Programm sich selbst an einen laufenden Prozess mit DebugActiveProcess hängt.
Das wird das erste Ereigniss sein, dass Ihr Programm erhalten wird. |
EXIT_PROCESS_DEBUG_EVENT |
Ein Prozess wird beendet. |
CREATE_THEAD_DEBUG_EVENT |
Ein neuer Thread ist innerhalb des Debuggee-Prozesses erzeugt worden oder Ihr Programm hängt sich selbst das erste Mal in einen laufenden Prozess. Beachten Sie, dass Sie diese Benachrichtigung nicht erhalten, wenn der Haupt-Thread des Debuggee erzeugt wird. |
EXIT_THREAD_DEBUG_EVENT |
Ein Thread in dem Debuggee-Prozess wird beendet. Ihr Programm wird dieses Ereigniss nicht empfangen, wenn es sich dabei um den Haupt-Thread handelt. Sie können sich den Haupt-Thread des Debuggee auch als den Debuggee-Prozess an sich vorstellen. Wenn Ihr Programm also CREATE_PROCESS_DEBUG_EVENT erhält, ist es für den Haupt-Thread eigentlich CREATE_THREAD_DEBUG_EVENT . |
LOAD_DLL_DEBUG_EVENT |
Das Debuggee lädt eine DLL. Sie erhalten dieses Ereigniss, wenn der PE-Loader das erste Mal die Links auf die DLLs auflöst (Sie rufen CreateProcess auf, um das Debuggee zu laden) und wenn das Debuggee LoadLibrary aufruft. |
UNLOAD_DLL_DEBUG_EVENT |
Eine DLL wird vom Debuggee-Prozess aus dem Speicher entfernt. |
EXCEPTION_DEBUG_EVENT |
Eine Exception tritt in dem Debuggee-Prozess auf.Wichtig: Dieses Ereignis tritt einmal auf, genau bevor das Debuggee mit der Ausführung des ersten Befehls beginnt. Die Exception ist tatsächlich ein Debug-Break (int 3h). Wenn Sie das Debuggee fortsetzen wollen, rufen Sie ContinueDebugEvent
mit DBG_CONTINUE als Parameter auf.
Benutzen Sie nicht DBG_EXCEPTION_NOT_HANDLED
da das Debuggee ansonsten unter NT nicht laufen wird (unter Win98 läuft es einwandfrei). |
OUTPUT_DEBUG_STRING_EVENT |
Dieses Ereigniss wird generiert, wenn das Debuggee die DebugOutputString Funktion aufruft, um einen Nachrichten-String an Ihr Programm zu senden.
|
RIP_EVENT |
Ein System debugging Fehler ist aufgetreten. |
dwProcessId
und dwThreadId sind der Prozess und die Thread-ID des Prozesses, welcher die Debug-Ereignisse erzeugt hat. Sie können diese Werte benutzen, als Identifizierer des Prozesses/Threads benutzen, in dem Sie interessiert sind. Beachten Sie, dass wenn Sie CreateProcess benutzen, um das Debuggee zu laden, bekommen Sie ebenfalls die Prozess und Thread ID des Debuggee in der PROCESS_INFO
Struktur. Sie können diese Werte dazu benutzen, um zwischen den Debug-Ereignissen im Debuggee und seinen Child-Prozessen zu unterscheiden (für den Fall, dass Sie nicht
DEBUG_ONLY_THIS_PROCESS spezifiziert haben).
u
ist eine Union, die mehr über das Debug-Ereigniss enthält. Es kann eine der folgenden Strukturen sein, abhängig von dem Wert in dwDebugEventCode .
Wert in dwDebugEventCode |
Interpretation von u |
CREATE_PROCESS_DEBUG_EVENT |
Eine CREATE_PROCESS_DEBUG_INFO
Struktur namens CreateProcessInfo |
EXIT_PROCESS_DEBUG_EVENT |
Eine EXIT_PROCESS_DEBUG_INFO Struktur namens
ExitProcess
|
CREATE_THREAD_DEBUG_EVENT |
Eine CREATE_THREAD_DEBUG_INFO
Struktur namens CreateThread |
EXIT_THREAD_DEBUG_EVENT |
Eine EXIT_THREAD_DEBUG_EVENT
Struktur namens ExitThread |
LOAD_DLL_DEBUG_EVENT |
Eine LOAD_DLL_DEBUG_INFO
Structur namens LoadDll |
UNLOAD_DLL_DEBUG_EVENT |
Eine UNLOAD_DLL_DEBUG_INFO
Struktur namens UnloadDll |
EXCEPTION_DEBUG_EVENT |
Eine EXCEPTION_DEBUG_INFO
Struktur namens Exception |
OUTPUT_DEBUG_STRING_EVENT |
Eine OUTPUT_DEBUG_STRING_INFO
Struktur namens DebugString |
RIP_EVENT |
Eine RIP_INFO
Struktur namens RipInfo |
Ich werde hier nicht weiter ins Detail bei den einzelnen Strukturen gehen, nur die CREATE_PROCESS_DEBUG_INFO
Struktur soll hier angesprochen werden.
Angenommen, unser Programm ruft WaitForDebugEvent auf und kehrt zurück. Das erste was wir machen sollten, ist den Wert in dwDebugEventCode untersuchen, um zu sehen, was für Art von Debug-Ereigniss im Debuggee-Prozess aufgetreten ist. Wenn der Wert in dwDebugEventCode zum Beispiel gleich CREATE_PROCESS_DEBUG_EVENT ist, können Sie das Element in u als CreateProcessInfo interpretieren und mit u.CreateProcessInfo drauf zugreifen.
- Machen Sie was Ihr Programm auch machen will, um auf ein Debug-Ereigniss zu antworten .
Wenn WaitForDebugEvent zurückkehrt, bedeutet das, dass gerade ein Debug-Ereigniss im Debuggee-Prozess oder ein Timeout aufgetreten ist. Ihr Programm muss den Wert in dwDebugEventCode untersuchen, um angemessen auf das Ereigniss zu reagieren. In dieser Hinsicht, ist wie das Bearbeiten von Windows-Nachricht: einige bearbeiten Sie und andere ignorieren Sie.
- Lassen Sie das Debuggee seine Ausführung fortfahren . Wenn ein Debug-Ereignis auftritt, hält Windows das Debuggee an. Wenn Sie fertig mit der Ereigniss-Behandlung sind, müssen Sie das Debuggee wieder starten. Das machen Sie, indem Sie die ContinueDebugEvent
Funktion aufrufen.
ContinueDebugEvent proto ProcessId:DWORD, dwThreadId:DWORD, dwContinueStatus:DWORD
Diese Funktion setzt den Thread fort, der zuvor auf Grund eines Debug-Ereignisses angehalten wurde.
dwProcessId und dwThreadId
sind die Prozess und Thread IDs des Threads, der fortgesetzt wird. Normalerweise nehmen Sie diese Werte aus den dwProcessId
und dwThreadId Elementen der DEBUG_EVENT
Struktur.
dwContinueStatus spezifiziert wie der Thread, in dem das Debug-Ereigniss aufgetreten ist, fortgesetzt werden soll. Es gibt zwei mögliche Werte: DBG_CONTINUE
und DBG_EXCEPTION_NOT_HANDLED . Für alle anderen Debug-Ereignisse machen diese beiden Werte das Selbe: den Thread fortsetzen.
Die Exception ist das EXCEPTION_DEBUG_EVENT .
Wenn der Thread ein Exception-Debug-Ereigniss berichtet, bedeutet das, dass eine Exception in dem Debuggee aufgetreten ist. Wenn Sie DBG_CONTINUE spezifizieren, wird der Thread sein eigenes Exception-Handling ignorieren und mit der Ausführung fortfahren. In diesem Szenario muss Ihr Programm selbst die Exception untersuchen und lösen, bevor der Thread mit DBG_CONTINUE fortgesetzt wird, ansonsten wird die Exception immer wieder und wieder und wieder... auftreten. Wenn Sie DBG_EXCEPTION_NOT_HANDLED spezifizieren, teilt Ihr Programm Windows mit, dass es die Exception nicht behandelt: Windows soll den Standard-Exception-Handler benutzen, um die Exception zu behandeln.
Zusammgefasst kann man sagen, dass, wenn das Debug-Ereignis sich auf eine Exception im Debuggee-Prozess bezieht, sollten Sie ContinueDebugEvent
mit DBG_CONTINUE aufrufen, wenn Ihr Programm schon den Grund der Exception entfernt hat. Ansonsten muss Ihr Programm ContinueDebugEvent
mit DBG_EXCEPTION_NOT_HANDLED aufrufen.
Außer in einem Fall, wo Sie immer DBG_CONTINUE
benutzen müssen: das erste EXCEPTION_DEBUG_EVENT
welches den Wert EXCEPTION_BREAKPOINT
im ExceptionCode Element hat. Wenn das Debuggee seinen aller ersten Befehl ausführt, wird Ihr Programm das Exception-Debug-Ereigniss erhalten. Eigentlich ist es ein Debug-Break (int 3h). Wenn Sie als Anwort ContinueDebugEvent
mit DBG_EXCEPTION_NOT_HANDLED aufrufen, wird Windows NT sich weigern, das Debuggee laufen zu lassen (da sich keiner drum kümmert). Sie müssen immer DBG_CONTINUE in einem solchen Fall benutzen, um Windows mitzuteilen, dass Sie den Thread fortsetzen möchten.
- Wiederholen Sie diesen Zyklus in einer Endlos-Schleife, bis der Debuggee-Prozess beendet wird .
Ihr Programm muss in einer Endlos-Schleife sein, ähnlich wie bei der Message-Loop, bis das Debuggee beendet wird. Die Schleife sieht ungefähr so aus:
.while TRUE
invoke WaitForDebugEvent, addr DebugEvent, INFINITE
.break .if DebugEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
<Behandel Debug-Ereignisse>
invoke ContinueDebugEvent, DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
.endw
Das liegt am folgenden: Wenn Sie ein Programm angefangen haben zu debuggen, kommen Sie nur davon wieder los, wenn das Debuggee beendet wird.
Lassen Sie uns die Schritte noch einmal zusammefassen:
- Erzeugen eines Prozesses oder hängen Sie Ihr Programm an einen laufenden Prozess .
- Auf Debug-Ereignisse warten .
- Machen Sie was Ihr Programm auch machen will, um auf ein Debug-Ereigniss zu antworten .
- Lassen Sie das Debuggee seine Ausführung fortfahren .
- Wiederholen Sie diesen Zyklus in einer Endlos-Schleife, bis der Debuggee-Prozess beendet wird
Beispiel:
Dieses Beispiel debugged ein Win32 Programm und zeigt wichtige Informationen wie Prozess-Handle, Prozess-ID und so weiter an.
.386
.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.1",0
ofn OPENFILENAME
FilterString db "Executable Files",0,"*.exe",0
db "All Files",0,"*.*",0,0
ExitProc db "The debuggee exits",0
NewThread db "A new thread is created",0
EndThread db "A thread is destroyed",0
ProcessInfo db "File Handle: %lx ",0dh,0Ah
db "Process Handle: %lx",0Dh,0Ah
db "Thread Handle: %lx",0Dh,0Ah
db "Image Base: %lx",0Dh,0Ah
db "Start Address: %lx",0
.data?
buffer db 512 dup(?)
startinfo STARTUPINFO
pi PROCESS_INFORMATION
DBEvent DEBUG_EVENT
.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 MessageBox, 0, addr ExitProc, addr AppName, MB_OK+MB_ICONINFORMATION
.break
.elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
invoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFile, DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread, DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartAddress
invoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
.continue
.endif
.elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION
.endif
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
.endw
invoke CloseHandle,pi.hProcess
invoke CloseHandle,pi.hThread
.endif
invoke ExitProcess, 0
end start
Analyse:
Das Programm füllt die OPENFILENAME Struktur und ruft dann GetOpenFileName auf, um den Benutzer das gewählte Programm zu debuggen.
invoke GetStartupInfo,addr startinfo
invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi
Wenn der Benutzer eins auswählt, wird CreateProcess
aufgerufen, um das Programm zu laden. Danach wird GetStartupInfo aufrgerufen, um die STARTUPINFO Struktur mit den Standard-Werten zu belegen. Beachten Sie, dass wir DEBUG_PROCESS benutzen, kombiniert mit DEBUG_ONLY_THIS_PROCESS um nur dieses Programm zu debuggen und nicht seine Child-Prozesse.
.while TRUE
invoke WaitForDebugEvent, addr DBEvent, INFINITE
Wenn das Debuggee geladen ist, betreten wir eine Endlos-Debug-Schleife, indem wir WaitForDebugEvent aufrufen.
WaitForDebugEvent wird solange nicht zurückkehren, bis ein Debug-Ereignis im Debuggee auftritt, da wir INFINITE als zweiten Parameter angegeben haben. Wenn ein Debug-Ereignis auftritt, kehrt WaitForDebugEvent
zurück und DBEvent wird mit den Informationen über das Debug-Ereigniss gefüllt.
.if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
invoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK+MB_ICONINFORMATION
.break
Als erstes überprüfen wir den Wert in dwDebugEventCode .
Wenn er gleich EXIT_PROCESS_DEBUG_EVENT ist, zeigen wir eine MessageBox an, die "The debuggee exits" enthält und springen aus der Debug-Loop.
.elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
invoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFile, DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread, DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartAddress
invoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION
Wenn der Wert in dwDebugEventCode
gleich CREATE_PROCESS_DEBUG_EVENT ist, dann zeigen wir verschiedene interessante Informationen über das Debuggee in einer MessageBox an. Wir erhalten diese Informationen von u.CreateProcessInfo .
CreateProcessInfo ist eine Struktur des Typen CREATE_PROCESS_DEBUG_INFO .
Sie können mehr über diese Struktur in der Win32 API Referenz erfahren.
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
.continue
.endif
Wenn der Wert in dwDebugEventCode
gleich EXCEPTION_DEBUG_EVENT ist, müssen wir weitere Überprüfungen vornehmen, um den genauen Typen der Exception zu ermitteln. Es ist eine lange Reihe an verschachtelten Struktur-Referenzen, aber Sie können die Art der Exception aus dem ExceptionCode
Element erhalten. Wenn der Wert in ExceptionCode gleich
EXCEPTION_BREAKPOINT ist und es das erste Mal auftritt (oder wir sicher sind, dass kein int 3h im Debuggee vorkommt), können wir sicher sein, dass diese Exception aufgetreten ist, als das Debuggee seinen ersten Befehl ausgeführt hat. Wenn wir mit der Bearbeitung fertig sind, müssen wir ContinueDebugEvent mit dem DBG_CONTINUE
Flag aufrufen, um das Debuggee weiterlaufen zu lassen. Dann gehen wir zurücl und warten auf das nächste Debug-Ereignis.
.elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION
.endif
Wenn der Wert in dwDebugEventCode
gleich CREATE_THREAD_DEBUG_EVENT oder EXIT_THREAD_DEBUG_EVENT ist,
zeigen wir eine Message Box an, die das mitteilt.
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
.endw
Außer für den
EXCEPTION_DEBUG_EVENT Fall oben, rufen wir ContinueDebugEvent
mit dem DBG_EXCEPTION_NOT_HANDLED Flag auf, um das Debuggee fortzusetzen.
invoke CloseHandle,pi.hProcess
invoke CloseHandle,pi.hThread
Wenn das Debuggee sich beendet, verlassen wir die Debug-Loop und müssen beides Prozess- und Thread-Handle des Debuggee schließen. Schließen der Handle bedeutet nicht, dass der Prozess/Thread gekillt wird. Es bedeutet nur, dass wir die Handles nicht mehr benutzen wollen, um auf den Prozess/Thread zuzugreifen.
Deutsche Übersetzung: Joachim Rohde
Die original Win32Asm-Tutorials stammen von Iczelion's Win32 Assembly HomePage