码迷,mamicode.com
首页 > 其他好文 > 详细

调试器开发实例_调试器框架设计

时间:2014-07-31 09:34:36      阅读:398      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   使用   os   strong   io   for   

 

作为一个安全开发人员离不开调试器,它可以动态显示程序的执行过程,对于解决程序问题有极大的帮助,这些文章记录了我开发一个调试器雏形的过程,希望对你有帮助。或许我写的代码很拙劣,还请大家多多见谅!

我们使用  Microsoft Visual Studio 6.0 VC编译器来作为我们的开发工具
想对一个程序进行调试,首先要做的当然是启动这个程序,这要使用CreateProcess这个Windows API来完成。
例如: 

 1 // LilisiDebug.cpp : Defines the entry point for the console application.
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <windows.h>
 6 
 7 int main(int argc, char* argv[])
 8 {
 9     STARTUPINFO si = { 0 };
10     si.cb = sizeof(si);    
11     PROCESS_INFORMATION pi = { 0 };
12 
13     BOOL bRet = CreateProcess(TEXT("C:\\windows\\system32\\calc.exe"),
14                               NULL,
15                               NULL,
16                               NULL,
17                               FALSE,
18                               DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE,
19                               NULL,
20                               NULL,
21                               &si,
22                               &pi);
23         
24         if ( bRet == FALSE) 
25         {
26             
27             printf("Open Debug Process Error!");
28             return -1;
29         }        
30         CloseHandle(pi.hThread);
31         CloseHandle(pi.hProcess);        
32         return 0;
33 }

CreateProcess的第六个参数使用了DEBUG_ONLY_THIS_PROCESS,这意味着调用CreateProcess的进程成为了调试器,而它启动的子进程成了被调试的进程。
在第六个参数之中也可以加上CREATE_NEW_CONSOLE ,他的作用在于如果被调试程序是一个控制台程序的话,调试器和被调试程序的输出都在同一个控制台窗口内,显得很混乱,加上这个标记之后,被调试程序就会在一个新的控制台窗口中输出信息。如果被调试程序是一个窗口程序,这个标记没有影响。(个人推荐) 

以上的代码仅仅是启动了被调试进程,然后就立即退出了。要注意的是,如果调试器进程结束了,那么被它调试的所有子进程都会随着结束。这就是为什么虽然CreateProcess调用成功了,却看不到计算器窗口的原因。

那么调试器如何知道被调试进程内部发生了什么?其实当一个进程成为被调试进程之后,在完成了某些操作或者发生异常时,它会发送通知给调试器,然后将自身挂起,直到调试器命令它继续执行。所以接下来我们开始调用
调试循环事件对被调试程序进行事件的处理。
被调试进程发送的通知称为调试事件,在
DEBUG_EVENT结构体中详细描述了调试事件的内容: 

 

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

其结构体中的dwDebugEventCode描述了调试事件的类型,总共有9类调试事件:

 

 

CREATE_PROCESS_DEBUG_EVENT

创建进程的时候会来到该调试事件.

CREATE_THREAD_DEBUG_EVENT

创建一个线程之后发送此类调试事件.

EXCEPTION_DEBUG_EVENT

发生异常时发送此类调试事件.

EXIT_PROCESS_DEBUG_EVENT

进程结束后发送此类调试事件.

EXIT_THREAD_DEBUG_EVENT

一个线程结束后发送此类调试事件.

LOAD_DLL_DEBUG_EVENT

装载一个DLL模块之后发送此类调试事件.

OUTPUT_DEBUG_STRING_EVENT

被调试进程调用OutputDebugString之类的函数时发送此类调试事件.

RIP_EVENT

发生系统调试错误时发送此类调试事件.

UNLOAD_DLL_DEBUG_EVENT

卸载一个DLL模块之后发送此类调试事件.

 

