標 題: Win32除錯API的另類應用
發帖人:hangj
時 間: 2005-01-21 15:11
詳細資訊:
俺寫一個虛擬CPU,可出錯不容易找到,就想到這個辦法。讓一個程式單步執行,每執行一步就與虛擬CPU執行的結果相比較,不同的地方就是我的錯。
下面是我的程式碼,高手別笑!
//比較程式執行的每一步,找到不同的地方
void CDebugDlg::Run(HCurrentThread ¤tThread)
{
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