Windows用户级调试器(debugger)编写框架

    这几天帮朋友做了个内存补丁,大致熟悉了一下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);
 }
}

    上面是一个简单的框架,供有兴趣的朋友参考!
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
这是一个windows脚本调试器程序。 绿色:只需复制文件到同一目录下就可以了。 纯净:基本不使用注册表,只是在注册文件类型图标和文件关联时才使用了注册表。 无毒:绝对没有任何恶意代码,但是由于程序会自动产生临时的批处理文件,可能会被杀毒软件误报。 注意:如果不能启动,下载vcredist_x86.exe安装VC运行库,然后再试。 已经实现的功能: 设置断点; 在断点命中时在代码编辑器指示哪个断点被命中。 在断点命中时可以观察现场状态【变量、ErrorLevel、当前目录】; 如果批处理没有调用Exit退出,那么可以观察到批处理执行完的现场状态; 调试暂停时会自动打开/切换文件并滚动代码窗口,使当前断点可见; 可以预设批处理执行前的环境变量和当前目录。 工程管理,也就是管理批处理文件、断点、观察变量、初始环境变量、初始当前目录、批处理入口文件、批处理文件命令行参数的信息。 支持用户自定义界面,使用标签多文档界面和停靠栏。 双击.bdc文件,会启动windows脚本调试器。 附带使用手册和批处理指南。 准备实现的功能: 在断点命中时修改环境变量或者当前目录; 语法分析【代码着色、语法检查的基础】; 语法检查; 代码着色; 内置命令帮助; 不打算实现的功能: 我感觉批处理编程并不能提供多少智能提示,所以就不做了。 局限性: 代码编辑器暂时不支持中文,这个是最大的限制了,我会在下个版本解决这个问题; 只可以在批处理语句之前加断点,不可以在空行、标签行和右括号)开头的行加断点,不可以在非批处理代码处加断点; 不支持单步调试; 必须在调试之前加断点,在调试之后加的断点,只能在以后的调试会话中起作用。 启动批处理脚本只能接受10个参数,这个限制好像问题不大。 目前可能还有bug。 注意: 不要调试本程序所在目录下的那三个批处理程序,否则会出现无法预料的行为。为了保险,请把他们设为只读隐藏文件。 可以把halt.exe也设为只读隐藏文件。 我会持续改进本程序。 email: cdp97531@sina.com blog: http://hi.baidu.com/chendeping/home
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值