OD版本:OllyICE v1.10ide
在從文件菜單選擇附加後,OD會在註冊一個窗口類後,先建立一個0x138大小的進程表; 再是CreateWindowExA 建立窗口;函數
00478013 loc_478013: 線程
00478013 push 0 ; int調試
00478015 push offset sub_477C10 ; intorm
0047801A push 100h ; int排序
0047801F push 310h ; int索引
00478024 push offset asc_4C20E8 ; "?進程
00478029 push offset byte_4ED3FC ; dest事件
0047802E call _Createsorteddata //此處爲建立進程表內存
表的結構體以下:
table struc ; (sizeof=0x138)
name db 260 dup(?) //表的名字
count dd ? //表中保存的數據個數
maxcount dd ? //表能保存的最大數量
currentobj dd ? //當前選中的表中數據的ID,未選中時爲爲-1
addrcurobj dd ? //當前選中數據的地址,未選中時爲0
size dd ? //表中每一個數據的大小
field_118 dd ?
baseaddrobj dd ? //表中保存的數據的基地址
fncmp dd ? //函數首地址
field_124 dd ?
field_128 dd ?
sign dd ? //標誌位,表示是否有索引數據(也就是baseaddroffset是否有效)
baseaddroffset dd ? //索引數據,標示每一個數據在表中的順序
field_134 dd ?
table ends
而後OD會獲取本身的進程ID號,並獲取EnumProcesses ,EnumProcessModules,GetModuleFileNameExA 三個函數的地址;
00475138 loc_475138:
00475138 xor ebx, ebx
0047513A call GetCurrentProcessId //獲取OD自己的進程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枚舉系統中的全部進程並保存枚舉到的進程;
004751A3 push eax
004751A4 push 400h
004751A9 push edx
004751AA call edi // EnumProcesses 枚舉進程
004751AC test eax, eax
004751AE jnz short loc_4751B3
接着再一個循環中OD會嘗試利用OpenProcess打開枚舉到的全部進程,若是進程ID不等於OD自己ID 而且OpenProcess函數返回成功的話,OD會利用EnumProcessModules枚舉模塊並獲取第一個模塊句柄,若是EnumProcessModules返回成功,OD會利用GetModuleFileNameExA獲取模塊全路徑,最後把進程ID和 模塊全路徑 按順序保存到上面創建的 進程表 中;
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//判斷進程是否打開成功
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枚舉進程模塊
00475211 test eax, eax
00475213 jnz short loc_475220
00475215 mov edx, [ebp+hObject]
00475218 push edx ; hObject
00475219 call CloseHandle//若是EnumProcessModules不成功則關閉句柄
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//把進程ID保存到一臨時結構體中
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//關閉打開的進程句柄
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 //把模塊路徑複製到臨時變量結構體中
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 //把包含了進程ID與模塊路徑的臨時結構體添加到進程表中
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] //檢查比較次數是否小於枚舉到的進程個數
004752A7 jl loc_4751DB //小於則繼續循環
枚舉完進程後接着檢查進程表中保存的數據是否小於等於0;若是小於等於則直接返回;
反之則EnumWindows,並利用GetWindowText函數獲取桌面窗口的標題
保存到 進程表中 對應的進程數據中
004753E9 cmp dword ptr [esi+104h], 0//比較進程表中數據是否小於0
004753F0 jle short loc_4753FD
004753F2 push esi //此處的參數是 進程表的首地址
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 //枚舉的窗口進程的句柄
00477AB0 call GetWindowThreadProcessId //得到窗口的進程ID
下面是個循環 利用上面獲得的進程ID與進程表中保存的進程ID作比較,若是相等 則GetWindowTextA得到窗口標題,並把獲得的數據保存在進程表中對應的位置
00477ABB loc_477ABB: ; CODE XREF: sub_477A90+75j
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既爲進程表中不一樣進程對應的數據地址
00477AE6 mov eax, [ebp+hWnd]
00477AE9 push eax ; hWnd
00477AEA call GetWindowTextA //得到枚舉的窗口的標題並保存到進程表中對應的進程數據中
00477AEF mov byte ptr [ebx+20Bh], 0
00477AF6 jmp short loc_477B07得到後跳出循環 利用枚舉到的下一個窗口再次執行此函數
若是進程ID不相等則繼續循環
00477AF8 inc eax
00477AF9 add ebx, 310h 0x310爲結構體大小
00477AFF loc_477AFF:
00477AFF cmp eax, [edi+104h] //檢查比較的次數 是否大於進程表中 的進程數
00477B05 jl short loc_477ABB
在EnumWindows函數執行完成返回後,OD會調用InvalidateRect函數,使顯示進程的窗口重繪;
004782F8 push 0 ; bErase
004782FA push 0 ; lpRect
004782FC mov edx, dword_4ED3F8
00478302 push edx ; hWnd
00478303 call InvalidateRect
OD會對進程表中的 ID號,把相對應的索引數據進行從小到大的排序..
004AC501 jz short loc_4AC51C
004AC503 mov edx, [ebp+fcmp]
004AC506 mov ecx, [ebp+nelem]
004AC509 push ecx //第一個參數爲進程表中的數據個數
004AC50A mov dword_50A5F8, edx
004AC510 mov eax, [ebp+base] //第二個參數爲進程表中索引數據的首地址
004AC513 push eax
004AC514 call sub_4AC310
最終函數會調用到進程表結構體中偏移0x120位置保存的函數地址;
當從進程窗口列表框中選擇要附加的進程並點擊附加按鈕後,OD會記錄其序號,並經過序號計算出此進程在 進程表中的 偏移位置,經過偏移位置獲得進程ID
004784A5 mov eax, dword_4ED508//獲得要附加進程在列表框中的位置
004784AA test eax, eax
004784AC jl loc_47867B//若是進程號小於0則直接返回;
004784B2 cmp eax, dword_4ED500/比較序號是否大於進程總數
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 //上面幾步是計算得出附加的進程在進程表中存儲的首地址
004784D4 mov eax, [esi] //獲得進程ID
004784D6 cmp eax, dword_4D5A70 //判斷OD是否正在調試此程序
004784DC jnz short loc_4784F4
若是此時OD正在調試此程序則會彈出一錯誤框提示 進程「xxxx」是你正在調試的程序……
並直接返回。
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句柄表,線程表,統計表,等等…
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 //此函數用於申請空間並初始化表
00478509 test eax, eax //判斷是否初始化成功。
0047850B jz short loc_47851D
0047850D push offset aIFUC ; "沒法分配足夠內存"
00478512 call _Error//若是不成功則會報告內存內存不足…並直接返回
00478517 pop ecx
00478518 jmp loc_47867B
在0046b258這個函數中OD會根據用戶設置的導入庫保存在ollydbg.ini文件中的[Import libraries]項解析調試程序中的庫函數;
下面就是處理的一個循環過程
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//此函數裏面主要是負責解析的函數
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 /要附加的進程ID
00478525 call DebugActiveProcess
0047852A test eax, eax
以後OD按必定格式設置窗口標題;
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]兩項進行設置……下面只貼出部分代碼
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設置程序狀態,並退出Dialog對話框…
0047860E push 0 ; name
00478610 push offset byte_4D5A7C ; int
00478615 call sub_409370
0047861A add esp, 8
0047861D push 3 //設置狀態爲運行
0047861F call sub_431978
00478624 pop ecx
00478625 push 0 ; nResult
00478627 push ebx ; hDlg
00478628 call EndDialog //結束附加窗口
0047862D jmp short loc_47867B
DebugActiveProcess附加程序後,系統會爲進程中的每個建立線程,向調試器發送CREATE_THREAD_DEBUG_EVENT調試事件,會爲進程中的每一個動態加載DLL向調試器發送LOAD_DLL_DEBUG_EVENT調試事件.. OD經過WaitForDebugEvent函數得到這些事件,作相應處理,並調用ContinueDebugEvent使程序繼續執行…..當這些都作完後,系統恢復進程中的全部線程,而且在第一個線程恢復的時候會執行 一個 斷點指令,最後會調用Ntdll.dll中的DbgBreakPoint函數 而根據跟蹤得知DbgBreakPoint中的實現 就是一個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+36r
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的實現
7C92120E > CC int3
7C92120F C3 retn
所以當程序執行到此時,會引發一個EXCEPTION_DEBUG_EVENT事件,OD經過WaitForDebugEvent函數會得到此調試事件…OD在得到EXCEPTION_DEBUG_EVENT事件後,以後並無調用ContinueDebugEvent使程序執行。所以OD會停到DbgBreakPoint處,也就是EIP會指在retn處。