0x00 调试函数
DebugActiveProcess() //使调试器能够附加到活动进程并对其进行调试
DebugActiveProcessStop() //阻止调试器调试指定的进程
ContinueDebugEvent() //使调试器能够继续以前报告调试事件的线程
DebugBreak() //导致当前进程中出现断点异常
DebugBreakProcess() //导致指定进程中发生断点异常。这允许调用线程向调试器发出信号以处理异常。
FatalExit() //将执行控制传输到调试器。此后调试器的行为是特定于所使用的调试器类型的。
FlushInstructionCache() //将指令缓存刷新为指定的进程。
GetThreadContext() //检索指定线程的上下文。
GetThreadSelectorEntry() //检索指定选择器和线程的描述符表项。
IsDebuggerPresent() //确定调用进程是否由用户模式调试器调试.
OutputDebugString() //将字符串发送到调试器以供显示。
ReadProcessMemory() //读取指定进程某区域的数据
SetThreadContext() //设置指定线程的上下文。
WaitForDebugEvent() //等待正在调试的进程中发生调试事件。
WriteProcessMemory() //将数据写入指定进程中的内存区域。要写入的整个区域必须是可访问的,否则操作失败。
0x01 BOOL WaitForDebugEvent( LPDEBUG_EVENT lpDebugEvent, DWORD dwMilliseconds )
参数1 指向DEBUG_EVENT结构的指针,该结构接收有关调试事件的信息
参数2 等待调试事件的毫秒数。如果此参数为零,则函数将测试调试事件并立即返回。如果参数是无限的,则在调试事件发生之前,函数不会返回
返回值 如果函数成功,则返回值为非零。如果函数失败,则返回值为零。要获得扩展错误信息,请调用GetLastError
目标进程中发生一个调试事件后,系统将通知调试器来处理,调试器通过WaitForDebugEvent函数获取目标进程的相关环境信息
。
DEBUG_EVENT –> 描述调试事件。其成员dwDebugEventCode描述了事件类型
https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-debug_event
0x02 进程调试方式
1调用CreateProcess函数创建进程
如果将dwCreationFlags标志字段设置为DEBUG_PROCESS或DEBUG_ONLY_THIS_PROCESS
则创建一个用于调试的进程
DEBUG_PROCESS -> 调用线程启动并调试新进程和由新进程创建的所有子进程。它可以使用WaitForDebugEvent函数接收所有相关的调试事件。使用DEBUG_Process的进程将成为调试链的根。这种情况一直持续到使用DEBUG_Process创建链中的另一个进程为止。
如果此标志与DEBUG_ONLY_THIS_PROCESS相结合,则调用方只调试新进程,而不是任何子进程
DEBUG_ONLY_THIS_PROCESS –> 调用线程启动并调试新进程。它可以使用WaitForDebugEvent函数接收所有相关的调试事件
2 调用DebugActiveProcesss函数可以将调试器捆绑到另一个正在运行的进程上
NT -> 试图通过DebugActiveProcesss函数将调试器绑定到一个创建时带有安全描述符的进程上时,将会失败
Windows 9.x -> 当指定了一个无效的进程标识符时,调用失败
0x03 代码
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
BOOL ProcessExist = FALSE; //标识进程是否退出
DWORD WINAPI ProcessWatch(_In_ LPVOID lpParameter)
{
printf("ProcessWatch -> start\n");
WaitForSingleObject(lpParameter, INFINITE); //等待进程退出
printf("ProcessWatch -> end\n");
ProcessExist = FALSE;
return 0;
}
int _tmain(int argc, TCHAR* argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
DEBUG_EVENT debugEvent = { 0 };
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (argc != 2)
{
printf("Usage: %ws [cmdline]\n", argv[0]);
return 0;
}
//创建进程
if (CreateProcess(NULL, argv[1], NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi))
{
printf("CreateProcess success\n");
//创建监听线程,监听进程退出
if (CreateThread(0, 0, ProcessWatch, pi.hProcess, 0, 0))
{
ProcessExist = TRUE;
printf("Debug Process Start\n");
//进程创建后监听
while (ProcessExist)
{
if (WaitForDebugEvent(&debugEvent, 150))
{
printf("WaitForDebugEvent Success\n");
switch (debugEvent.dwDebugEventCode)
{
//创建进程调试事件
case CREATE_PROCESS_DEBUG_EVENT:
printf("CREATE_PROCESS_DEBUG_EVENT\n");
break;
//退出进程调试事件
case EXIT_PROCESS_DEBUG_EVENT:
printf("EXIT_PROCESS_DEBUG_EVENT\n");
break;
//异常调试事件
case EXCEPTION_DEBUG_EVENT:
printf("EXCEPTION_DEBUG_EVENT\n");
printf("ExceptionCode: %x ; ExceptionAddress: %p \n", debugEvent.u.Exception.ExceptionRecord.ExceptionCode, debugEvent.u.Exception.ExceptionRecord.ExceptionAddress);
if (debugEvent.u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT)
{
ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
continue;
}
break;
//other
default:
printf("default: %x \n", debugEvent.dwDebugEventCode);
break;
}
Sleep(1000);
//恢复线程
ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
}
else
{
//等待超时
printf("WaitForDebugEvent Failed\n");
}
}
printf("Debug Process End\n");
}
//关闭创建进程的句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else
{
printf("CreateProcess failed (%d).\n", GetLastError());
}
return 0;
}
0x04 备注
1发生一个EXCEPTION_NONCONTINUEABLE异常后,如果使徒继续执行,会产生一个EXCEPTION_NONCONTINUABLE_EXCEPTION异常
2 当以调试的方式创建进程时,在进入进程前,系统会执行一次DebugBreak函数,此时会产生一个EXCEPTION_BREAKPOIN异常
3 ContinueDebugEvent函数
参数2 为DBG_CONTINUE时,表示被操作进程本身不进行异常处理,由ContinueDebugEvent调用方处理异常.
参数2为DBG_EXCEPTION_NOT_HANDLE时,表示由操作进程本身进行异常处理