debuger!

  1 #include <windows.h>
  2 #include <string>
  3 #include <iostream>
  4 
  5 using namespace std;
  6 
  7 /*先声明一些Debug消息处理函数供调用*/
  8 void OnProcessCreated(const CREATE_PROCESS_DEBUG_INFO*);
  9 void OnThreadCreated(const CREATE_THREAD_DEBUG_INFO*);
 10 void OnException(const EXCEPTION_DEBUG_INFO*);
 11 void OnProcessExited(const EXIT_PROCESS_DEBUG_INFO*);
 12 void OnThreadExited(const EXIT_THREAD_DEBUG_INFO*);
 13 void OnOutputDebugString(const OUTPUT_DEBUG_STRING_INFO*);
 14 void OnRipEvent(const RIP_INFO*);
 15 void OnDllLoaded(const LOAD_DLL_DEBUG_INFO*);
 16 void OnDllUnloaded(const UNLOAD_DLL_DEBUG_INFO*);
 17 
 18 
 19 void main()
 20 {
 21     //定义两个结构供api填值
 22     STARTUPINFO    si={0};
 23     
 24     PROCESS_INFORMATION pi = { 0 };
 25     
 26     if (!CreateProcess(
 27         TEXT("C:\windows\notepad.exe"), //打开的程序名称,这里用TEXT宏包含了一下
 28         NULL,
 29         NULL,
 30         NULL,
 31         FALSE,
 32         DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,//只调试当前进程
 33         NULL,
 34         NULL,    //当前目录
 35         &si,    //启动信息
 36         &pi))    //进程信息
 37     {
 38         std::cout<<GetLastError()<<endl;
 39         return;
 40     }
 41     
 42     BOOL waitEvent = TRUE;
 43     
 44     DEBUG_EVENT debugEvent;
 45     while (waitEvent == TRUE && WaitForDebugEvent(&debugEvent, INFINITE)) {
 46         //WaitForDebugEvent接收OS的调试消息事件
 47         switch (debugEvent.dwDebugEventCode) {
 48             
 49         case CREATE_PROCESS_DEBUG_EVENT:
 50             OnProcessCreated(&debugEvent.u.CreateProcessInfo);
 51             break;
 52             
 53         case CREATE_THREAD_DEBUG_EVENT:
 54             OnThreadCreated(&debugEvent.u.CreateThread);
 55             break;
 56             
 57         case EXCEPTION_DEBUG_EVENT:
 58             OnException(&debugEvent.u.Exception);
 59             break;
 60             
 61         case EXIT_PROCESS_DEBUG_EVENT:
 62             OnProcessExited(&debugEvent.u.ExitProcess);
 63 //要注意这里是如何退出循环的:引入一个BOOL类型的waitEvent变量,在处理EXIT_PROCESS_DEBUG_EVENT之后将它的值改成FALSE
 64             waitEvent = FALSE;
 65             break;
 66             
 67         case EXIT_THREAD_DEBUG_EVENT:
 68             OnThreadExited(&debugEvent.u.ExitThread);
 69             break;
 70             
 71         case LOAD_DLL_DEBUG_EVENT:
 72             OnDllLoaded(&debugEvent.u.LoadDll);
 73             break;
 74             
 75         case UNLOAD_DLL_DEBUG_EVENT:
 76             OnDllUnloaded(&debugEvent.u.UnloadDll);
 77             break;
 78             
 79         case OUTPUT_DEBUG_STRING_EVENT:
 80             OnOutputDebugString(&debugEvent.u.DebugString);
 81             break;
 82             
 83         case RIP_EVENT:
 84             OnRipEvent(&debugEvent.u.RipInfo);
 85             break;
 86             
 87         default:
 88             std::cout << TEXT("Unknown debug event.") << std::endl;
 89             break;
 90         }
 91         
 92         if (waitEvent == TRUE) {
 93             ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
 94         }
 95         else {
 96             break;//waitEvent != TRUE 时退出循环
 97         }
 98     }
 99 
100 }
101 
102 void OnProcessCreated(const CREATE_PROCESS_DEBUG_INFO* pInfo) {
103     
104     std::cout<<TEXT("Debuggee was created.")<<endl;
105 }
106 
107 
108 
109 void OnThreadCreated(const CREATE_THREAD_DEBUG_INFO* pInfo) {
110     
111     std::cout<<TEXT("A new thread was created.")<<endl;
112 }
113 
114 
115 
116 void OnException(const EXCEPTION_DEBUG_INFO* pInfo) {
117     
118     std::cout<< TEXT("An exception was occured.")<<endl;
119 }
120 
121 
122 
123 void OnProcessExited(const EXIT_PROCESS_DEBUG_INFO* pInfo) {
124     
125     std::cout<<TEXT("Debuggee was terminated.")<<endl;
126 }
127 
128 
129 
130 void OnThreadExited(const EXIT_THREAD_DEBUG_INFO* pInfo) {
131     
132     std::cout<<TEXT("A thread was terminated.")<<endl;
133 }
134 
135 
136 
137 void OnOutputDebugString(const OUTPUT_DEBUG_STRING_INFO* pInfo) {
138     
139     std::cout<<TEXT("Debuggee outputed debug string.")<<endl;
140 }
141 
142 
143 
144 void OnRipEvent(const RIP_INFO* pInfo) {
145     
146     std::cout<<TEXT("A RIP_EVENT occured.")<<endl;
147 }
148 
149 
150 
151 void OnDllLoaded(const LOAD_DLL_DEBUG_INFO* pInfo) {
152     
153     std::cout<<TEXT("A dll was loaded.")<<endl;
154 }
155 
156 
157 
158 void OnDllUnloaded(const UNLOAD_DLL_DEBUG_INFO* pInfo) {
159     
160     std::cout<<TEXT("A dll was unloaded.")<<endl;
161 }
typedef struct _DEBUG_EVENT {
  DWORD dwDebugEventCode;        //从这确定union联合域内是什么内容
  DWORD dwProcessId;           //PID
  DWORD dwThreadId;            //线程ID
  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;
//然后从各种event_info_struct中取得调试信息

 --各种事件的处理--------------------------------------

RIP_EVENT

关于这种调试事件的文档资料非常少,只要输出一条信息或者干脆忽略它即可。

OUTPUT_DEBUG_STRING_EVENT

被调试进程调用OutputDebugString()时就会引发该类调试事件,OUTPUT_DEBUG_STRING_INFO结构体描述了关于该事件的详细信息。

typedef struct _OUTPUT_DEBUG_STRING_INFO {
  LPSTR lpDebugStringData;    //字符串在被调试进程的进程空间内的地址
  WORD  fUnicode;              //是否Unicode编码
  WORD  nDebugStringLength;    //以字符为单位的字符串的长度
} OUTPUT_DEBUG_STRING_INFO, *LPOUTPUT_DEBUG_STRING_INFO;
    

字符串是在被调试进程的地址空间内,我们就要使用ReadProcessMemory函数读取这个字符串。下面的代码展示了这个过程:

void OnOutputDebugString(const OUTPUT_DEBUG_STRING_INFO* pInfo) {
    
    BYTE* pBuffer = (BYTE*)malloc(pInfo->nDebugStringLength);//申请的大小刚好
    
    SIZE_T bytesRead;    //读取的字数
    
    ReadProcessMemory(    //读入buffer
        g_hProcess,    //g_hProcess==pi.hProcess;
        pInfo->lpDebugStringData,
        pBuffer, 
        pInfo->nDebugStringLength,
        &bytesRead);
    
    std::cout << TEXT("Debugger debug string: ") << pBuffer <<  std::endl;
    
    free(pBuffer);
}

----------------读取寄存器和内存(OD的寄存器窗口和数据窗口)--------------------

获取寄存器的值

每个线程都有一个上下文环境(context),它包含了有关线程的大部分信息,例如线程栈的地址,线程当前正在执行的指令地址等。上下文环境保存在寄存器中,系统进行线程调度的时候会发生上下文切换,实际上就是将一个线程的上下文环境保存到内存中,然后将另一个线程的上下文环境装入寄存器。

在实际上下文中谈CONTEXT结构
CONTEXT结构包括以下部分:

   CONTEXT_CONTROL:包含CPU的控制寄存器,比如指今指针,堆栈指针,标志和函数返回地址..AX, BX, CX, DX, SI, DI
     CONTEXT_INTEGER:用于标识CPU的整数寄存器.DS, ES, FS, GS
   CONTEXT_FLOATING_POINT:用于标识CPU的浮点寄存器.
     CONTEXT_SEGMENTS:用于标识CPU的段寄存器.SS:SP, CS:IP, FLAGS, BP
   CONTEXT_DEBUG_REGISTER:用于标识CPU的调试寄存器.  
   CONTEXT_EXTENDED_REGISTERS:用于标识CPU的扩展寄存器I
   CONTEXT_FULL:相当于CONTEXT_CONTROL or CONTEXT_INTEGER or   CONTEXT_SEGMENTS,即这三个标志的组合

我们可以使用GetThreadContext函数来查看线程内核对象的内部,并获取当前CPU寄存器状态的集合。

BOOL GetThreadContext (

HANDLE  hThread,

PCONTEXT  pContext);

若要调用该函数,只需指定一个CONTEXT结构,对某些标志(该结构的ContextFlags成员)进行初始化,指明想要收回哪些寄存器,并将该结构的地址传递给GetThreadContext 。然后该函数将数据填入你要求的成员。

在调用GetThreadContext函数之前,应该调用SuspendThread,否则,线程可能刚好被调度,这样一来,线程的上下文就和所获取的信息不一致了。

示例代码如下: 

         CONTEXT Context;                  //定义一个CONTEXT结构

         Context.ContextFlags = CONTEXT_CONTROL;    //告诉系统我们想获取线程控制寄存器的内容   

         GetThreadContext(hThread, &Context);      //调用GetThreadContext获取相关信息

Ps:在调用GetThreadContext函数之前,必须首先初始化CONTEXT结构的ContextFlags成员。

要获得线程的所有重要的寄存器(也就是微软认为最常用的寄存器),应该像下面一样初始化ContextFlags:

Context.ContextFlags = CONTEXT_FULL;

在WinNT. h头文件中,定义了CONTEXT_FULL为CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS。

当然,我们还可以通过调用SetThreadContext函数来改变结构中的成员,并把新的寄存器值放回线程的内核对象中

BOOL SetThreadContext (

HANDLE  hThread,

CONST CONTEXT  *pContext);

同样,如果要改变哪个线程的上下文,应该先暂停该线程。       

         CONTEXT Context;      //定义一个CONTEXT结构      

         SuspendThread(hThread);  //挂起线程  

         Context.ContextFlags = CONTEXT_CONTROL;   //获取当前上下文的值

         GetThreadContext(hThread, &Context);

         Context.Eip = 0x00010000;      //Eip字段存储的是指令指针,现在让指令指针指向地址 0x00010000;

         Context.ContextFlags = CONTEXT_CONTROL;

         SetThreadContext(hThread, &Context);   //重新设置线程上下文

         ResumeThread(hThread);         //恢复线程,现在线程开始从0x00010000这个地方开始执行指令
原文地址:https://www.cnblogs.com/Rrouned/p/3418140.html