標(biāo) 題: 【原創(chuàng)】OllyDBG分析報(bào)告系列(1)---Int3斷點(diǎn) 作 者: driverox 時(shí) 間: 2008-05-19,16:45:43 鏈 接: http://bbs./showthread.php?t=65094 最近學(xué)習(xí)逆向,對(duì)OD本身做了個(gè)逆向,也算是一個(gè)小小的鍛煉吧。呵呵,在這里以分析報(bào)告的形式貼出來(lái),請(qǐng)大家批評(píng)指正。謝謝。 ![]() Ollydbg(以下均簡(jiǎn)稱為OD)中的Int3斷點(diǎn)的主要功能是:在需要下斷點(diǎn)的執(zhí)行代碼處將原來(lái)的代碼改成0xCC,程序執(zhí)行到此處后會(huì)報(bào)一個(gè)Int3異常,由OD捕獲并處理。當(dāng)要執(zhí)行該行代碼時(shí),將原來(lái)的代碼改回來(lái)并執(zhí)行,然后再恢復(fù)斷點(diǎn),這樣就不會(huì)影響程序的正常運(yùn)行了。 這里僅描述最常見(jiàn)的功能,其它的有興趣的話可以分析一把。 先說(shuō)明一下OD中的兩個(gè)結(jié)構(gòu)體,在IDA中,聲明為如下格式: t_bpoint用來(lái)保存Int斷點(diǎn)的相關(guān)信息 00000000 t_bpoint struc ; (sizeof=0x11) 00000000 addr dd ? ; // Address of breakpoint 00000004 dummy dd ? ; // Always 1 00000008 type dd ? ; // Type of breakpoint, TY_xxx 0000000C cmd db ? ; // Old value of command 0000000D passcount dd ? ; // Actual pass count 00000011 t_bpoint ends 其中:addr為斷點(diǎn)的地址,dummy始終為1,type為斷點(diǎn)的類(lèi)型,cmd為要用0xCC替換的指令碼,passcount為需要斷下的次數(shù),0表示每次都斷下。 t_sorted結(jié)構(gòu)體保存了一種有序的數(shù)據(jù): 00000000 ; Descriptor of sorted table 00000000 t_sorted struc ; (sizeof=0x138) 00000000 name[MAXPATH] db 260 dup(?) ; char Name of table, as appears in error messages 00000104 n dd ? ; int Actual number of entries 00000108 nmax dd ? ; int Maximal number of entries 0000010C selected dd ? ; int Index of selected entry or -1 00000110 seladdr dd ? ; ulong Base address of selected entry 00000114 itemsize dd ? ; int Size of single entry 00000118 version dd ? ; ulong Unique version of table 0000011C data dd ? ; void* Elements, sorted by address 00000120 sortfunc dd ? ; SORTFUNC Function which sorts data or NULL 00000124 destfunc dd ? ; DESTFUNC Destructor function or NULL 00000128 sort dd ? ; int Sorting criterium (column) 0000012C sorted dd ? ; int Whether indexes are sorted 00000130 index dd ? ; int Indexes, sorted by criterium 00000134 suppresserr dd ? ; int Suppress multiple overflow errors 00000138 t_sorted ends name是結(jié)構(gòu)體的名稱,用來(lái)區(qū)別不同類(lèi)型的結(jié)構(gòu)體 n是數(shù)組元素的個(gè)數(shù) itemsize是數(shù)組元素的大小 data 是指向各種數(shù)據(jù)結(jié)構(gòu)數(shù)組的指針,這里使用的是int3斷點(diǎn),所以現(xiàn)在保存的是int3斷點(diǎn)數(shù)據(jù)結(jié)構(gòu)體數(shù)組的指針 --------------------------------------------------------------------------------------------------------------------------------- 1)Int3斷點(diǎn)的設(shè)置 int3斷點(diǎn)的設(shè)置是通過(guò)消息來(lái)處理的,對(duì)應(yīng)右鍵點(diǎn)擊菜單中的切換,其對(duì)應(yīng)的消息為1E;此外還有熱鍵F2、雙擊反匯編窗口等也能切換int3斷點(diǎn),轉(zhuǎn)入的函數(shù)雖然不同,但是調(diào)用設(shè)置int3斷點(diǎn)的函數(shù)都是同一個(gè),就不再舉例了。傳入相應(yīng)參數(shù)調(diào)用函數(shù)00419974,改變int3斷點(diǎn),該函數(shù)的調(diào)用處如下: 004237C8 . 51 push ecx ; |Arg6 004237C9 . 50 push eax ; |Arg5 => 00000002 004237CA . 6A 00 push 0 ; |Arg4 = 00000000 004237CC . 6A 00 push 0 ; |Arg3 = 00000000 004237CE . 6A 71 push 71 ; |Arg2 = 00000071 004237D0 . 52 push edx ; |Arg1 => 0040100C 004237D1 . E8 9E61FFFF call 00419974 ; \OLLYDBG.00419974 下面主要來(lái)分析上述的00419974這個(gè)函數(shù),經(jīng)過(guò)分析可知大致主要流程為: 1. 判斷是否配置了“Warn when break not in code”為1,若為1的話,程序會(huì)先判斷所下斷點(diǎn)是否在代碼區(qū),不在的話,會(huì)顯示警告消息,若用戶選擇繼續(xù),則會(huì)斷下,否則退出; 2. 若沒(méi)有配置上面的項(xiàng)目,則首先獲得斷點(diǎn)的類(lèi)型(即斷點(diǎn)類(lèi)型的高位是否為2,若為2則刪除斷點(diǎn),不為2則設(shè)置斷點(diǎn)),檢查該地址的斷點(diǎn)是否已經(jīng)存在,若存在,則刪除斷點(diǎn),并退出; 3. 若該地址處無(wú)Int3斷點(diǎn),則設(shè)置斷點(diǎn),使用的是Setbreakpointext函數(shù),其流程如下: a) 獲得斷點(diǎn)在調(diào)試進(jìn)程中實(shí)際地址; b) 判斷指令碼是否有效(判斷規(guī)則是:指令碼與1F做與運(yùn)算之后為3或13的時(shí)候,說(shuō)明是斷在指令碼中間;1D、1E、1F是正常指令碼,除此之外,其它的都是無(wú)法執(zhí)行的指令碼),無(wú)效的話,重新設(shè)置CPU窗口,顯示錯(cuò)誤提示并退出; c) 在t_sorted結(jié)構(gòu)中查找斷點(diǎn)數(shù)據(jù); d) 若t_sorted中不存在該斷點(diǎn),則添加; e) 判斷被調(diào)試進(jìn)程是否在運(yùn)行狀態(tài),若在運(yùn)行,則把所有的線程都掛起; f) 讀取斷點(diǎn)所在地址的內(nèi)存,若讀取成功的話,調(diào)用WriteMemory寫(xiě)入0xCC斷點(diǎn)(跟入WriteMemory后,發(fā)現(xiàn)是調(diào)用WriteProcessMemory這個(gè)API函數(shù)來(lái)下Int3斷點(diǎn)的); g) 恢復(fù)線程運(yùn)行; h) 顯示信息在窗口中; 4. 若設(shè)置斷點(diǎn)成功,則插入name并做其它的一些判斷與顯示操作,進(jìn)而退出; 保存現(xiàn)場(chǎng),提升棧幀空間,用于存放局部變量: 00419974 /$ 55 push ebp 00419975 |. 8BEC mov ebp, esp 00419977 |. 81C4 F8FBF>add esp, -408 0041997D |. 53 push ebx 0041997E |. 56 push esi 0041997F |. 57 push edi 檢查OD配置文件中的 “Warn when break not in code”是否為1,1為真,0為假,若上面的配置為0,則跳到下面的處理代碼中: 00419980 |. 8B7D 14 mov edi, dword ptr [ebp+14] 00419983 |. 8B5D 08 mov ebx, dword ptr [ebp+8] 00419986 |. 833D C4574>cmp dword ptr [4D57C4], 0 ; 4D57C4--Warn when break not in code 0041998D |. 74 5E je short 004199ED ;為0則跳轉(zhuǎn)到下面的處理代碼 檢查傳入的參數(shù)是否正確: 0041998F |. 837D 0C 71 cmp dword ptr [ebp+C], 71 00419993 |. 75 12 jnz short 004199A7 00419995 |. 837D 10 00 cmp dword ptr [ebp+10], 0 00419999 |. 75 0C jnz short 004199A7 先在t_sorted列表中查找int3斷點(diǎn),找不到返回8,并跳過(guò)取得模塊信息部分: 0041999B |. 53 push ebx 0041999C |. E8 D703000>call _Getbreakpointtype 004199A1 |. F6C4 02 test ah, 2 ;檢查返回值是否為20h 004199A4 |. 59 pop ecx 004199A5 |. 75 46 jnz short 004199ED ;不是則跳過(guò)取得模塊信息部分 取得模塊信息,并檢查是否取得,若取得失敗則跳轉(zhuǎn)到顯示斷點(diǎn)錯(cuò)誤消息分支: 004199A7 |> 53 push ebx ; /Arg1 004199A8 |. E8 6B44040>call _Findmodule ; \_Findmodule 004199AD |. 59 pop ecx 004199AE |. 8BF0 mov esi, eax 004199B0 |. 85C0 test eax, eax ;檢查是否得到模塊信息 004199B2 |. 74 0F je short 004199C3 ;沒(méi)有得到則跳轉(zhuǎn)到下面錯(cuò)誤顯示分支 004199B4 |. 3B5E 0C cmp ebx, dword ptr [esi+C] 004199B7 |. 72 0A jb short 004199C3 004199B9 |. 8B56 0C mov edx, dword ptr [esi+C] 004199BC |. 0356 10 add edx, dword ptr [esi+10] 004199BF |. 3BDA cmp ebx, edx 004199C1 |. 72 2A jb short 004199ED 顯示斷點(diǎn)錯(cuò)誤消息,若用戶選擇Yes則繼續(xù),否則退出: 004199C3 |> 68 2421000>push 2124 ; /Style = MB_YESNO 004199C8 |. 68 40274B0>push 004B2740 ; |Title 004199CD |. 68 C3284B0>push 004B28C3 ; |Text 004199D2 |. 8B0D 7C3B4>mov ecx, dword ptr [4D3B7C] ; | 004199D8 |. 51 push ecx ; |hOwner 004199D9 |. E8 385B090>call <jmp.&USER32.MessageBoxA> ; \MessageBoxA 004199DE |. 8BF0 mov esi, eax 004199E0 |. 83FE 06 cmp esi, 6 004199E3 |. 74 08 je short 004199ED 004199E5 |. 83C8 FF or eax, FFFFFFFF ;返回-1 004199E8 |. E9 8403000>jmp 00419D71 ;跳轉(zhuǎn)到結(jié)束處 得到該地址int3斷點(diǎn)的屬性,如果已經(jīng)設(shè)置了int3斷點(diǎn),則將其刪除并跳轉(zhuǎn)到結(jié)束處;若沒(méi)有設(shè)置,則跳過(guò)刪除部分代碼: 004199ED |> 837D 0C 71 cmp dword ptr [ebp+C], 71 004199F1 |. 0F85 24020>jnz 00419C1B 004199F7 |. 837D 10 00 cmp dword ptr [ebp+10], 0 004199FB |. 75 20 jnz short 00419A1D 004199FD |. 53 push ebx 004199FE |. E8 7503000>call _Getbreakpointtype ;得到該地址的int3斷點(diǎn)的屬性 00419A03 |. F6C4 02 test ah, 2 ;比較是否已經(jīng)設(shè)置了int3斷點(diǎn) 00419A06 |. 59 pop ecx 00419A07 |. 74 14 je short 00419A1D ;若沒(méi)有設(shè)置則跳過(guò)刪除斷點(diǎn)的代碼 00419A09 |. 6A 00 push 0 ; /Arg3 = 00000000 00419A0B |. 8D53 01 lea edx, dword ptr [ebx+1] ; | 00419A0E |. 52 push edx ; |Arg2 00419A0F |. 53 push ebx ; |Arg1 00419A10 |. E8 03FBFFF>call _Deletebreakpoints ; \_Deletebreakpoints 00419A15 |. 83C4 0C add esp, 0C 00419A18 |. E9 4103000>jmp 00419D5E 在這里有對(duì)傳入?yún)?shù)的一個(gè)比較,但是測(cè)試時(shí)無(wú)法得到0以外的值,所以無(wú)法確定該參數(shù)的作用,這樣也無(wú)法測(cè)試00419A6D后面的代碼所表示的意義: 00419A1D |> 837D 10 00 cmp dword ptr [ebp+10], 0 00419A21 |. 75 4A jnz short 00419A6D 這里就是設(shè)置int3斷點(diǎn)的函數(shù),將地址傳入即可: 00419A23 |. 6A 00 push 0 ; /Arg4 = 00000000 00419A25 |. 6A 00 push 0 ; |Arg3 = 00000000 00419A27 |. 68 0002020>push 20200 ; |Arg2 = 00020200 00419A2C |. 53 push ebx ; |Arg1 00419A2D |. E8 2EFBFFF>call _Setbreakpointext ; \_Setbreakpointext 00419A32 |. 83C4 10 add esp, 10 設(shè)置完int3斷點(diǎn)后,刪除int3斷點(diǎn)處的name屬性為38h、3Ch、3Bh以及30h的name,然后跳轉(zhuǎn)到結(jié)束廣播處: 00419A35 |. 8D73 01 lea esi, dword ptr [ebx+1] 00419A38 |. 6A 38 push 38 ; /Arg3 = 00000038 00419A3A |. 56 push esi ; |Arg2 00419A3B |. 53 push ebx ; |Arg1 00419A3C |. E8 87B5040>call _Deletenamerange ; \_Deletenamerange 00419A41 |. 83C4 0C add esp, 0C 00419A44 |. 6A 3C push 3C ; /Arg3 = 0000003C 00419A46 |. 56 push esi ; |Arg2 00419A47 |. 53 push ebx ; |Arg1 00419A48 |. E8 7BB5040>call _Deletenamerange ; \_Deletenamerange 00419A4D |. 83C4 0C add esp, 0C 00419A50 |. 6A 3B push 3B ; /Arg3 = 0000003B 00419A52 |. 56 push esi ; |Arg2 00419A53 |. 53 push ebx ; |Arg1 00419A54 |. E8 6FB5040>call _Deletenamerange ; \_Deletenamerange 00419A59 |. 83C4 0C add esp, 0C 00419A5C |. 6A 30 push 30 ; /Arg3 = 00000030 00419A5E |. 56 push esi ; |Arg2 00419A5F |. 53 push ebx ; |Arg1 00419A60 |. E8 63B5040>call _Deletenamerange ; \_Deletenamerange 00419A65 |. 83C4 0C add esp, 0C 00419A68 |. E9 F102000>jmp 00419D5E ;跳轉(zhuǎn)到結(jié)束廣播處 這部分省略的代碼無(wú)法得知其調(diào)用的必要條件,不過(guò)里面的內(nèi)容跟上面相似,都是通過(guò)判斷來(lái)設(shè)置int3斷點(diǎn),這里就不再詳細(xì)說(shuō)明了: …… …… 向子窗體發(fā)送廣播,要求更新所有子窗口: 00419D5E |> 6A 00 push 0 ; /Arg3 = 00000000 00419D60 |. 6A 00 push 0 ; |Arg2 = 00000000 00419D62 |. 68 7404000>push 474 ; |Arg1 = 00000474 00419D67 |. E8 0807040>call _Broadcast ; \_Broadcast 00419D6C |. 83C4 0C add esp, 0C 最后返回0,并且恢復(fù)現(xiàn)場(chǎng): 00419D6F |. 33C0 xor eax, eax 00419D71 |> 5F pop edi 00419D72 |. 5E pop esi 00419D73 |. 5B pop ebx 00419D74 |. 8BE5 mov esp, ebp 00419D76 |. 5D pop ebp 00419D77 \. C3 retn 2)Int3斷點(diǎn)的處理 Int3斷點(diǎn)處理的大致流程是: 1、 獲取當(dāng)前寄存器的信息,重點(diǎn)是Eip的值 2、 根據(jù)Int3斷點(diǎn)的類(lèi)型(0xCC或0xCD03)回溯指針地址 3、 觸發(fā)Int3異常,被調(diào)試程序斷下; 4、 若繼續(xù)跑的話,則恢復(fù)原有的指令,讓被調(diào)試程序正確執(zhí)行指令; 5、 走完正確指令之后,再重新設(shè)置指令為Int3斷點(diǎn); 在OD中有一個(gè)處理所有異常的函數(shù)42EBD0,從該函數(shù)入手分析Int3斷點(diǎn)的處理。 0042EBD0 /$ 55 push ebp 0042EBD1 |. 8BEC mov ebp, esp 0042EBD3 |. 81C4 04F0FFFF add esp, -0FFC 0042EBD9 |. 50 push eax 0042EBDA |. 81C4 00F5FFFF add esp, -0B00 0042EBE0 |. 53 push ebx 0042EBE1 |. 56 push esi 0042EBE2 |. 57 push edi ;以上是開(kāi)棧幀代碼 0042EBE3 |. 8B35 1C574D00 mov esi, dword ptr [4D571C] ;4D571C為全局變量,保存的是DebugEvent.dwThreadId 0042EBE9 |. 56 push esi 0042EBEA |. E8 5DF8FFFF call 0042E44C 函數(shù)42E44C的主要功能描述如下: 函數(shù)功能:通過(guò)GetThreadContext的方法獲得線程的上下文環(huán)境,把該環(huán)境保存 至OD線程信息結(jié)構(gòu)中的reg字段中,若oldreg已經(jīng)失效,則復(fù)制reg的 值到oldreg中。 若被調(diào)試進(jìn)程有多個(gè)線程,則循環(huán)取值,保存至OD線程信息結(jié)構(gòu)數(shù)組中。 傳入?yún)?shù):DebugEvent.dwThreadId 返回值 :成功時(shí)為保存在OD線程信息結(jié)構(gòu)中的當(dāng)前寄存器信息結(jié)構(gòu)的指針(主線程) 失敗返回0 這里說(shuō)到了兩個(gè)結(jié)構(gòu)體,在IDA中描述如下: 00000000 t_reg struc ; (sizeof=0x196) ;保存寄存器信息 00000000 r_modified dd ? ; // Some regs modified, update context 00000004 r_modifiedbyuser dd ? ; // Among modified, some modified by user 00000008 r_singlestep dd ? ; // Type of single step, SS_xxx 0000000C r_EAX dd ? 00000010 r_ECX dd ? 00000014 r_EDX dd ? 00000018 r_EBX dd ? 0000001C r_ESP dd ? 00000020 r_EBP dd ? 00000024 r_ESI dd ? 00000028 r_EDI dd ? 0000002C r_EIP dd ? ; // Instruction pointer (EIP) 00000030 r_EFlags dd ? ; // Flags 00000034 r_top dd ? ; // Index of top-of-stack 00000038 r_long_double db 80 dup(?) ; // Float registers, f[top] - top of stack 00000088 r_tag db 8 dup(?) ; // Float tags (0x3 - empty register) 00000090 r_fst dd ? ; // FPU status word 00000094 r_fcw dd ? ; // FPU control word 00000098 r_ES dd ? 0000009C r_CS dd ? 000000A0 r_SS dd ? 000000A4 r_DS dd ? 000000A8 r_FS dd ? 000000AC r_GS dd ? 000000B0 r_base dd 6 dup(?) ; // Segment bases 000000C8 r_limit dd 6 dup(?) ; // Segment limits 000000E0 r_big db 6 dup(?) ; // Default size (0-16, 1-32 bit) 000000E6 r_dr6 dd ? ; // Debug register DR6 000000EA r_threadid dd ? ; // ID of thread that owns registers 000000EE r_lasterror dd ? ; // Last thread error or 0xFFFFFFFF 000000F2 r_ssevalid dd ? ; // Whether SSE registers valid 000000F6 r_ssemodified dd ? ; // Whether SSE registers modified 000000FA r_ssereg db 128 dup(?) ; // SSE registers 0000017A r_mxcsr dd ? ; // SSE control and status register 0000017E r_selected dd ? ; // Reports selected register to plugin 00000182 r_dr0 dd ? ; // Debug registers DR0..DR3 00000186 r_dr1 dd ? 0000018A r_dr2 dd ? 0000018E r_dr3 dd ? 00000192 r_dr7 dd ? ; // Debug register DR7 00000196 t_reg ends 00000196 00000000 ; --------------------------------------------------------------------------- 00000000 00000000 t_thread struc ; (sizeof=0x66C) ;保存線程信息,同時(shí)有新舊兩份reg值,可以用來(lái)在OD的寄存器窗口為改變的值設(shè)置顏色等功能。 00000000 th_threadid dd ? ; // Thread identifier 00000004 th_dummy dd ? ; // Always 1 00000008 th_type dd ? ; // Service information, TY_xxx 0000000C th_thread dd ? ; // Thread handle 00000010 th_datablock dd ? ; // Per-thread data block 00000014 th_entry dd ? ; // Thread entry point 00000018 th_stacktop dd ? ; // Working variable of Listmemory() 0000001C th_stackbottom dd ? ; // Working variable of Listmemory() 00000020 th_context CONTEXT ? ; // Actual context of the thread 000002EC th_reg t_reg ? ; // Actual contents of registers 00000482 th_regvalid dd ? ; // Whether reg is valid 00000486 th_oldreg t_reg ? ; // Previous contents of registers 0000061C th_oldregvalid dd ? ; // Whether oldreg is valid 00000620 th_suspendcount dd ? ; // Suspension count (may be negative) 00000624 th_usertime dd ? ; // Time in user mode, 1/10th ms, or -1 00000628 th_systime dd ? ; // Time in system mode, 1/10th ms, or -1 0000062C th_reserved dd 16 dup(?) ; // Reserved for future compatibility 0000066C t_thread ends 下面的代碼是: 0042EBEF |. 8BF8 mov edi, eax 0042EBF1 |. 8B45 08 mov eax, dword ptr [ebp+8] 0042EBF4 |. 59 pop ecx 0042EBF5 |. 8938 mov dword ptr [eax], edi 0042EBF7 |. 8B15 14574D00 mov edx, dword ptr [4D5714] ; 4D5714中保存的是調(diào)試事件的代碼DebugEvent.dwDebugEventCode 0042EBFD |. 83FA 09 cmp edx, 9 ; Switch (cases 1..9) 0042EC00 |. 0F87 EE270000 ja 004313F4 0042EC06 |. FF2495 0DEC4200 jmp dword ptr [edx*4+42EC0D] ; 這里是switch跳轉(zhuǎn) 用來(lái)判斷是何種異常: 0042EC0D |. F4134300 dd OLLYDBG.004313F4 ; EXCEPTION_DEBUG_EVENT 0042EC11 |. |35EC4200 dd OLLYDBG.0042EC35 0042EC15 |. |FF0C4300 dd OLLYDBG.00430CFF 0042EC19 |. |D70D4300 dd OLLYDBG.00430DD7 0042EC1D |. |3F0F4300 dd OLLYDBG.00430F3F 0042EC21 |. |37104300 dd OLLYDBG.00431037 0042EC25 |. |2D114300 dd OLLYDBG.0043112D 0042EC29 |. |B7114300 dd OLLYDBG.004311B7 0042EC2D |. |76124300 dd OLLYDBG.00431276 0042EC31 |. |C7134300 dd OLLYDBG.004313C7 0042EC35 |> \8B0D 0C364E00 mov ecx, dword ptr [4E360C] ; Case 1 of switch 0042EBFD 0042EC3B |. 33C0 xor eax, eax 0042EC3D |. 894D EC mov dword ptr [ebp-14], ecx 0042EC40 |. A3 0C364E00 mov dword ptr [4E360C], eax 0042EC45 |. C745 A4 20574D00 mov dword ptr [ebp-5C], 004D5720 0042EC4C |. 85FF test edi, edi ;檢查主線程中是否有當(dāng)前寄存器的信息; 0042EC4E |. 75 0D jnz short 0042EC5D 0042EC50 |. 8B55 A4 mov edx, dword ptr [ebp-5C] 0042EC53 |. 33DB xor ebx, ebx 0042EC55 |. 8B4A 0C mov ecx, dword ptr [edx+C] 0042EC58 |. 894D D8 mov dword ptr [ebp-28], ecx 0042EC5B |. EB 22 jmp short 0042EC7F 0042EC5D |> 8B47 2C mov eax, dword ptr [edi+2C] ; ntdll.7C921231 0042EC60 |. 8945 D8 mov dword ptr [ebp-28], eax ;這一段是把異常地址賦給局部變量ebp-28 0042EC63 |. 837D EC 00 cmp dword ptr [ebp-14], 0 0042EC67 |. 8B5F 10 mov ebx, dword ptr [edi+10] 0042EC6A |. 74 13 je short 0042EC7F 以下代碼是判斷產(chǎn)生中斷的指令碼是0xCC還是0xCD03,若是0xCC,則指令碼要回溯1(因?yàn)镋ip指向下一條指令,回溯后才是正確的斷點(diǎn)地址),若是0xCD03,則指令碼要回溯2,其它的不回溯。 0042EC6C |. F647 31 01 test byte ptr [edi+31], 1 0042EC70 |. 74 0D je short 0042EC7F 0042EC72 |. 8167 30 FFFEFFFF and dword ptr [edi+30], FFFFFEFF 0042EC79 |. C707 01000000 mov dword ptr [edi], 1 0042EC7F |> 8B45 A4 mov eax, dword ptr [ebp-5C] 0042EC82 |. 8138 03000080 cmp dword ptr [eax], 80000003 ; Int3中斷 0042EC88 |. 74 07 je short 0042EC91 0042EC8A |. 33D2 xor edx, edx 0042EC8C |. 8955 DC mov dword ptr [ebp-24], edx 0042EC8F |. EB 79 jmp short 0042ED0A 0042EC91 |> 6A 02 push 2 ; /Arg4 = 00000002 0042EC93 |. 6A 01 push 1 ; |Arg3 = 00000001 0042EC95 |. 8B4D D8 mov ecx, dword ptr [ebp-28] ; | 0042EC98 |. 49 dec ecx ; |減一是讓指令碼回溯 0042EC99 |. 51 push ecx ; |Arg2 0042EC9A |. 8D45 BB lea eax, dword ptr [ebp-45] ; | 0042EC9D |. 50 push eax ; |Arg1 0042EC9E |. E8 69260300 call _Readmemory ; \_Readmemory 0042ECA3 |. 83C4 10 add esp, 10 0042ECA6 |. 83F8 01 cmp eax, 1 0042ECA9 |. 74 07 je short 0042ECB2 0042ECAB |. 33D2 xor edx, edx 0042ECAD |. 8955 DC mov dword ptr [ebp-24], edx 0042ECB0 |. EB 58 jmp short 0042ED0A 0042ECB2 |> 33C0 xor eax, eax 0042ECB4 |. 8A45 BB mov al, byte ptr [ebp-45] 0042ECB7 |. 3D CC000000 cmp eax, 0CC 0042ECBC |. 75 09 jnz short 0042ECC7 0042ECBE |. C745 DC 01000000 mov dword ptr [ebp-24], 1 ; 若Readmemory在斷點(diǎn)地址讀的指令碼是CC的話,ebp-24設(shè)為1---ebp-24保存的是要回溯的指令長(zhǎng)度 0042ECC5 |. EB 43 jmp short 0042ED0A 0042ECC7 |> 83F8 03 cmp eax, 3 0042ECCA |. 74 07 je short 0042ECD3 0042ECCC |. 33D2 xor edx, edx 0042ECCE |. 8955 DC mov dword ptr [ebp-24], edx 0042ECD1 |. EB 37 jmp short 0042ED0A 0042ECD3 |> 6A 02 push 2 ; /Arg4 = 00000002 0042ECD5 |. 6A 01 push 1 ; |Arg3 = 00000001 0042ECD7 |. 8B4D D8 mov ecx, dword ptr [ebp-28] ; | 0042ECDA |. 83E9 02 sub ecx, 2 ; |指令碼回溯2 0042ECDD |. 51 push ecx ; |Arg2 0042ECDE |. 8D45 BB lea eax, dword ptr [ebp-45] ; | 0042ECE1 |. 50 push eax ; |Arg1 0042ECE2 |. E8 25260300 call _Readmemory ; \_Readmemory 0042ECE7 |. 83C4 10 add esp, 10 0042ECEA |. 83F8 01 cmp eax, 1 0042ECED |. 75 0D jnz short 0042ECFC 0042ECEF |. 33D2 xor edx, edx 0042ECF1 |. 8A55 BB mov dl, byte ptr [ebp-45] 0042ECF4 |. 81FA CD000000 cmp edx, 0CD 0042ECFA |. 74 07 je short 0042ED03 0042ECFC |> 33C9 xor ecx, ecx 0042ECFE |. 894D DC mov dword ptr [ebp-24], ecx 0042ED01 |. EB 07 jmp short 0042ED0A 0042ED03 |> C745 DC 02000000 mov dword ptr [ebp-24], 2 0042ED0A |> 8B45 DC mov eax, dword ptr [ebp-24] 0042ED0D |. 2945 D8 sub dword ptr [ebp-28], eax ; 回溯指令碼,才是正確的斷點(diǎn)地址 0042ED10 |. 8B15 08574D00 mov edx, dword ptr [4D5708] 0042ED16 |. 3B55 D8 cmp edx, dword ptr [ebp-28] ; ntdll.DbgBreakPoint 0042ED19 |. 75 08 jnz short 0042ED23 0042ED1B |. 3B1D 0C574D00 cmp ebx, dword ptr [4D570C] 0042ED21 |. 74 16 je short 0042ED39 0042ED23 |> \33C9 xor ecx, ecx 0042ED25 |. 8B45 D8 mov eax, dword ptr [ebp-28] 0042ED28 |. 890D 10574D00 mov dword ptr [4D5710], ecx 0042ED2E |. A3 08574D00 mov dword ptr [4D5708], eax ; 把當(dāng)前斷點(diǎn)地址保存到全局變量4D5708中 0042ED33 |. 891D 0C574D00 mov dword ptr [4D570C], ebx 0042ED39 |> 8B55 A4 mov edx, dword ptr [ebp-5C] 0042ED3C |. 8B0A mov ecx, dword ptr [edx] 以上找到了回溯后的斷點(diǎn)地址。然后下面是做一些別的操作,這里暫不予考慮。 這時(shí)因?yàn)橛|發(fā)了Int3異常,被調(diào)試程序斷了下來(lái),且已經(jīng)回溯了地址,這時(shí)按下F9的話,OD就會(huì)重新跑起來(lái),這時(shí)OD對(duì)用戶設(shè)置的Int3斷點(diǎn)又做了兩件事: 1、恢復(fù)原有的指令,讓被調(diào)試程序正確執(zhí)行指令; 2、走完正確指令之后,再重新設(shè)置指令為0xCC; 在OD的函數(shù)Go中: 先通過(guò)Findthread獲得線程結(jié)構(gòu)體: 00434A45 |> \8B4D 08 mov ecx, dword ptr [ebp+8] 00434A48 |. 51 push ecx ; ecx 是Go函數(shù)傳入?yún)?shù),為被調(diào)試線程的ID 00434A49 |. E8 2A3F0400 call _Findthread ; 返回OD中t_thread線程結(jié)構(gòu)體 00434A4E |. 59 pop ecx 00434A4F |. 8945 DC mov dword ptr [ebp-24], eax ;把t_thread線程結(jié)構(gòu)體的地址賦給ebp-24 然后通過(guò)線程結(jié)構(gòu)體獲得當(dāng)前要執(zhí)行的指令的地址(這個(gè)地址在前面已經(jīng)用回溯法修正過(guò)了) 00434AB9 |. 8B99 18030000 mov ebx, dword ptr [ecx+t_thread.th_reg.r_EIP] … 00434B2A |. 53 push ebx ; ebx = t_thread.th_reg.r_EIP 00434B2B |. E8 7C49FEFF call 004194AC ; 把Eip傳給函數(shù)004194AC 在函數(shù)004194AC中,先獲得Int3斷點(diǎn)結(jié)構(gòu)體數(shù)組: 004194EC |> \56 push esi ;Eip 004194ED |. 68 E17E4D00 push 004D7EE1 ; |Arg1 = 004D7EE1 ASCII "Table of breakpoints" 004194F2 |. E8 19C00300 call _Findsorteddata ; 返回Int3斷點(diǎn)結(jié)構(gòu)體數(shù)組首地址 OD的Int3斷點(diǎn)結(jié)構(gòu)體中有斷點(diǎn)處的原始指令碼,用來(lái)恢復(fù)被調(diào)試程序原先的指令碼。把該地址作為參數(shù)傳給函數(shù)00418C4C 00419505 |. 50 push eax 00419506 |. 8915 20D64C00 mov dword ptr [4CD620], edx 0041950C |. E8 3BF7FFFF call 00418C4C 在函數(shù)00418C4C中層層調(diào)用,最終是調(diào)用WriteProcessMemory函數(shù)恢復(fù)指令碼的: 00461814 |> \6A 00 push 0 ; /pBytesWritten = NULL 00461816 |. A1 685A4D00 mov eax, dword ptr [4D5A68] ; | 0046181B |. 8B55 10 mov edx, dword ptr [ebp+10] ; | 0046181E |. 52 push edx ; |BytesToWrite 0046181F |. 8B4D 08 mov ecx, dword ptr [ebp+8] ; | 00461822 |. 51 push ecx ; |Buffer 00461823 |. 56 push esi ; |Address 00461824 |. 50 push eax ; |hProcess => 0000026C (window) 00461825 |. E8 F8D90400 call <jmp.&KERNEL32.WriteProcessMe>; \WriteProcessMemory 在運(yùn)行完該指令之后,OD又把該指令碼設(shè)為Int3斷點(diǎn),即0xCC 關(guān)鍵Call是函數(shù)41B5A4,在這個(gè)函數(shù)里,調(diào)用WriteMemory設(shè)置0xCC斷點(diǎn),而WriteMemory最終調(diào)用的還是上面所說(shuō)的WriteProcessMemory(這里就不再詳細(xì)描述了) 0041B6A4 |. C60424 CC |mov byte ptr [esp], 0CC ;直接設(shè)置0xCC斷點(diǎn) 0041B6A8 |. 6A 02 |push 2 ; /Arg4 = 00000002 0041B6AA |. 6A 01 |push 1 ; |Arg3 = 00000001 0041B6AC |. 55 |push ebp ; BreakPointAddress 0041B6AD |. 8D5424 0C |lea edx, dword ptr [esp+C] ; [esp+C] = 0xCC 0041B6B1 |. 52 |push edx ; [edx] = 0xCC 0041B6B2 |. E8 71600400 |call _Writememory ; \_Writememory 通過(guò)以上方法,OD實(shí)現(xiàn)了在運(yùn)行時(shí)動(dòng)態(tài)處理Int3斷點(diǎn)的功能。 武漢科銳學(xué)員: driverox 2008-5-19 |
|
來(lái)自: herowuking > 《Cracker》