而在结构体中的u联合体来记录每种调试事件,通过u的字段的名称可以很快地判断哪个字段与哪种事件关联。
 dwProcessIddwThreadId分别是触发调试事件的进程ID和线程ID
 调试器则通过WaitForDebugEvent,通过ContinueDebugEvent继续被调试进程的执行。 

以下代码摘要于微软帮助文档MSDN 

 

 1 DEBUG_EVENT DebugEv;                   // debugging event information 
 2 DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation 
 3 for(;;) 
 4 { 
 5 
 6 // Wait for a debugging event to occur. The second parameter indicates 
 7 // that the function does not return until a debugging event occurs. 
 8 
 9     WaitForDebugEvent(&DebugEv, INFINITE); 
10 
11 // Process the debugging event code. 
12 switch (DebugEv.dwDebugEventCode) 
13     { 
14         case EXCEPTION_DEBUG_EVENT: 
15         // Process the exception code. When handling 
16         // exceptions, remember to set the continuation 
17         // status parameter (dwContinueStatus). This value 
18         // is used by the ContinueDebugEvent function. 
19 
20             switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode) 
21             { 
22                 case EXCEPTION_ACCESS_VIOLATION: 
23                 // First chance: Pass this on to the system. 
24                 // Last chance: Display an appropriate error. 
25 
26                 case EXCEPTION_BREAKPOINT: 
27                 // First chance: Display the current 
28                 // instruction and register values. 
29 
30                 case EXCEPTION_DATATYPE_MISALIGNMENT: 
31                 // First chance: Pass this on to the system. 
32                 // Last chance: Display an appropriate error. 
33 
34                 case EXCEPTION_SINGLE_STEP: 
35                 // First chance: Update the display of the 
36                 // current instruction and register values. 
37 
38                 case DBG_CONTROL_C: 
39                 // First chance: Pass this on to the system. 
40                 // Last chance: Display an appropriate error. 
41 
42                 // Handle other exceptions. 
43             } 
44         case CREATE_THREAD_DEBUG_EVENT: 
45         // As needed, examine or change the thread‘s registers 
46         // with the GetThreadContext and SetThreadContext functions; 
47         // and suspend and resume thread execution with the 
48         // SuspendThread and ResumeThread functions. 
49 
50         case CREATE_PROCESS_DEBUG_EVENT: 
51         // As needed, examine or change the registers of the 
52         // process‘s initial thread with the GetThreadContext and 
53         // SetThreadContext functions; read from and write to the 
54         // process‘s virtual memory with the ReadProcessMemory and 
55         // WriteProcessMemory functions; and suspend and resume 
56         // thread execution with the SuspendThread and ResumeThread 
57         // functions. 
58 
59         case EXIT_THREAD_DEBUG_EVENT: 
60         // Display the thread‘s exit code. 
61 
62         case EXIT_PROCESS_DEBUG_EVENT: 
63         // Display the process‘s exit code. 
64 
65         case LOAD_DLL_DEBUG_EVENT: 
66         // Read the debugging information included in the newly 
67         // loaded DLL. 
68 
69         case UNLOAD_DLL_DEBUG_EVENT: 
70         // Display a message that the DLL has been unloaded. 
71 
72         case OUTPUT_DEBUG_STRING_EVENT: 
73         // Display the output debugging string. 
74         }     
75     // Resume executing the thread that reported the debugging event.  
76        ContinueDebugEvent(DebugEv.dwProcessId, 
77                    DebugEv.dwThreadId, dwContinueStatus);
78 } 

这样一个循环就是所谓的调试循环。要注意这里是如何退出循环的:引入一个BOOL类型的bRetEvent变量,在处理
EXIT_PROCESS_DE BUG_EVENT

 

调试器开发实例_调试器框架设计,布布扣,bubuko.com

调试器开发实例_调试器框架设计

标签:style   blog   color   使用   os   strong   io   for   

原文地址:http://www.cnblogs.com/hailunchina/p/3879876.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!