標 題: 【原創(chuàng)】OllyDBG分析報告系列(4)---獲得當前cpu狀態(tài) 作 者: angelqkm 時 間: 2008-05-25,22:48:25 鏈 接: http://bbs./showthread.php?t=65476 這是分析報告的第四部分,請多多指教。 ![]() Ollydbg(以下均簡稱為OD)中獲得當前cpu狀態(tài)的主要原理是:windows操作系統(tǒng)是多線程的操作系統(tǒng),其線程運行是分時間片的,每個程序按照其優(yōu)先級輪流運行一段時間。當運行一個線程時,其他線程需要把運行環(huán)境保留到一個地方,當時間片分配到自己時,再講運行環(huán)境讀取出來并運行。根據(jù)windows運行原理,調試寄存器能夠讀取、修改保存起來的線程運行環(huán)境,這樣也就獲得了CPU的工作狀態(tài)了。其API為:GetThreadContext、SetThreadContext。 通過分析,OD會遍歷所有活動線程,得到其線程環(huán)境,并將得到的所有信息放到一個66Ch大小的結構體中,該結構體的詳細情況即該系 關于這部分的代碼分析,在IDA中已經詳細標出,就直接將IDA中的分析結果貼上。這里就總的說一下這個函數(shù)的功能以及參數(shù)(函數(shù)名為GetThreadInfo): a. 通過GetThreadContext的方法獲得線程的上下文環(huán)境,把該環(huán)境保存至OD線程信息結構中的reg字段中,若oldreg已經失效,則復制reg的值到oldreg中; b. 若被調試進程有多個線程,則循環(huán)取值,保存至OD線程信息結構數(shù)組中; c. 傳入?yún)?shù)為:DebugEvent.dwThreadId; d. 返回值為:成功時為保存在OD線程信息結構中的當前寄存器信息結構的指針(主線程),失敗返回0。 GetThreadInfo proc near ; CODE XREF: sub_42EBD0+1A p ; _Suspendprocess+45 p reg_big[6] = dword ptr -34h reg_seg_reg = dword ptr -30h s_base_ss = dword ptr -2Ch f_reg_st_i = dword ptr -28h SelectorEntry = _LDT_ENTRY ptr -24h ret = dword ptr -1Ch pThreadInfo = dword ptr -18h var_11 = byte ptr -11h src = dword ptr -10h segment_size = dword ptr -0Ch f_reg_index = dword ptr -8 i = dword ptr -4 ThreadId = dword ptr 8 保存現(xiàn)場,拉伸空間,檢查線程信息結構體是否存在,若不存在直接跳轉到結束處,若存在則跳過退出部分的代碼: push ebp mov ebp, esp add esp, 0FFFFFFCCh mov eax, pThreadInfo push ebx push esi push edi mov [ebp+pThreadInfo], eax cmp [ebp+pThreadInfo], 0 jnz short has_ThreadInfo xor eax, eax jmp _exit ; --------------------------------------------------------------------------- 下面開始即是一個大的循環(huán)體,這里初始值變量,然后跳轉到循環(huán)體的判斷處: has_ThreadInfo: ; CODE XREF: GetThreadInfo+15 j xor edx, edx mov [ebp+ret], edx xor ecx, ecx mov [ebp+i], ecx jmp loc_42E7C1 ; --------------------------------------------------------------------------- 這里開始為循環(huán)體的內部處理,即讀取當前cpu狀態(tài)到結構體中: getThreadInfo: ; CODE XREF: GetThreadInfo+37E j 先將線程信息結構體中幾個標識修改狀態(tài)的值置零,即標識還沒有修改: mov eax, [ebp+pThreadInfo] xor edx, edx mov [eax+t_Thread.reg.modified], edx ; 標識寄存器是否修改 mov ecx, [ebp+pThreadInfo] xor eax, eax mov [ecx+t_Thread.reg.modifiedbyuser], eax ; 標識被用戶修改 mov edx, [ebp+pThreadInfo] xor ecx, ecx mov [edx+t_Thread.reg.singlestep], ecx ; 標識單步 將CONTEXT結構體的ContextFlags設置為取得所有信息,然后調用GetThreadContext取當前線程信息,檢查是否取得線程信息,若取得則跳過錯誤處理,繼續(xù)設置: mov esi, [ebp+pThreadInfo] add esi, 20h mov dword ptr [esi], 1001Fh push esi ; lpContext mov eax, [ebp+pThreadInfo] mov edx, [eax+t_Thread.thread] ; HANDLE Thread handle push edx ; hThread call GetThreadContext test eax, eax jnz short loc_42E4C7 這里為沒有得到線程信息的處理,設置其線程信息有效值為0,即無效,然后跳轉到循環(huán)體判斷處遍歷下一個線程信息: mov ecx, [ebp+pThreadInfo] xor eax, eax mov [ecx+t_Thread.regvalid], eax ; int Whether reg is valid jmp j_next_Thread ; --------------------------------------------------------------------------- 檢查得到線程信息的線程ID是否與要得到線程的ID相同,若相同則設置返回值為其寄存器結構體的首地址,若不同則跳過對返回值的設置: loc_42E4C7: ; CODE XREF: GetThreadInfo+69 j mov eax, [ebp+pThreadInfo] mov ebx, [ebp+pThreadInfo] add ebx, 2ECh ; ebx : ThreadInfo.reg mov edx, [eax] ; edx : ThreadInfo.dwThreadId cmp edx, [ebp+ ThreadId] jnz short loc_42E4DD mov [ebp+ret], ebx 下面將得到的線程信息結構體中 寄存器結構體的信息一一賦值到OD為其準備的線程信息結構體處: loc_42E4DD: ; CODE XREF: GetThreadInfo+8C j mov ecx, [esi+CONTEXT._Eax] mov [ebx+t_reg.r_eax], ecx ; ulong register mov eax, [esi+CONTEXT._Ecx] mov [ebx+t_reg.r_ecx], eax ; ulong register mov edx, [esi+CONTEXT._Edx] mov [ebx+t_reg.r_edx], edx ; ulong register mov ecx, [esi+CONTEXT._Ebx] mov [ebx+t_reg.r_ebx], ecx ; ulong register mov eax, [esi+CONTEXT._Esp] mov [ebx+t_reg.r_esp], eax ; ulong register mov edx, [esi+CONTEXT._Ebp] mov [ebx+t_reg.r_ebp], edx ; ulong register mov ecx, [esi+CONTEXT._Esi] mov [ebx+t_reg.r_esi], ecx ; ulong register mov eax, [esi+CONTEXT._Edi] mov [ebx+t_reg.r_edi], eax ; ulong register mov edx, [esi+CONTEXT._Eip] mov [ebx+t_reg.r_eip], edx ; ulong Instruction pointer (EIP) 初始化浮點寄存器的棧頂、狀態(tài)等變量: lea edx, [ebx+t_reg.f_reg_st0] ; long double Float registers, f[top] - top of stack mov ecx, [esi+CONTEXT.EFlags] mov [ebx+t_reg.flags], ecx ; ulong Flags mov eax, [esi+CONTEXT.FloatSave.StatusWord] shr eax, 0Bh and eax, 7 xor edi, edi mov [ebx+t_reg.top], eax ; int Index of top-of-stack lea eax, [ebx+t_reg.tag[8]] ; uchar Float tags (0x3 - empty register) mov [ebp+s_base_ss], eax mov [ebp+f_reg_st_i], edx 這段是循環(huán)遍歷8個浮點寄存器,對其檢查并進行賦值: loc_42E554: ; CODE XREF: GetThreadInfo+158 j 8減去浮點寄存器的棧頂序號,再與80000007位與之后若為正則跳過對負數(shù)的處理,若為負數(shù)則取其補碼,由于浮點棧頂?shù)男蛱枮?,所以與80000007位與之后還是0,這里一個錯誤檢查: lea ecx, [edi+8] sub ecx, [ebx+t_reg.top] ; int Index of top-of-stack and ecx, 80000007h jns short loc_42E567 dec ecx or ecx, 0FFFFFFF8h inc ecx 這里是一個循環(huán)體,根據(jù)序號給浮點寄存器結構體賦值,每個浮點寄存器10個字節(jié): loc_42E567: ; CODE XREF: GetThreadInfo+114 j mov [ebp+f_reg_index], ecx mov eax, [ebp+f_reg_st_i] mov edx, [ebp+f_reg_index] lea edx, [edx+edx*4] mov ecx, dword ptr [esi+edx*2+CONTEXT.FloatSave.RegisterArea] mov [eax], ecx mov ecx, dword ptr [esi+edx*2+(CONTEXT.FloatSave.RegisterArea+4)] mov [eax+4], ecx mov cx, word ptr [esi+edx*2+(CONTEXT.FloatSave.RegisterArea+8)] mov [eax+8], cx 由于TagWord寄存器16位寬,只有一個作用,就是記錄每1個浮點寄存器的使用情況,8個浮點寄存器分為占用2位,所以每個寄存器有4個狀態(tài),分別為:00有效(Valid)、01零值(Zero)、10特殊的(Spical)、11空閑(Empty),這里就是按照序號標識其狀態(tài): mov ecx, edi add ecx, ecx mov eax, [esi+CONTEXT.FloatSave.TagWord] shr eax, cl and al, 3 mov edx, [ebp+s_base_ss] mov [edx], al 序號、寄存器基址、寄存器結構體指針自加,檢查是否遍歷完8個寄存器,若沒有遍歷完則繼續(xù): inc edi inc [ebp+s_base_ss] add [ebp+f_reg_st_i], 0Ah ; cmp edi, 8 jl short loc_42E554 最后設置控制字與狀態(tài)字寄存器: mov eax, [esi+CONTEXT.FloatSave.StatusWord] xor edi, edi mov [ebx+t_reg.fst], eax ; ulong FPU status word mov edx, [esi+CONTEXT.FloatSave.ControlWord] mov [ebx+t_reg.fcw], edx ; ulong FPU control word 下面開始為對段寄存器的賦值,標識都已注明: mov ecx, [esi+CONTEXT.SegEs] mov [ebx+t_reg.s_reg_es], ecx ; ulong Segment register mov eax, [esi+CONTEXT.SegCs] mov [ebx+t_reg.s_reg_cs], eax ; ulong Segment register mov edx, [esi+CONTEXT.SegSs] mov [ebx+t_reg.s_reg_ss], edx ; ulong Segment register mov ecx, [esi+CONTEXT.SegDs] mov [ebx+t_reg.s_reg_ds], ecx ; ulong Segment register mov eax, [esi+CONTEXT.SegFs] mov [ebx+t_reg.s_reg_fs], eax ; ulong Segment register lea eax, [ebx+t_reg.big[6]] ; uchar Default size (0-16, 1-32 bit) mov edx, [esi+CONTEXT.SegGs] mov [ebx+t_reg.s_reg_gs], edx ; ulong Segment register 初始化段寄存器的兩個變量(size、segment_reg): lea edx, [ebx+t_reg.s_reg_es] ; ulong Segment register mov [ebp+reg_big[6]], eax mov [ebp+reg_seg_reg], edx 這段是循環(huán)遍歷6個段寄存器,得到其大小,放入reg_big[6]結構體中,即得到該段的大?。?br> loc_42E614: ; CODE XREF: GetThreadInfo+278 j lea ecx, [ebp+SelectorEntry] push ecx ; lpSelectorEntry mov eax, [ebp+reg_seg_reg] mov edx, [eax] push edx ; dwSelector mov ecx, [ebp+pThreadInfo] mov eax, [ecx+0Ch] push eax ; hThread call GetThreadSelectorEntry ; 取得當前線程描述符表 test eax, eax jz short loc_42E697 movzx ecx, [ebp+SelectorEntry.BaseLow] mov dl, byte ptr [ebp+SelectorEntry.HighWord] mov al, byte ptr [ebp+SelectorEntry.HighWord+3] and edx, 0FFh and eax, 0FFh shl edx, 10h and ecx, 0FFFFh shl eax, 18h and edx, 0FF0000h add edx, ecx and eax, 0FF000000h add edx, eax mov [ebp+segment_size], edx movzx edx, [ebp+SelectorEntry.LimitLow] mov al, byte ptr [ebp+SelectorEntry.HighWord+2] and edx, 0FFFFh and eax, 0Fh shl eax, 10h and eax, 0F0000h add eax, edx test byte ptr [ebp+SelectorEntry.HighWord+2], 80h jz short loc_42E689 shl eax, 0Ch add eax, 0FFFh loc_42E689: ; CODE XREF: GetThreadInfo+233 j mov cl, byte ptr [ebp+SelectorEntry.HighWord+2] shr ecx, 6 and ecx, 1 mov [ebp+var_11], cl jmp short loc_42E6A2 ; --------------------------------------------------------------------------- loc_42E697: ; CODE XREF: GetThreadInfo+1E0 j xor edx, edx mov eax, edx mov [ebp+segment_size], edx mov [ebp+var_11], 1 loc_42E6A2: ; CODE XREF: GetThreadInfo+249 j mov ecx, [ebp+reg_seg_reg] mov edx, [ebp+segment_size] mov [ecx+18h], edx ; reg_seg_reg + 18h 剛好是其對應的reg_big[6]所在的位置 mov ecx, [ebp+reg_seg_reg] mov [ecx+30h], eax mov eax, [ebp+reg_big[6]] mov dl, [ebp+var_11] mov [eax], dl 檢查6個段寄存器是否遍歷完畢,若完畢則退出循環(huán): inc edi inc [ebp+reg_big[6]] add [ebp+reg_seg_reg], 4 cmp edi, 6 jl loc_42E614 下面是對調試寄存器的賦值: mov eax, [esi+CONTEXT.Dr0] mov [ebx+t_reg.drlin_dr0], eax ; ulong Debug register mov ecx, [esi+CONTEXT.Dr1] mov [ebx+t_reg.drlin_dr1], ecx ; ulong Debug register mov eax, [esi+CONTEXT.Dr2] mov [ebx+t_reg.drlin_dr2], eax ; ulong Debug register mov edx, [esi+CONTEXT.Dr3] mov [ebx+t_reg.drlin_dr3], edx ; ulong Debug register mov ecx, [esi+CONTEXT.Dr6] mov [ebx+t_reg.dr6], ecx ; ulong Debug register DR6 mov eax, [esi+CONTEXT.Dr7] mov [ebx+t_reg.dr7], eax ; ulong Debug register DR7 mov edx, [ebp+arg_0] mov [ebx+t_reg.threadid], edx ; ulong ID of thread that owns registers mov eax, VersionInformation.dwPlatformId 檢查子系統(tǒng)屬性,根據(jù)其進行相應的設置: cmp eax, 2 ; 檢查是否是windows圖形界面 jnz short loc_42E71A mov eax, 34h ; 若是則使 EAX = 34h jmp short loc_42E728 ; --------------------------------------------------------------------------- loc_42E71A: ; CODE XREF: GetThreadInfo+2C5 j cmp eax, 1 ; 檢查是否為本地屬性 jnz short loc_42E726 mov eax, 60h ; 若是則使EAX = 60h jmp short loc_42E728 ; --------------------------------------------------------------------------- loc_42E726: ; CODE XREF: GetThreadInfo+2D1 j xor eax, eax ; 若都不是則設置EAX = 0 loc_42E728: ; CODE XREF: GetThreadInfo+2CC j ; GetThreadInfo+2D8 j test eax, eax jz short loc_42E75C cmp dword_4D579C, 0 jz short loc_42E75C push 3 ; char push 4 ; n mov edx, [ebp+pThreadInfo] add eax, [edx+t_Thread.datablock] ; ulong Per-thread data block push eax ; arglist lea ecx, [ebp+src] push ecx ; src call _Readmemory add esp, 10h cmp eax, 4 jnz short loc_42E75C mov eax, [ebp+src] mov [ebx+0EEh], eax jmp short loc_42E766 ; --------------------------------------------------------------------------- loc_42E75C: ; CODE XREF: GetThreadInfo+2DE j ; GetThreadInfo+2E7 j ... mov dword ptr [ebx+0EEh], 0FFFFFFFFh 將剛得到的寄存器信息設置為有效,并檢查線程信息結構體中oldreg的屬性是否有效,若無效則將當前的寄存器值賦值進去: loc_42E766: ; CODE XREF: GetThreadInfo+30E j xor edx, edx xor ecx, ecx mov [ebx+0F2h], edx mov [ebx+0F6h], ecx mov eax, [ebp+pThreadInfo] mov [eax+t_Thread.regvalid], 1 ; int Whether reg is valid mov edx, [ebp+pThreadInfo] cmp dword ptr [edx+t_Thread.oldregvalid], 0 ; check ThreadInfo is read jnz short j_next_Thread mov ecx, [ebp+pThreadInfo] mov eax, [ebp+pThreadInfo] lea esi, [ecx+t_Thread.reg] ; struct Actual contents of registers lea edi, [eax+t_Thread.oldreg] ; struct Previous contents of registers mov ecx, 65h rep movsd ; Thread.reg copy to Thread.oldreg movsw mov eax, [ebp+pThreadInfo] mov dword ptr [eax+61Ch], 1 將線程計數(shù)自加1,將線程信息結構體指針指向下一個結構體的首地址(ThreadInfo的大小為66Ch): j_next_Thread: ; CODE XREF: GetThreadInfo+76 j ; GetThreadInfo+341 j inc [ebp+i] add [ebp+pThreadInfo], 66Ch ; pThreadInfo -> next ThreadInfo 這里為循環(huán)體的判斷處,檢查是否遍歷完所有線程,若沒有遍歷完,則繼續(xù)遍歷: loc_42E7C1: ; CODE XREF: GetThreadInfo+28 j mov edx, [ebp+i] cmp edx, Num_Thread jl getThreadInfo mov eax, [ebp+ret] 最后恢復現(xiàn)場: _exit: ; CODE XREF: GetThreadInfo+19 j pop edi pop esi pop ebx mov esp, ebp pop ebp retn GetThreadInfo endp 武漢科銳學員: angelqkm 2008-5-25 |
|
來自: herowuking > 《Cracker》