这几天帮朋友做了个内存补丁,大致熟悉了一下Windows下用户级调试器(Debugger)程序编写的基本框架。做一个小小的总结,由于本人能力所限,这里只是根据MSDN的说明,给出一个大致的框架结构,还请高手批评指正。其实,要编写实际可用或是更加完善的程序,还需要学习掌握更多的技术,花费更多的努力!
我想对于Debugger不用多说什么了。我认为除了SoftIce之外,做得比较好的调试器应该算是OllyDbg,但它只能作为用户级的调试器。作者(德国人)宣称,OllyDbg完全使用Windows公开的API写成,因此兼容性很好,经过众多网友的试用也的确如此,并且用它来调试和分析程序能带来事半功倍的效果。有兴趣的朋友可以试用一下!
其实,Windows向系统开发者提供了比较完善的调试用API。应用这些API,再加上进程、线程等相关API就能写出实用的调试器。下面就是一个调试器的基本框架:
int main(int args,char* argv[])
{ STARTUPINFO StartUpInfo; //模块启动信息 CONTEXT ProcessContext; //进程的上下文环境 DEBUG_EVENT DebugEv; // debugging event information DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation PROCESS_INFORMATION ProcessInfo; //创建的子进程信息 int ReturnSize; //内存操作API函数返回的字节数
//
//获得模块信息 // GetStartupInfo(&StartUpInfo); // //建立要打补丁的子进程 // if( ! CreateProcess(ExecFileName,NULL,NULL,NULL,NULL,DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL,NULL,&StartUpInfo,&ProcessInfo) ) { MessageBox(NULL,"无法加载相应可执行文件,请检查文件是否存在!","严重错误",MB_OK | MB_ICONSTOP); return -1; } for(;;) { // Wait for a debugging event to occur. The second parameter indicates // that the function does not return until a debugging event occurs. WaitForDebugEvent(&DebugEv, INFINITE); // Process the debugging event code. switch (DebugEv.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: // Process the exception code. When handling // exceptions, remember to set the continuation // status parameter (dwContinueStatus). This value // is used by the ContinueDebugEvent function. switch(DebugEv.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. // break; case EXCEPTION_BREAKPOINT: // First chance: Display the current // instruction and register values. ProcessContext.ContextFlags=CONTEXT_FULL; GetThreadContext(ProcessInfo.hThread,&ProcessContext); if (ProcessContext.Eip == BreakPoint1 + 1) { ProcessContext.Eip --; //设定断点0,用于再次中断时设定断点1 WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)BreakPoint0,&InstructInt3,1,(SIZE_T*)&ReturnSize); //恢复int 3前的原指令 WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)BreakPoint1,&OldInstruct1,1,(SIZE_T*)&ReturnSize); SetThreadContext(ProcessInfo.hThread,&ProcessContext); //内存打补丁 WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)ProcessContext.Ecx,&NewIp,sizeof(NewIp),(SIZE_T*)&ReturnSize);
}
else if (ProcessContext.Eip == BreakPoint0 + 1) { ProcessContext.Eip --; //设定断点1,用于再次中断 WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)BreakPoint1,&InstructInt3,1,(SIZE_T*)&ReturnSize); //恢复int 3前的原指令 WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)BreakPoint0,&OldInstruct0,1,(SIZE_T*)&ReturnSize); SetThreadContext(ProcessInfo.hThread,&ProcessContext); } break; case EXCEPTION_DATATYPE_MISALIGNMENT: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. // break; case EXCEPTION_SINGLE_STEP: // First chance: Update the display of the // current instruction and register values. // break; case DBG_CONTROL_C: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. // break; default: // Handle other exceptions. //这里用DBG_EXCEPTION_NOT_HANDLED继续,是为了使原有的程序有机会做异常处理,否则系统用锁死 ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); continue; break; } case CREATE_THREAD_DEBUG_EVENT: // As needed, examine or change the thread's registers // with the GetThreadContext and SetThreadContext functions; // and suspend and resume thread execution with the // SuspendThread and ResumeThread functions. break;
case CREATE_PROCESS_DEBUG_EVENT:
// As needed, examine or change the registers of the // process's initial thread with the GetThreadContext and // SetThreadContext functions; read from and write to the // process's virtual memory with the ReadProcessMemory and // WriteProcessMemory functions; and suspend and resume // thread execution with the SuspendThread and ResumeThread // functions. Be sure to close the handle to the process image // file with CloseHandle. //设置内在补丁断点1 WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)BreakPoint1,&InstructInt3,1,(SIZE_T*)&ReturnSize); break; case EXIT_THREAD_DEBUG_EVENT: // Display the thread's exit code. break; case EXIT_PROCESS_DEBUG_EVENT: // Display the process's exit code. CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); return 0; break; case LOAD_DLL_DEBUG_EVENT: // Read the debugging information included in the newly // loaded DLL. Be sure to close the handle to the loaded DLL // with CloseHandle. break; case UNLOAD_DLL_DEBUG_EVENT: // Display a message that the DLL has been unloaded. break; case OUTPUT_DEBUG_STRING_EVENT: // Display the output debugging string. break; } // Resume executing the thread that reported the debugging event. ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, DBG_CONTINUE); } } |
上面是一个简单的框架,供有兴趣的朋友参考!