首页 > 其他分享 >10.0 探索API调试事件原理

10.0 探索API调试事件原理

时间:2023-10-03 18:44:30浏览次数:50  
标签:10.0 进程 API 线程 事件 DEBUG EVENT 调试

本章笔者将通过Windows平台下自带的调试API接口实现对特定进程的动态转存功能,首先简单介绍一下关于调试事件的相关信息,调试事件的建立需要依赖于DEBUG_EVENT这个特有的数据结构,该结构用于向调试器报告调试事件。当一个程序发生异常事件或者被调试器附加时,就会产生对应的DEBUG_EVENT调试事件,通常DEBUG_EVENT包含了多种调试类型,包括异常事件、进程创建事件、线程创建事件、进程退出事件和线程退出事件等等,我们只需要动态捕捉这些调试事件并作相应的处理即可实现更多有用的功能。

调试事件通常可以分为如下几种类型;

  • 异常事件 (Exception Event) - 发生了异常,例如访问非法的内存、除以零或调用了无效的函数。
  • 进程创建事件 (Process Creation Event) - 当一个新进程被创建时发送此事件。
  • 进程退出事件 (Process Exit Event) - 当一个进程退出时发送此事件。
  • 线程创建事件 (Thread Creation Event) - 当一个新线程被创建时发送此事件。
  • 线程退出事件 (Thread Exit Event) - 当一个线程退出时发送此事件。
  • 调试字符串事件 (Debug String Event) - 当一个进程向其调试器发送字符串消息时发送此事件。
  • 输出字符串事件 (Output String Event) - 当输出调试字符串时发送此事件。
  • 动态链接库加载事件(LOAD_DLL_DEBUG_EVENT) - 当进程装载 DLL 时发送此事件。

当我们需要调试一个程序时有两种方式可以实现,第一种方式是通过CreateProcess()函数创建一个进程,并在调用函数时指定DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS则当程序被运行起来后自动进入到调试状态,另一种方式则是通过DebugActiveProcess()函数,该函数接受一个正在运行的进程PID号,可动态附加到一个已运行程序上而对其进行调试。

一旦调试器通过CreateProcess()附加并运行,下一步则是通过WaitForDebugEvent()用于等待一个调试事件,当有调试事件到达后系统会将调试类型存储到debugEvent.dwDebugEventCode这个变量内,此时我们可以通过判断该变量内的参数来对特定的事件做出自定义处理操作,接着会通过ContinueDebugEvent()继续等待下一个调试事件的到来,我们以打开一个进程并创建调试为例,看一下如下代码片段;

#include <iostream>
#include <windows.h>

int main(int argc, char* argv[])
{
    DEBUG_EVENT debugEvent = { 0 };
    BOOL bRet = TRUE;

    // 创建调试进程
    STARTUPINFO startupInfo = { 0 };
    PROCESS_INFORMATION pInfo = { 0 };
    GetStartupInfo(&startupInfo);

    // 创建调试进程并设置 DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS 调试事件
    bRet = CreateProcess("d://lyshark.exe", NULL, NULL, NULL, TRUE, DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &pInfo);
    if (!bRet)
    {
        return 0;
    }

    // 附加调试进程
    // DebugActiveProcess(13940)

    // 无限循环等待调试事件
    while (WaitForDebugEvent(&debugEvent, INFINITE))
    {
        // 根据调试事件判断
        switch (debugEvent.dwDebugEventCode)
        {
            // 异常调试事件
        case EXCEPTION_DEBUG_EVENT:
            printf("异常处理事件 \n");
            break;

            // 线程创建调试事件
        case CREATE_THREAD_DEBUG_EVENT:
            printf("线程创建调试事件 \n");
            break;
            // 进程创建调试事件
        case CREATE_PROCESS_DEBUG_EVENT:
            printf("进程创建调试事件 \n");
            break;
            // 线程退出调试事件
        case EXIT_THREAD_DEBUG_EVENT:
            printf("线程退出调试事件 \n");
            break;
            // 进程退出调试事件
        case EXIT_PROCESS_DEBUG_EVENT:
            printf("进程退出调试事件 \n");
            break;
            // 装载DLL调试事件
        case LOAD_DLL_DEBUG_EVENT:
            printf("装载DLL调试事件 \n");
            break;
            // 卸载DLL调试事件
        case UNLOAD_DLL_DEBUG_EVENT:
            printf("卸载DLL调试事件 \n");
            break;
            // 输出调试信息事件
        case OUTPUT_DEBUG_STRING_EVENT:
            printf("输出调试信息事件 \n");
            break;
        }

        // 使调试器能够继续以前报告调试事件的线程
        bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
    }

    system("pause");
    return 0;
}

