標(biāo) 題: 【原創(chuàng)】OllyDBG分析報告系列(8)---進(jìn)程加載調(diào)試原理 作 者: comewhere 時 間: 2008-12-23,21:16:16 鏈 接: http://bbs./showthread.php?t=79305 標(biāo) 題: 【原創(chuàng)】OllyDBG分析報告系 作 者: comewhere 時 間: 2008-12-23,21:16 鏈 接: http://bbs./showthread.php?t=79305 我還是初學(xué)者 請各位多多指教....O(∩_∩)O OD版本:OllyICE v1.10 在從文件菜單選擇附加后,OD會在注冊一個窗口類后,,先創(chuàng)建一個0x138大小的進(jìn)程表; 再是CreateWindowExA 創(chuàng)建窗口; 00478013 loc_478013: 00478013 push 0 ; int 00478015 push offset sub_477C10 ; int 0047801A push 100h ; int 0047801F push 310h ; int 00478024 push offset asc_4C20E8 ; "? 00478029 push offset byte_4ED3FC ; dest 0047802E call _Createsorteddata //此處為創(chuàng)建進(jìn)程表 表的結(jié)構(gòu)體如下: table struc ; (sizeof=0x138) name db 260 dup(?) //表的名字 count dd ? //表中保存的數(shù)據(jù)個數(shù) maxcount dd ? //表能保存的最大數(shù)量 currentobj dd ? //當(dāng)前選中的表中數(shù)據(jù)的ID,未選中時為為-1 addrcurobj dd ? //當(dāng)前選中數(shù)據(jù)的地址,,未選中時為0 size dd ? //表中每個數(shù)據(jù)的大小 field_118 dd ? baseaddrobj dd ? //表中保存的數(shù)據(jù)的基地址 fncmp dd ? //函數(shù)首地址 field_124 dd ? field_128 dd ? sign dd ? //標(biāo)志位,,表示是否有索引數(shù)據(jù)(也就是baseaddroffset是否有效) baseaddroffset dd ? //索引數(shù)據(jù),標(biāo)示每個數(shù)據(jù)在表中的順序 field_134 dd ? table ends 然后OD會獲取自己的進(jìn)程ID號,,并獲取EnumProcesses ,,EnumProcessModules,GetModuleFileNameExA 三個函數(shù)的地址,; 00475138 loc_475138: 00475138 xor ebx, ebx 0047513A call GetCurrentProcessId //獲取OD本身的進(jìn)程ID 0047513F mov [ebp+var_10], eax 00475142 mov eax, dword_4D5A0C 00475147 test eax, eax 00475149 jz loc_4752AF 0047514F push offset aEnumprocesses ; "EnumProcesses" 00475154 push eax ; hModule 00475155 call GetProcAddress//獲取EnumProcesses地址 0047515A mov edi, eax 0047515C push offset aEnumprocessm_0 ; "EnumProcessModules" 00475161 mov eax, dword_4D5A0C 00475166 push eax ; hModule 00475167 call GetProcAddress//獲取EnumProcessModules的地址 0047516C mov [ebp+var_20], eax 0047516F push offset aGetmodulefil_0 ; "GetModuleFileNameExA" 00475174 mov edx, dword_4D5A0C 0047517A push edx ; hModule 0047517B call GetProcAddress//獲取GetModuleFileNameExA地址 00475180 mov [ebp+var_24], eax 之后OD枚舉系統(tǒng)中的所有進(jìn)程并保存枚舉到的進(jìn)程,; 004751A3 push eax 004751A4 push 400h 004751A9 push edx 004751AA call edi // EnumProcesses 枚舉進(jìn)程 004751AC test eax, eax 004751AE jnz short loc_4751B3 接著再一個循環(huán)中OD會嘗試?yán)肙penProcess打開枚舉到的所有進(jìn)程,如果進(jìn)程ID不等于OD本身ID 并且OpenProcess函數(shù)返回成功的話,,OD會利用EnumProcessModules枚舉模塊并獲取第一個模塊句柄,,如果EnumProcessModules返回成功,OD會利用GetModuleFileNameExA獲取模塊全路徑,最后把進(jìn)程ID和 模塊全路徑 按順序保存到上面建立的 進(jìn)程表 中,; 004751DB loc_4751DB: 004751DB mov eax, [edi] 004751DD cmp eax, [ebp+var_10]// 判斷是否等于OD本身ID 004751E0 jz loc_47529B 004751E6 push eax ; dwProcessId 004751E7 push 0 ; bInheritHandle 004751E9 push 410h ; dwDesiredAccess 004751EE call OpenProcess 004751F3 mov [ebp+hObject], eax 004751F6 cmp [ebp+hObject], 0//判斷進(jìn)程是否打開成功 004751FA jz loc_47529B 00475200 lea edx, [ebp+var_C] 00475203 lea ecx, [ebp+var_1C] 00475206 push edx 00475207 push 4 00475209 push ecx 0047520A mov eax, [ebp+hObject] 0047520D push eax 0047520E call [ebp+var_20] //EnumProcessModules枚舉進(jìn)程模塊 00475211 test eax, eax 00475213 jnz short loc_475220 00475215 mov edx, [ebp+hObject] 00475218 push edx ; hObject 00475219 call CloseHandle//如果EnumProcessModules不成功則關(guān)閉句柄 0047521E jmp short loc_47529B 如果EnumProcessModules成功則走如下分支 00475220 loc_475220: 00475220 mov ecx, [edi] ; int 00475222 xor eax, eax ; int 00475224 mov dword ptr [ebp+arglist], ecx//把進(jìn)程ID保存到一臨時結(jié)構(gòu)體中 0047522A lea edx, [ebp+var_528] 00475230 mov [ebp+var_730], 1 0047523A mov [ebp+var_72C], eax 00475240 mov [ebp+var_528], 0 00475247 push 104h 0047524C push edx 0047524D mov ecx, [ebp+var_1C] 00475250 push ecx 00475251 mov eax, [ebp+hObject] 00475254 push eax 00475255 call [ebp+var_24]//GetModuleFileNameExA獲得模塊路徑 00475258 mov [ebp+var_425], 0 0047525F mov edx, [ebp+hObject] 00475262 push edx ; hObject 00475263 call CloseHandle//關(guān)閉打開的進(jìn)程句柄 00475268 push 0 0047526A lea ecx, [ebp+var_728] 00475270 push ecx 00475271 push 0 00475273 push 0 00475275 lea eax, [ebp+var_528] 0047527B push eax 0047527C call 004A51BC //把模塊路徑復(fù)制到臨時變量結(jié)構(gòu)體中 00475281 add esp, 14h 00475284 lea edx, [ebp+arglist] ; int 0047528A mov [ebp+var_628], 0 00475291 push edx ; arglist 00475292 push esi ; src 00475293 call _Addsorteddata //把包含了進(jìn)程ID與模塊路徑的臨時結(jié)構(gòu)體添加到進(jìn)程表中 00475298 add esp, 8 0047529B loc_47529B: 0047529B inc [ebp+var_4] 0047529E add edi, 4 004752A1 mov ecx, [ebp+var_4] 004752A4 cmp ecx, [ebp+var_8] //檢查比較次數(shù)是否小于枚舉到的進(jìn)程個數(shù) 004752A7 jl loc_4751DB //小于則繼續(xù)循環(huán) 枚舉完進(jìn)程后接著檢查進(jìn)程表中保存的數(shù)據(jù)是否小于等于0;如果小于等于則直接返回,; 反之則EnumWindows,并利用GetWindowText函數(shù)獲取桌面窗口的標(biāo)題 保存到 進(jìn)程表中 對應(yīng)的進(jìn)程數(shù)據(jù)中 004753E9 cmp dword ptr [esi+104h], 0//比較進(jìn)程表中數(shù)據(jù)是否小于0 004753F0 jle short loc_4753FD 004753F2 push esi //此處的參數(shù)是 進(jìn)程表的首地址 004753F3 push offset sub_477A90 ; lpEnumFunc 004753F8 call EnumWindows 以下是EnumWindowsProc的功能 00477AA8 lea edx, [ebp+dwProcessId] 00477AAB push edx ; lpdwProcessId 00477AAC mov ecx, [ebp+hWnd] 00477AAF push ecx //枚舉的窗口進(jìn)程的句柄 00477AB0 call GetWindowThreadProcessId //獲得窗口的進(jìn)程ID 下面是個循環(huán) 利用上面得到的進(jìn)程ID與進(jìn)程表中保存的進(jìn)程ID做比較,,如果相等 則GetWindowTextA獲得窗口標(biāo)題,,并把得到的數(shù)據(jù)保存在進(jìn)程表中對應(yīng)的位置 00477ABB loc_477ABB: ; CODE XREF: sub_477A90+75 j 00477ABB mov edx, [ebx] 00477ABD cmp edx, [ebp+dwProcessId] 00477AC0 jnz short loc_477AF8 00477AC2 cmp byte ptr [ebx+10Ch], 0 00477AC9 jnz short loc_477AF8 00477ACB push 100h ; nMaxCount 00477AD0 mov ecx, eax 00477AD2 lea eax, [ecx+eax*2] 00477AD5 shl eax, 4 00477AD8 add eax, ecx 00477ADA shl eax, 4 00477ADD add esi, eax 00477ADF add esi, 10Ch 00477AE5 push esi //此buffer既為進(jìn)程表中不同進(jìn)程對應(yīng)的數(shù)據(jù)地址 00477AE6 mov eax, [ebp+hWnd] 00477AE9 push eax ; hWnd 00477AEA call GetWindowTextA //獲得枚舉的窗口的標(biāo)題并保存到進(jìn)程表中對應(yīng)的進(jìn)程數(shù)據(jù)中 00477AEF mov byte ptr [ebx+20Bh], 0 00477AF6 jmp short loc_477B07獲得后跳出循環(huán) 利用枚舉到的下一個窗口再次執(zhí)行此函數(shù) 如果進(jìn)程ID不相等則繼續(xù)循環(huán) 00477AF8 inc eax 00477AF9 add ebx, 310h 0x310為結(jié)構(gòu)體大小 00477AFF loc_477AFF: 00477AFF cmp eax, [edi+104h] //檢查比較的次數(shù) 是否大于進(jìn)程表中 的進(jìn)程數(shù) 00477B05 jl short loc_477ABB 在EnumWindows函數(shù)執(zhí)行完成返回后,,OD會調(diào)用InvalidateRect函數(shù),,使顯示進(jìn)程的窗口重繪; 004782F8 push 0 ; bErase 004782FA push 0 ; lpRect 004782FC mov edx, dword_4ED3F8 00478302 push edx ; hWnd 00478303 call InvalidateRect OD會對進(jìn)程表中的 ID號,把相對應(yīng)的索引數(shù)據(jù)進(jìn)行從小到大的排序.. 004AC501 jz short loc_4AC51C 004AC503 mov edx, [ebp+fcmp] 004AC506 mov ecx, [ebp+nelem] 004AC509 push ecx //第一個參數(shù)為進(jìn)程表中的數(shù)據(jù)個數(shù) 004AC50A mov dword_50A5F8, edx 004AC510 mov eax, [ebp+base] //第二個參數(shù)為進(jìn)程表中索引數(shù)據(jù)的首地址 004AC513 push eax 004AC514 call sub_4AC310 最終函數(shù)會調(diào)用到進(jìn)程表結(jié)構(gòu)體中偏移0x120位置保存的函數(shù)地址; 當(dāng)從進(jìn)程窗口列表框中選擇要附加的進(jìn)程并點擊附加按鈕后,OD會記錄其序號,,并通過序號計算出此進(jìn)程在 進(jìn)程表中的 偏移位置,,通過偏移位置得到進(jìn)程ID 004784A5 mov eax, dword_4ED508//得到要附加進(jìn)程在列表框中的位置 004784AA test eax, eax 004784AC jl loc_47867B//如果進(jìn)程號小于0則直接返回; 004784B2 cmp eax, dword_4ED500/比較序號是否大于進(jìn)程總數(shù) 004784B8 jge loc_47867B //大于也直接返回 004784BE mov edx, dword_4ED52C 004784C4 mov esi, [edx+eax*4] 004784C7 imul esi, dword_4ED510 004784CE add esi, dword_4ED518 //上面幾步是計算得出附加的進(jìn)程在進(jìn)程表中存儲的首地址 004784D4 mov eax, [esi] //得到進(jìn)程ID 004784D6 cmp eax, dword_4D5A70 //判斷OD是否正在調(diào)試此程序 004784DC jnz short loc_4784F4 如果此時OD正在調(diào)試此程序則會彈出一錯誤框提示 進(jìn)程“xxxx”是你正在調(diào)試的程序…… 并直接返回,。 004784DE add esi, 0Ch 004784E1 push esi ; arglist 004784E2 push offset asc_4C2122 ; "? 004784E7 call _Error 004784EC add esp, 8 004784EF jmp loc_47867B//直接返回.. 接著OD會申請一定的空間并初始化一些表,,如:dll句柄表,,線程表,,統(tǒng)計表,等等… 004784F4 loc_4784F4: 004784F4 push 1 004784F6 call sub_4758A4 004784FB pop ecx 004784FC test eax, eax 004784FE jnz loc_47867B 00478504 call sub_47540C //此函數(shù)用于申請空間并初始化表 00478509 test eax, eax //判斷是否初始化成功,。 0047850B jz short loc_47851D 0047850D push offset aIFUC ; "無法分配足夠內(nèi)存" 00478512 call _Error//如果不成功則會報告內(nèi)存內(nèi)存不足…并直接返回 00478517 pop ecx 00478518 jmp loc_47867B 在0046b258這個函數(shù)中OD會根據(jù)用戶設(shè)置的導(dǎo)入庫保存在ollydbg.ini文件中的[Import libraries]項解析調(diào)試程序中的庫函數(shù); 下面就是處理的一個循環(huán)過程 0046B268 loc_46B268: 0046B268 push ebx 0046B269 lea eax, [edi+4F8h] 0046B26F push eax ; format 0046B270 lea edx, [esp+318h+buffer] 0046B277 push edx ; buffer 0046B278 call _sprintf 0046B27D add esp, 0Ch 0046B280 push offset FileName ; lpFileName 0046B285 push 104h ; nSize 0046B28A lea ecx, [esp+318h+path] 0046B28E push ecx ; lpReturnedString 0046B28F lea eax, [edi+4] 0046B292 push eax ; lpDefault 0046B293 lea edx, [esp+320h+buffer] 0046B29A push edx ; lpKeyName 0046B29B lea ecx, [edi+503h] 0046B2A1 push ecx ; lpAppName 0046B2A2 call GetPrivateProfileStringA //得到ollydbg.ini 文件中[Import libraries]項中的路徑 0046B2A7 cmp [esp+310h+path], 0 0046B2AB jz short loc_46B2E6 0046B2AD mov eax, hCursor 0046B2B2 push eax ; hCursor 0046B2B3 call SetCursor 0046B2B8 mov esi, eax 0046B2BA xor eax, eax 0046B2BC mov dword_4EAE50, eax 0046B2C1 push 0 ; int 0046B2C3 lea edx, [esp+314h+arglist] 0046B2CA push edx ; arglist 0046B2CB lea ecx, [esp+318h+path] 0046B2CF push ecx ; path 0046B2D0 call sub_469818//此函數(shù)里面主要是負(fù)責(zé)解析的函數(shù) 0046B2D5 add esp, 0Ch 0046B2D8 call sub_46718C 0046B2DD cmp dword_4EAE50, 0 0046B2E4 jnz short loc_46B2F3 0046B2E6 0046B2E6 loc_46B2E6: 0046B2E6 inc ebx 0046B2E7 cmp ebx, 0C8h 0046B2ED jl loc_46B268 等做完上面的工作后,,OD才開始真正的附加 主要是通過DebugActiveProcess對程序附加 00478522 mov eax, [esi] 00478524 push eax /要附加的進(jìn)程ID 00478525 call DebugActiveProcess 0047852A test eax, eax 之后OD按一定格式設(shè)置窗口標(biāo)題; 004785A5 push edx 004785A6 push offset byte_4D5A7C 004785AB push offset aOllyice ; "OllyICE" 004785B0 push offset aSSS_0 ; "%s - %s%s" 004785B5 lea ecx, [ebp+buffer] 004785BB push ecx ; buffer 004785BC call _sprintf 004785C1 add esp, 14h 004785C4 lea eax, [ebp+buffer] ; int 004785CA push eax ; lpString 004785CB mov edx, hWnd 004785D1 push edx ; hWnd 004785D2 call SetWindowTextA 然后OD會對ollydbg.ini文件中的[History],[Arguments]兩項進(jìn)行設(shè)置……下面只貼出部分代碼 00476F08 lea edx, [ebx+1] 00476F0B push edx 00476F0C lea ecx, [edi+6DAh] 00476F12 push ecx ; format 00476F13 lea eax, [ebp+buffer] 00476F19 push eax ; buffer 00476F1A call _sprintf 00476F1F mov edx, ebx 00476F21 add esp, 0Ch 00476F24 shl edx, 6 00476F27 lea ecx, [ebp+var_518] 00476F2D add edx, ebx 00476F2F push offset FileName ; lpFileName 00476F34 shl edx, 2 00476F37 lea eax, [ebp+buffer] 00476F3D add edx, ecx 00476F3F push edx ; lpString 00476F40 lea edx, [edi+6E9h] 00476F46 push eax ; lpKeyName 00476F47 push edx ; lpAppName 00476F48 call WritePrivateProfileStringA 接著OD設(shè)置程序狀態(tài),,并退出Dialog對話框… 0047860E push 0 ; name 00478610 push offset byte_4D5A7C ; int 00478615 call sub_409370 0047861A add esp, 8 0047861D push 3 //設(shè)置狀態(tài)為運行 0047861F call sub_431978 00478624 pop ecx 00478625 push 0 ; nResult 00478627 push ebx ; hDlg 00478628 call EndDialog //結(jié)束附加窗口 0047862D jmp short loc_47867B DebugActiveProcess附加程序后,系統(tǒng)會為進(jìn)程中的每一個創(chuàng)建線程,,向調(diào)試器發(fā)送CREATE_THREAD_DEBUG_EVENT調(diào)試事件,會為進(jìn)程中的每個動態(tài)加載DLL向調(diào)試器發(fā)送LOAD_DLL_DEBUG_EVENT調(diào)試事件.. OD通過WaitForDebugEvent函數(shù)獲得這些事件,,做相應(yīng)處理,并調(diào)用ContinueDebugEvent使程序繼續(xù)執(zhí)行…..當(dāng)這些都做完后,,系統(tǒng)恢復(fù)進(jìn)程中的所有線程,并且在第一個線程恢復(fù)的時候會執(zhí)行 一個 斷點指令,,最后會調(diào)用Ntdll.dll中的DbgBreakPoint函數(shù) 而根據(jù)跟蹤得知DbgBreakPoint中的實現(xiàn) 就是一個int3指令; dwDebugEventCode事件處理表: 0042EBF7 mov edx, DebugEvent.dwDebugEventCode 0042EBFD cmp edx, 9 ; switch 10 cases 0042EC00 ja loc_4313F4 ; default 0042EC00 ; jumptable 0042EC06 case 0 0042EC06 jmp ds:off_42EC0D[edx*4] ; switch jump 0042EC06 ; --------------------------------------------------------------------------- 0042EC0D off_42EC0D dd offset loc_4313F4 ; DATA XREF: sub_42EBD0+36 r 0042EC0D dd offset loc_42EC35 ; jump table for switch 0042EC0D dd offset loc_430CFF 0042EC0D dd offset loc_430DD7 0042EC0D dd offset loc_430F3F 0042EC0D dd offset loc_431037 0042EC0D dd offset loc_43112D 0042EC0D dd offset loc_4311B7 0042EC0D dd offset loc_431276 0042EC0D dd offset loc_4313C7 DbgBreakPoint的實現(xiàn) 7C92120E > CC int3 7C92120F C3 retn 因此當(dāng)程序執(zhí)行到此時,,會引起一個EXCEPTION_DEBUG_EVENT事件,OD通過WaitForDebugEvent函數(shù)會獲得此調(diào)試事件…OD在獲得EXCEPTION_DEBUG_EVENT事件后,,之后并沒有調(diào)用ContinueDebugEvent使程序執(zhí)行。因此OD會停到DbgBreakPoint處,,也就是EIP會指在retn處。 武漢科銳學(xué)員: comewhere |
|