Article ID: 121093
Article Last Modified on 3/15/2004
while( GetMessage(&msg, NULL, NULL, NULL) )
{
TranslateMessage(&msg); /* Translate virtual key codes */
DispatchMessage(&msg); /* Dispatch message to window */
SetLastError( 0 ); /* Set error code to zero */
if( WaitForDebugEvent(&DebugEvent, INFINITE) )
{
/* Process the debug event */
ProcessDebugEvents( &DebugEvent );
}
else
{
if( GetLastError() != 0 )
{
/* Handle error condition. */
}
}
}
HANDLE OpenThread(dwThreadId); DWORD dwThreadId; /* The thread ID */Parameter description:
dwThreadId - Specifies the thread identifier of the thread to open.
If the function succeeds, the return value is an open handle of the specified thread; otherwise, it is NULL. To get extended error information, use the GetLastError() API.
The handle returned by OpenThread() can be used in any function that requires a handle to a thread.
#include <windows.h>
HANDLE WINAPI OpenThread(DWORD dwThreadId)
{
return (HANDLE)NULL;
}
LIBRARY kernel32
DESCRIPTION 'Win32s OpenThread library'
EXPORTS
OpenThread
w32sopth.lib: w32sopth.obj
lib -out:w32sopth.lib -machine:i386 -def:w32sopth.def w32sopth.obj
w32sopth.obj: w32sopth.c
cl /c w32sopth.c
LPDEBUG_EVENT lpEvent; /* Pointer to the debug event structure */
HANDLE hProc; /* Handle to process */
HANDLE hThread; /* Handle to thread */
CONTEXT Context; /* Context structure */;
BYTE bOrgByte; /* Original byte in the place of BP */
DWORD cWritten; /* Number of bytes written to memory */
static DWORD dwBPLoc; /* Breakpoint location */
/*
* Other debugger functions:
*
* LookupThreadHandle -
* Receives a thread ID and returns a handle to the thread, if
* the thread created by the debugger, else returns NULL.
*/
HANDLE LookupThreadHandle(DWORD);
/*
* LookupOriginalBPByte -
* Receives an address of a breakpoint and returns the original
* contents of the memory in the place of the breakpoint.
* The memory contents is returned in the byte buffer passed as
* a parameter.
* Return value - If the breakpoint was set by the debugger the
* return value is TRUE, else FALSE.
*/
BOOL LookupOriginalBPByte( LPVOID, LPBYTE );
/* Handle debug events according to event types */
switch( lpEvent->dwDebugEventCode )
{
/* ... */
case EXCEPTION_DEBUG_EVENT:
/* Handle exception debug events according to exception type */
switch( lpEvent->u.Exception.ExceptionRecord.ExceptionCode )
{
/* ... */
case EXCEPTION_BREAKPOINT:
/* Breakpoint exception */
/* Look for the thread handle in the debugger tables */
hThread = LookupThreadHandle( lpEvent->dwThreadId );
if( hThread == NULL )
{
/* Not a debuggee */
/* Get process and thread handles */
hProc = OpenProcess( 0, FALSE, lpEvent->dwProcessId );
hThread = OpenThread( lpEvent->dwThreadId );
/* Get the full context of the processor */
Context.ContextFlags = CONTEXT_FULL;
GetThreadContext( hThread, &Context );
/* We get the exception after executing the INT 3 */
dwBPLoc = --Context.Eip;
/* Restore the original byte in memory in the */
/* place of the breakpoint */
if( !LookupOriginalBPByte((LPVOID)dwBPLoc, &bOrgByte) )
{
/* Handle unfamiliar breakpoint */
}
else
{
/* Restore memory contents */
WriteProcessMemory( hProc, (LPVOID)dwBPLoc,
&bOrgByte, 1, &cWritten );
/* Set the Single Step bit in EFlags */
Context.EFlags |= 0x0100;
SetThreadContext( hThread, &Context );
}
/* Free Handles */
CloseHandle( hProc );
CloseHandle( hThread );
/* Resume the interrupted process */
ContinueDebugEvent( lpEvent->dwProcessId,
lpEvent->dwThreadId, DBG_CONTINUE );
}
else
{
/* Handle debuggee breakpoint. */
}
break;
case STATUS_SINGLE_STEP:
hThread = LookupThreadHandle( lpEvent->dwThreadId );
if( hThread == NULL )
{
/* Not a debuggee, just executed the original instruction */
/* and returned to the debugger. */
/* Get process handle */
hProc = OpenProcess( 0, FALSE, lpEvent->dwThreadId );
/* Restore the INT 3 instruction in the place of the BP */
bOrgByte = 0xCC;
WriteProcessMemory( hProc, (LPVOID)dwBPLoc,
&bOrgByte, 1, &cWritten );
/* Free Handle */
CloseHandle( hProc );
/* Resume the process */
ContinueDebugEvent( lpEvent->dwProcessId,
lpEvent->dwThreadId, DBG_CONTINUE );
}
else
{
/* Handle debuggee single-step. */
}
break;
/* .... */
}
/* .... */
}
This sample code does not contain code to handle error checking and return
values from APIs. The assumption is that a non-debugged process generates a
single step exception only when it is executing the instruction in the
place of the breakpoint. The code for handling the single step exception
does not handle debug registers.
CONTEXT Context;
LDT_ENTRY SelEntry;
DWORD dwDsBase;
DWORD DR7;
BYTE Buffer[4];
/* Get Context */
Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext( hThread, &Context );
/* Calculate the base address of DS */
GetThreadSelectorEntry(hThread, Context.SegDs, &SelEntry);
dwDsBase = ( SelEntry.HighWord.Bits.BaseHi << 24) |
(SelEntry.HighWord.Bits.BaseMid << 16) |
SelEntry.BaseLow;
/*
* Disable all hardware breakpoints before reading the process
* memory. Not doing so will lead to nested breapoints.
*/
DR7 = Context.Dr7;
Context.Dr7 &= ~0x3FF;
SetThreadContext( hThread, &Context );
/* Read DWORD at the location of DR0 */
ReadProcessMemory( hProcess,
(LPVOID)((DWORD)Context.Dr0-dwDsBase),
Buffer, sizeof(Buffer), NULL);
/* Restore hardware breakpoints */
Context.Dr7 = DR7;
SetThreadContext( hThread, &Context );
Additional query words: 1.10 1.20
Keywords: kbcode KB121093