Win32除錯API的另類應用

看雪資料發表於2015-11-15

標 題: Win32除錯API的另類應用

發帖人:hangj

時 間: 2005-01-21 15:11 

詳細資訊: 



俺寫一個虛擬CPU,可出錯不容易找到,就想到這個辦法。讓一個程式單步執行,每執行一步就與虛擬CPU執行的結果相比較,不同的地方就是我的錯。
下面是我的程式碼,高手別笑!

//比較程式執行的每一步,找到不同的地方
void CDebugDlg::Run(HCurrentThread &currentThread)
{
  DEBUG_EVENT debug_event;
  LPEXCEPTION_DEBUG_INFO pdebug_info;
  STARTUPINFO starupInfo;
  BYTE codebuf[30];
  CONTEXT context;
  HANDLE hTread;
  HANDLE hProc;

  PE32Loader * w32;
  STOP_CONDITION cond;
  DWORD rip,readsize;
  HFile file;
  if(!file.OpenForRead(m_path))
    return;
  if(!(w32= new PE32Loader))
    return;
  w32->Attach(&file);
  w32->LoadModule(m_vm);
  m_vm.SetMemory(w32);
  rip=w32->m_pe.GetEntry();
  memset(codebuf,0,sizeof(codebuf));
  ::GetStartupInfo(&starupInfo);
  if(::CreateProcess(m_path,"",NULL,NULL,FALSE,DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&starupInfo,&pi))
  {
    for(;;)
    {
      if(WaitForDebugEvent(&debug_event,INFINITE))
      {
        switch(debug_event.dwDebugEventCode)
        {
        case CREATE_PROCESS_DEBUG_EVENT://
          //儲存執行緒和程式控制程式碼
          hTread=debug_event.u.CreateProcessInfo.hThread;
          hProc=debug_event.u.CreateProcessInfo.hProcess;
          //把程式入口指令改為單步中斷int 3
          readsize=0;
          ::ReadProcessMemory(hProc,(LPCVOID)rip,codebuf,1,&readsize);//儲存原入口指令位元組
          codebuf[10]=0xcc;//中斷int 3的機器碼
          readsize=0;
          ::WriteProcessMemory(hProc,(LPVOID)rip,&codebuf[10],1,&readsize);
          ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId,DBG_CONTINUE);
          break;
        case EXCEPTION_DEBUG_EVENT:
          pdebug_info=&debug_event.u.Exception;
          switch(pdebug_info->ExceptionRecord.ExceptionCode)
          {  
          case EXCEPTION_BREAKPOINT:
          
            context.ContextFlags=CONTEXT_CONTROL|CONTEXT_INTEGER;
            ::GetThreadContext(hTread ,&context);
            if(context.Eip==rip+1)
            {
              //如果是修改過的入口則恢復為原來的指令重新執行。
              readsize=0;
              ::ReadProcessMemory(hProc,(LPCVOID)rip,&codebuf[10],10,&readsize);
              if(codebuf[10]==0xcc)
              {
                context.EFlags|=0x100;//開始單步

                context.Eip=rip;//重新執行

                //設定虛擬CPU的暫存器內容
                m_vm.m_cpu.rReg[AMD_RIP_INDEX].qword=context.Eip;
                m_vm.m_cpu.rReg[AMD_RAX_INDEX].qword=context.Eax;
                m_vm.m_cpu.rReg[AMD_RBX_INDEX].qword=context.Ebx;
                m_vm.m_cpu.rReg[AMD_RCX_INDEX].qword=context.Ecx;
                m_vm.m_cpu.rReg[AMD_RDX_INDEX].qword=context.Edx;
                m_vm.m_cpu.rReg[AMD_RSI_INDEX].qword=context.Esi;
                m_vm.m_cpu.rReg[AMD_RDI_INDEX].qword=context.Edi;
                m_vm.m_cpu.rReg[AMD_RBP_INDEX].qword=context.Ebp;
                //恢復為原來的指令。
                readsize=0;
                ::WriteProcessMemory(hProc,(LPVOID)rip,&codebuf,1,&readsize);
                ::SetThreadContext(hTread,&context);
              }
            }
            ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId,DBG_CONTINUE);
            break;
          case EXCEPTION_SINGLE_STEP:
            
            context.ContextFlags=CONTEXT_CONTROL|CONTEXT_INTEGER;
            ::GetThreadContext(hTread ,&context);
            
            cond.type=STOP_STEP;
            cond.cond_info.dwords[0]=m_vm.GetCurrentSetpCount()+1;
            m_vm.Run(&cond);

            if(!CmpCpu(context))
            {
              MessageBox("EXCEPTION_SINGLE_STEP");
            }
            
            

            context.EFlags|=0x100;//開始單步
            ::SetThreadContext(hTread,&context);
            ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId,DBG_CONTINUE);
            break;
          }
          break;
        case EXIT_PROCESS_DEBUG_EVENT:
          return;
          break;
        case RIP_EVENT:
          ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId,DBG_TERMINATE_PROCESS);
          break;
        default:
          ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
        }
      }
    }
  }
}
比較CPU暫存器內容是否相同
BOOL CDebugDlg::CmpCpu(CONTEXT &context)
{
  if(m_vm.m_cpu.rReg[AMD_RAX_INDEX].dwords[0]!=context.Eax||
    m_vm.m_cpu.rReg[AMD_RBX_INDEX].dwords[0]!=context.Ebx||
    m_vm.m_cpu.rReg[AMD_RCX_INDEX].dwords[0]!=context.Ecx||
    m_vm.m_cpu.rReg[AMD_RDX_INDEX].dwords[0]!=context.Edx||
    m_vm.m_cpu.rReg[AMD_RSI_INDEX].dwords[0]!=context.Esi||
    m_vm.m_cpu.rReg[AMD_RDI_INDEX].dwords[0]!=context.Edi||
    m_vm.m_cpu.rReg[AMD_RBP_INDEX].dwords[0]!=context.Ebp||
    m_vm.m_cpu.rReg[AMD_RIP_INDEX].dwords[0]!=context.Eip)
    return FALSE;
  return TRUE;
}



俺寫的虛擬CPU是hdasm64,請大家下載試用:
本身是一個Win32程式(PE32格式)在下載的包裡有64位的PE和ELF檔案各一個,32位ELF檔案一個,供大家研究!
支援真實模式、保護模式、64位模式三種模式指令集的動態反彙編. 支援DOS系統COM和EXE可執行檔案格式,支援32位和64位PE檔案格式(windows可執行檔案),支援32位和64位ELF檔案格式(Linux可執行檔案),共計六種檔案格式。支援部分指令的虛擬執行除錯。

下載頁面:
http://pay500.com/s/s56504.htm

相關文章