刘收获

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

minidebug学习分析 01 基本框架

0x01  基本框架

    基本框架就是CreateProcess启动目标程序,再通过调试事件DEBUG_EVENT在调试循环中监控程序的行为。

    (1)CreatProcess  

1
2
3
4
5
6
BOOL CreateProcess(
LPCTSTR lpApplicationName, // 要创建的进程模块名 <br>LPTSTR lpCommandLine, // 命令行字符串
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全属性 <br>LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性 <br>BOOL bInheritHandles, // 句柄继承选项
DWORD dwCreationFlags, // 进程创建选项
LPVOID lpEnvironment, // 进程环境块数据指针 <br>LPCTSTR lpCurrentDirectory, // 当前目录名 <br>LPSTARTUPINFO lpStartupInfo, // 启动信息
LPPROCESS_INFORMATION lpProcessInformation // 进程信息<br> );

  双击一个EXE可执行文件时,Windows内核也就会自动调用CreatProcess  函数创建我们双击的文件所对应的进程。

  CreateProcess函数的第六个成员dwCreationFlags进程创建选项,指明了要如何创建目标进程,在minidebug中,它指定的是DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE | CREATE_SUSPENDED。

  DEBUG_ONLY_THIS_PROCESS表明调用CreateProcess的进程成为调试器,而它启动的子进程成为被调试的进程。DEBUG_ONLY_THIS_PROCESS与DEBUG_PROCESS的不同在于:DEBUG_PROCESS会调试被调试进程以及它的所有子进程,而DEBUG_ONLY_THIS_PROCESS只调试被调试进程,不调试它的子进程。

  CreateProcess函数的最后一个成员LPPROCESS_INFORMATION指向一个进程信息结构体PROCESS_INFORMATION,进程创建后的相关信息会放到PROCESS_INFORMATION信息块中:

  LPPROCESS_INFORMATION结构: 

1
2
3
4
5
6
typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

  启动被调试进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
STARTUPINFO StartupInfo = { 0 };
    StartupInfo.cb = sizeof(STARTUPINFO);
 
    PROCESS_INFORMATION ProcessInfo = { 0 };
 
    if (CreateProcess(
        Command[1].c_str(),
        NULL,
        NULL,
        NULL,
        FALSE,
        DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE | CREATE_SUSPENDED,
        NULL,
        NULL,
        &StartupInfo,
        &ProcessInfo) == FALSE) {
 
        std::wcout << TEXT("CreateProcess Failed") << GetLastError() << std::endl;
        return;
    }
 
    __ProcessHandle = ProcessInfo.hProcess;
    __ThreadHandle = ProcessInfo.hThread;
    __ProcessID = (HANDLE)ProcessInfo.dwProcessId;
    __ThreadID  = (HANDLE)ProcessInfo.dwThreadId;
 
    __DebuggerStatus = STATUS_SUSPENDED;

  

 

  (2)调试循环DEBUG LOOP监控调试事件DEBUG_EVENT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
void OnGo(const CommandVector& Commmd)
{
    //SetSingleInstruction(FALSE);
 
    if (Commmd.size() < 2)
    {
        HandledException(FALSE);   //g   调试器未处理异常
        ContinueDebugSession();    //
        return;
    }
     
          ......
}
 
 
void ContinueDebugSession() {
 
    if (__DebuggerStatus == STATUS_NONE) {
 
        std::wcout << TEXT("Debuggee Is Not Started Yet") << std::endl;
        return;
    }
 
    if (__DebuggerStatus == STATUS_SUSPENDED) {
 
        ResumeThread(__ThreadHandle);
    }
    else {
 
        ContinueDebugEvent(
            (DWORD)__ProcessID,
            (DWORD)__ThreadID,
            __AlwaysContinue == TRUE ? DBG_CONTINUE : __ContinueStatus);
 
        __AlwaysContinue = FALSE;
    }
 
    DEBUG_EVENT DebugEvent;
 
    while (WaitForDebugEvent(&DebugEvent, INFINITE) == TRUE)
    {
 
        if (DispatchDebugEvent(&DebugEvent) == TRUE) {
 
            ContinueDebugEvent((DWORD)__ProcessID, (DWORD)__ThreadID, __ContinueStatus);
        }
        else {
 
            break;
        }
    }
}

  

  1>调试事件DEBUG_EVENT

   结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct _DEBUG_EVENT {
    DWORD dwDebugEventCode;
    DWORD dwProcessId;
    DWORD dwThreadId;
    union {
        EXCEPTION_DEBUG_INFO Exception;
        CREATE_THREAD_DEBUG_INFO CreateThread;
        CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
        EXIT_THREAD_DEBUG_INFO ExitThread;
        EXIT_PROCESS_DEBUG_INFO ExitProcess;
        LOAD_DLL_DEBUG_INFO LoadDll;
        UNLOAD_DLL_DEBUG_INFO UnloadDll;
        OUTPUT_DEBUG_STRING_INFO DebugString;
        RIP_INFO RipInfo;
    } u;
} DEBUG_EVENT, *LPDEBUG_EVENT;

  调试事件是被调试进程让系统通知调试器的事件,它包含了创建进程、创建线程、加载DLL、卸载DLL、发送输出字符串、发生异常等。如果调试器等待调试事件时刚好发生了一个调试事件,系统将填写WaitForDebugEvent函数的DEBUG_EVENT结构体的相关调试信息。 当系统通知调试器调试事件时,同时会挂起相关进程的所有线程,直到调试器使用ContinueDebugEvent继续调试事件时,被挂起的线程才继续执行。当进程被调试时,后续的调试事件也可能发生。

  调试事件的具体含义可见:http://blog.csdn.net/wlsgzl/article/details/18629635

   

  2>WaitForDebugEvent与ContinueDebugEvent

     

1
2
3
4
5
6
BOOL WaiteForDebugEvent(
LPDEBUG_EVENT _DEBUG_EVENT, 
//指向调试事件的指针
DWORD dwMilliseconds
//等待事件的毫秒数
)

  

1
2
3
4
5
BOOL ContinueDebugEvent(
 DWORD dwProcessId,          // 目标进程ID
DWORD dwThreadId,            // 目标线程ID
DWORD dwContinueStatus    // 线程继续的标志
 );

  目标进程ID和目标线程ID这就是CreateProcess调用后,ProcessInfo结构中所包含的信息。该函数通过目标进程/线程ID来唯一标识目标进/线程,并且通过设置不同的ContinueStatus来通知目标进/线程继续运行的动作。

  第三成员最主ContinueStatus有两个值可供设定:一个是DBG_CONTINUE,表明调试事件已经被Debugger处理完毕,目标进/线程可以照常继续运行;另一个是DBG_EXCEPTION_NOT_HANDLED,表明Debugger并未处理该调试事件,目标进程收到该标志位后,将会将调试事件沿着Windows异常调用链继续往下发送。直至该调试事件被处理完为止——当然,如果目标进程发出的Debug Event没有任何调试器能够处理,那最后Windows只有祭出自己的杀手锏:应用程序XXX异常,即将被关闭。

posted on   沉疴  阅读(464)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示