本章笔者将通过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;
}
当编译并运行上述程序后,读者应该能看到如下图所示的输出效果,其中包括了各类调试事件被触发时的提示信息,由于在调试事件内没有做任何操作,程序在加载后就被自动运行起来了;
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容