Windows用户态调试器原理(二)

2014-11-24 08:19:00 · 作者: · 浏览: 1
} u;
} DEBUG_EVENT, *LPDEBUG_EVENT;
处理通知代码如下:
[cpp]
DWORD ProcessEvent(DEBUG_EVENT de)
{
switch(de.dwDebugEvent.Code)
{
case EXCEPTION_DEBUG_EVENT:
{
}
break;
case CREATE_THREAD_DEBUG_EVENT:
{
}
break;
case CREATE_PROCESS_DEBUG_EVENT:
{
}
break;
case EXIT_THREAD_DEBUG_EVENT:
{
}
break;
case EXIT_PROCESS_DEBUG_EVENT:
{
}
break;
case LOAD_DLL_DEBUG_EVENT:
{
}
break;
case OUTPUT_DEBUG_STRING_EVENT:
{
}
break;
......
}
return DBG_CONTINUE;
}
调试事件介绍
OUTPUT_DEBUG_STRING_EVENT事件
很多程序员在调试程序时喜欢将执行的结果或中间步骤输出,用以检查程序执行的正确与否。在很多系统中这是很不方便的。但我们可以使用调试输出命令,将某些需要显示的结果输出到输出窗口中。如 vc的TRACE宏。其实在TRACE宏内部是调用OutputDebugString来实现的 。调试器会把调试目标输出的字符串通过事件处理代码显示出来。在DEBUG_EVENT 结构中有一个DebugString成员。
该结构定义为:
[cpp]
typedef struct _OUTPUT_DEBUG_STRING_INFO {
LPSTR lpDebugStringData;
WORD fUnicode;
WORD nDebugStringLength;
} OUTPUT_DEBUG_STRING_INFO, *LPOUTPUT_DEBUG_STRING_INFO;
在此结构中有一个lpDebugStringData成员,它保存被输出字符串的地址。nDebugStringLength为字符串长度。fUnicode表示是ANSI还是UNICODE字符。
下面为处理OUTPUT_DEBUG_STRING_EVENT事件的代码:
[cpp]
case OUTPUT_DEBUG_STRING_EVENT:
{
OUTPUT_DEBUG_STRING_INFO oi=de.u.DebugString;
WCHAR *msg=ReadRemoteString(调试目标句柄,
oi.lpDebugStringData,oi.nDebugStringLength,oi.fUnicode);
std::wcout<
break;
}
ReadRemoteString是用户自定义函数。在此函数内部是调用ReadProcessMemory从调试目标进程内读取字符串。具体不再介绍。
ReadProcessMemory
读取指定进程的某区域内的数据。
[cpp]
BOOL ReadProcessMemory(HANDLE hProcess, LPCVOID lpBassAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead)
hProcess:进程的句柄
lpBassAddress:欲读取区域的基地址
lpBuffer:保存读取数据的缓冲的指针
nSize:欲读取的字节数
lpNumberOfBytesRead:存储已读取字节数的地址指针
如果函数成功,则返回非零值;如果失败,则返回零
处理EXCEPTION_DEBUG_EVENT事件
当调试目标在调试时发生异常时,操作 系统将会向调试器发送EXCEPTION_DEBUG_EVENT事件通知
当发生此事件时,DEBUG_EVENT结构包含的是一个EXCEPTION_DEBUG_INFO结构。
[cpp]
typedef struct _EXCEPTION_DEBUG_INFO {
EXCEPTION_RECORD ExceptionRecord;
DWORD dwFirstChance;
} EXCEPTION_DEBUG_INFO, *LPEXCEPTION_DEBUG_INFO;
ExceptionRecord成员包含了异常信息的一个副本。如异常码,异常引发地址以及异常参数等。定义如下:
[cpp]
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;
dwFirstChance告诉调试器是否是第一轮通知这个异常。
从操作系统的角度来看,调试器必须