注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

古城风~~~

竹密无妨溪水过,天高不碍白云飞。这天下总有一份是属于我古城的天地!

 
 
 

日志

 
 

OllyDBG分析报告系列(1)---Int3断点(下)  

2008-06-10 12:46:43|  分类: 反编译(OllyDBG |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
2)Int3断点的处理
Int3断点处理的大致流程是:
1、  获取当前寄存器的信息,重点是Eip的值
2、  根据Int3断点的类型(0xCC或0xCD03)回溯指针地址
3、  触发Int3异常,被调试程序断下;
4、  若继续跑的话,则恢复原有的指令,让被调试程序正确执行指令;
5、  走完正确指令之后,再重新设置指令为Int3断点;

在OD中有一个处理所有异常的函数42EBD0,从该函数入手分析Int3断点的处理。
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  ;以上是开栈帧代码

0042EBE3  |.  8B35 1C574D00 mov     esi, dword ptr [4D571C] ;4D571C为全局变量,保存的是DebugEvent.dwThreadId
0042EBE9  |.  56            push    esi
0042EBEA  |.  E8 5DF8FFFF   call    0042E44C
函数42E44C的主要功能描述如下:

函数功能:通过GetThreadContext的方法获得线程的上下文环境,把该环境保存
          至OD线程信息结构中的reg字段中,若oldreg已经失效,则复制reg的
          值到oldreg中。
          若被调试进程有多个线程,则循环取值,保存至OD线程信息结构数组中。
传入参数:DebugEvent.dwThreadId 
返回值  :成功时为保存在OD线程信息结构中的当前寄存器信息结构的指针(主线程)
          失败返回0

这里说到了两个结构体,在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)  ;保存线程信息,同时有新旧两份reg值,可以用来在OD的寄存器窗口为改变的值设置颜色等功能。
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中保存的是调试事件的代码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跳转
用来判断是何种异常:
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  ;检查主线程中是否有当前寄存器的信息;
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

以下代码是判断产生中断的指令码是0xCC还是0xCD03,若是0xCC,则指令码要回溯1(因为Eip指向下一条指令,回溯后才是正确的断点地址),若是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在断点地址读的指令码是CC的话,ebp-24设为1---ebp-24保存的是要回溯的指令长度
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      ;  回溯指令码,才是正确的断点地址
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       ;  把当前断点地址保存到全局变量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]

以上找到了回溯后的断点地址。然后下面是做一些别的操作,这里暂不予考虑。
这时因为触发了Int3异常,被调试程序断了下来,且已经回溯了地址,这时按下F9的话,OD就会重新跑起来,这时OD对用户设置的Int3断点又做了两件事:
1、恢复原有的指令,让被调试程序正确执行指令;
2、走完正确指令之后,再重新设置指令为0xCC;
在OD的函数Go中:
先通过Findthread获得线程结构体:
00434A45  |> \8B4D 08       mov     ecx, dword ptr [ebp+8]
00434A48  |.  51            push    ecx            ; ecx 是Go函数传入参数,为被调试线程的ID
00434A49  |.  E8 2A3F0400   call    _Findthread      ; 返回OD中t_thread线程结构体
00434A4E  |.  59            pop     ecx
00434A4F  |.  8945 DC       mov     dword ptr [ebp-24], eax ;把t_thread线程结构体的地址赋给ebp-24
然后通过线程结构体获得当前要执行的指令的地址(这个地址在前面已经用回溯法修正过了)
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传给函数004194AC

在函数004194AC中,先获得Int3断点结构体数组:
004194EC  |> \56            push    esi             ;Eip
004194ED  |.  68 E17E4D00   push    004D7EE1       ; |Arg1 = 004D7EE1 ASCII "Table of breakpoints"
004194F2  |.  E8 19C00300   call    _Findsorteddata    ; 返回Int3断点结构体数组首地址
OD的Int3断点结构体中有断点处的原始指令码,用来恢复被调试程序原先的指令码。把该地址作为参数传给函数00418C4C
00419505  |.  50            push    eax
00419506  |.  8915 20D64C00 mov     dword ptr [4CD620], edx
0041950C  |.  E8 3BF7FFFF   call    00418C4C
在函数00418C4C中层层调用,最终是调用WriteProcessMemory函数恢复指令码的:
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

在运行完该指令之后,OD又把该指令码设为Int3断点,即0xCC
关键Call是函数41B5A4,在这个函数里,调用WriteMemory设置0xCC断点,而WriteMemory最终调用的还是上面所说的WriteProcessMemory(这里就不再详细描述了)
0041B6A4  |.  C60424 CC     |mov     byte ptr [esp], 0CC      ;直接设置0xCC断点
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

通过以上方法,OD实现了在运行时动态处理Int3断点的功能。
  评论这张
 
阅读(514)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017