当编译并运行上述程序后,读者应该能看到如下图所示的输出效果,其中包括了各类调试事件被触发时的提示信息,由于在调试事件内没有做任何操作,程序在加载后就被自动运行起来了;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/b8eecce4.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

标签:10.0,进程,API,线程,事件,DEBUG,EVENT,调试
From: https://www.cnblogs.com/LyShark/p/17741475.html

相关文章

  • 2023.10.03补题两则
    2023.10.03T2Solution在\(\bmod{2}\)意义下,\(-x^{c}=x^{c}\)。对于\(A_i\equivC\pmod{B}\),变为\(A_i-C\equiv0\pmod{B}\),那么\(-C\)操作可以看成是异或上\(C\)。对于\(A^{'}_i\equiv0\pmod{B}\)的形式,欲找到最大的\(B\),则\(B\)显然是\(\gcd\......
  • APIO2019 桥梁
    Day\(\mathbb{Z}(\text{Ni})\)。想成kruskal重构树后就再也不会了。考虑没有修改怎么做,将所有边和询问按照权值从大到小排序,对于一个询问\((s,w)\),向并查集中插入所有边权\(\gew\)的边,维护连通块大小即可。现在有了修改,考虑对询问修改分块。设每\(B\)个询问修改重构一......
  • 10.03模拟赛总结
    总结寄掉啦,\(50+30+100+8\)。T1组队(team)分析很简单的题目,通过充分发扬人类智慧,设\(x\)为二元组\((i,j)\)满足\(i<j,a_i=a_j\)的数量,则答案为\(2^x-1\)。代码没有。T2话外世界奇观:、附:题面组队(team)题目描述穗织镇上共有\(n\)个种族的秽神,第\(i\)个......
  • JDWP调试SpringBoot程序
    JDWP调试SpringBoot程序<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-loader</artifactId></dependency>java-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5050-jar&......
  • 在Kubernetes环境中有关Nginx Ingress与API Gateway的连接问题
    文章目录小结问题解决参考小结在Kubernetes环境中是通过NginxIngress来从外部访问Kubernetes内部的环境,并用APIGateway来分发请求,碰到了502Badgateway.的问题,并尝试解决。问题从外部通过NginxIngress访问Kubernetes内部的环境APIGateway,返回错误:502Badgateway.这里API......
  • 开发调试:提高代码质量与开发效率的关键步骤
    ......
  • 9.2 运用API实现线程同步
    Windows线程同步是指多个线程一同访问共享资源时,为了避免资源的并发访问导致数据的不一致或程序崩溃等问题,需要对线程的访问进行协同和控制,以保证程序的正确性和稳定性。Windows提供了多种线程同步机制,以适应不同的并发编程场景。主要包括以下几种:事件(Event):用于不同线程间的信......
  • 嵌入式软件调试与验证4自动重现和分析嵌入式软件中的Bug
    4自动重现和分析嵌入式软件中的Bug4.1引言嵌入式软件的重要性逐年增加。ISO26262标准的最高安全级别要求十个9小时内无故障运行。然而,历史上的一些项目表明,即使进行了全面的测试,多年来仍有许多错误未被发现。航天飞机的控制计算机仅有50万行源代码,却经过了长达8年的测试,每行源......
  • template 2023.10.01
    特斯拉ModelY2023小更新款AllInOne⚠️没有座椅通风......
  • 2023.10.01 日记
    1+1=2令\(f[i]\)为\(a+b=i\)的和。显然可得\(f[a]=f[a-b]+f[b],f[1]=1\)。所以可得\(1+1=f[1]+f[1]=f[2]=2\)。code#include<bits/stdc++.h>usingnamespacestd;constintmaxn=1e5+10;inta,b,f[maxn];intmain(){ios::sync_with_stdio(false);cin.......