这是分析报告的第六部分,请多多指教。 

Ollydbg(以下均简称为OD)中对各类断点、各类热键以及菜单消息的处理都是通过一个不停循环的消息线程处理的,当然对于调试程序异常的处理也包括在里面。

在OD中该循环位于WinMain函数的中间部分,先说一下其流程,然后具体分析代码:
1.  得到开机到现在的时间,根据时间间隔更新日志文件,流程如下:
  a)  检查是否创建了记录OD调试信息日志文件,若有创建继续检查距离上次更新是否超过30秒,若超过则将调试信息新增部分写入到文件中;
  b)  检查是否创建了运行跟踪结果的日志文件,若有创建继续检查距离上次更新是否超过30秒,若超过则将运行跟踪结果新增部分写入到文件中;
  c)  保存最后一次更新时间;
2.  检查是否需要刷新反汇编窗口、主窗口,若需要则检查刷新间隔是否超过0.5秒,超过则刷新,并记录该次刷新的时间,否则就不刷新;
3.  接受线程的消息队列,并将消息信息放入MSG结构体中,并检查消息是否接受成功,若失败跳过第4步对消息的处理;
4.  转换子窗体中的快捷键消息,若转换成功则跳过对其他消息的处理;
5.  ……一般消息的判断以及消息收发,这里跳过,没有分析;
6.  对EXE、DLL做相应的检查以及设置(添加临时断点、添加插件栏);
7.  使用WaitForDebugEvent函数接收异常,若没有接收到则发送NULL消息,跳转到第20步;
8.  先让插件处理异常,然后检查接收到的异常信息中进程Id是否为调试进程的Id,异常码是否为EXCEPTION_DEBUG_EVENT,若不是则调用ContinueDebugEvent 继续调试程序,其ContinueStatus 参数设置为DBG_CONTINUE,跳转到第1步继续循环;这一步比较关键,当异常为调试异常时并没有调用ContinueDebugEvent函数让函数继续执行,这样调试程序就被断下了;
9.  修改调试程序的状态标识为被调试状态,调用函数检查int3断点,若是运行状态则设置断点;
10.  检查异常、线程的信息结构体,设置标识,调用一个函数处理所有的异常;
11.  检查更新线程信息,检查是否开了运行跟踪文件,若开了则更新文件,将调试程序状态设置回去;
12.  检查异常信息以及平台情况,做相应的错误处理;
13.  下面开始为对调试功能的处理,一共有9种情况(0-No animation、1-Animate into、Animate over、Execute till RET、Skip RET instruction、Execute till user code、Run trace in、Run trace over、Gracefully stop animation),有一个全局变量标识其状态;
14.  对Execute till RET(执行到返回)进行处理,检查调试寄存器信息,检查第一个机器码是否为C2(retn…)C3(retn)CA(retf…)CB(retf)或者CF(iretd),若不是则跳过对其处理的部分;若是则开始处理:
  a)  调用_GO函数检查线程信息,设置断点,检查其合法性,根据检查结果设置提示信息;
  b)  调整优先级,对调试程序结构体信息、OD界面显示信息以及插件信息的更新
  c)  发送广播到子窗体,要求更新窗口内容,设置窗口获得焦点,最后返回到第1步
15.  对Execute till user code(执行到用户代码)进行处理,检查eip所在的模块是否为系统模块,若不是则调整其优先级,若是则跳过设置优先级;根据ebx判断是否调用函数设置所有断点;
16.  对Gracefully stop animation(停止自动跟踪)处理,检查线程信息,检查完毕后设置OD的界面,发送子窗体更新广播,更新插件;
17.  对于其他操作调用_GO函数进行处理,除了线程ID,其他参数都设0值;
18.  对No animation(无自动跟踪)进行处理,调用Set_all_Bpoint函数处理,然后跳转到第20步,函数中调用ContinueDebugEvent 函数继续调试程序,其ContinueStatus 参数设置为DBG_EXCEPTION_NOT_HANDLED;
19.  ……部分省略,是一些对OD操作的处理,跟上面雷同,一般都是调用_GO函数执行代码;检查更新标识;用_Broadcast函数发送更新广播;检查是否有自动跟踪文件,对其进行更新等等;
20.  两个对系统时间全局变量的判断以及设置,更新窗口,跳转到循环体开始处


得到开机到现在的时间,检查是否创建了记录OD调试信息的日志文件以及运行跟踪结果的日志文件,根据结果进行相应的跳转:
00439077   >  E8 566>call    <jmp.&KERNEL32.GetTickCount>
0043907C   . |8945 C>mov     dword ptr [ebp-34], eax
0043907F   . |833D E>cmp     dword ptr [4D55E8], 0  ; 检查调试信息日志文件指针是否存在
00439086   . |75 09  jnz     short 00439091      ; 存在则跳转到下面检查暂停时间
00439088   . |833D 4>cmp     dword ptr [4D9E40], 0    ; 检查运行跟踪的文件指针是否存在
0043908F   . |74 43  je      short 004390D4      ; 存在则跳转到下面检查暂停时间
这里为检查时间处,根据时间更新文件:
00439091   > |A1 283>mov     eax, dword ptr [4E3B28]
00439096   . |05 307>add     eax, 7530      ; 上次更新时间增加30秒
0043909B   . |3B45 C>cmp     eax, dword ptr [ebp-34]  ;与当前时间比较,检查是否间隔超过30秒
0043909E   . |73 34  jnb     short 004390D4  ; 超过则跳过文件的更新
004390A0   . |833D E>cmp     dword ptr [4D55E8], 0  ; 检查调试信息日志文件指针是否存在
004390A7   . |74 0D  je      short 004390B6  ; 不存在跳过更新被调试的文件
更新调试信息日志文件:
004390A9   . |8B15 E>mov     edx, dword ptr [4D55E8] 
004390AF   . |52     push    edx
004390B0   . |E8 B3B>call    004A4F68  ; _fflush 更新调试信息日志文件
004390B5   . |59     pop     ecx
检查运行跟踪文件指针是否存在,不存在则跳过更新运行跟踪文件:
004390B6   > |833D 4>cmp     dword ptr [4D9E40], 0
004390BD   . |74 0D  je      short 004390CC  ; 不存在则跳过更新运行跟踪文件
004390BF   . |8B0D 4>mov     ecx, dword ptr [4D9E40]
004390C5   . |51     push    ecx
004390C6   . |E8 9DB>call    004A4F68      ; _fflush 更新运行跟踪文件
004390CB   . |59     pop     ecx
将开机到当前的时间赋值给一个全局变量,保存文件最后一次更新时间:
004390CC   > |8B45 C>mov     eax, dword ptr [ebp-34]
004390CF   . |A3 283>mov     dword ptr [4E3B28], eax
检查是否需要刷新反汇编窗口,若不需要则跳过刷新:
004390D4   > |833D 3>cmp     dword ptr [4E3B34], 0  ; [4E3B34] 反汇编窗口刷新标识
004390DB   . |74 26  je      short 00439103
检查刷新窗口的间隔时间是否超过0.5秒,若超过则刷新所有窗口,并设置刷新时间以及刷新标识:
004390DD   . |8B55 C>mov     edx, dword ptr [ebp-34]
004390E0   . |2B15 3>sub     edx, dword ptr [4E3B38]    ; 得到两次刷新窗口的时间间隔
004390E6   . |81FA F>cmp     edx, 1F4      ; 比较时间间隔是否低于等于0.5秒
004390EC   . |76 15  jbe     short 00439103      ; 若低于0.5秒则跳过刷新
004390EE   . |E8 D95>call    _Redrawdisassembler    ; 刷新反汇编窗口
004390F3   . |8B4D C>mov     ecx, dword ptr [ebp-34]
004390F6   . |33C0   xor     eax, eax
004390F8   . |890D 3>mov     dword ptr [4E3B38], ecx    ; 记录刷新最后时间
004390FE   . |A3 343>mov     dword ptr [4E3B34], eax    ; 将刷新标识置零
检查主窗口更新标识,若不需要更新则将当前时间设置到记录主窗口更新时间的全局变量,然后跳过对主窗口的刷新:
00439103   > |833D C>cmp     dword ptr [4D57C0], 0  ; 检查主窗口更新标识
0043910A   . |74 09  je      short 00439115
0043910C   . |833D 3>cmp     dword ptr [4E3B30], 0  ; 检查nNumber是否为0
00439113   . |75 0B  jnz     short 00439120
00439115   > |8B55 C>mov     edx, dword ptr [ebp-34]  ; 记录更新时间
00439118   . |8915 2>mov     dword ptr [4E3B2C], edx
0043911E   . |EB 55  jmp     short 00439175    ; 跳过对主窗口的更新
检查距离上次刷新的时间间隔是否超过0.5秒,小于则跳过刷新:
00439120   > |8B0D 2>mov     ecx, dword ptr [4E3B2C]
00439126   . |81C1 E>add     ecx, 3E8
0043912C   . |3B4D C>cmp     ecx, dword ptr [ebp-34]
0043912F   . |73 44  jnb     short 00439175
检查nNumber是否超过50,小于则跳过更新:
00439131   . |833D 3>cmp     dword ptr [4E3B30], 32
00439138   . |7C 2B  jl      short 00439165
间隔时间*1000/edx (edx > 50),最后用计算的值更新:
0043913A   . |8B45 C>mov     eax, dword ptr [ebp-34]
0043913D   . |8B15 3>mov     edx, dword ptr [4E3B30]
00439143   . |2B05 2>sub     eax, dword ptr [4E3B2C]
00439149   . |50     push    eax                           ; /Divisor
0043914A   . |68 E80>push    3E8                           ; |Multiplier = 3E8 (1000.)
0043914F   . |52     push    edx                           ; |Multiplicand => 0
00439150   . |E8 FB5>call    <jmp.&KERNEL32.MulDiv>        ; \MulDiv
00439155   . |50     push    eax                           ; /Arg2
00439156   . |8D8E 6>lea     ecx, dword ptr [esi+3162]          ; |
0043915C   . |51     push    ecx                           ; |Arg1
0043915D   . |E8 CA8>call    _Flash                        ; \_Flash
00439162   . |83C4 0>add     esp, 8
00439165   > |33C0   xor     eax, eax
00439167   . |8B55 C>mov     edx, dword ptr [ebp-34]
0043916A   . |A3 303>mov     dword ptr [4E3B30], eax  ; 将除数置零
0043916F   . |8915 2>mov     dword ptr [4E3B2C], edx    ; 将系统时间记录
接受主线程的消息队列,并将消息信息放入MSG结构体中,并检查消息是否接受成功,若失败跳过下面对消息的处理:
00439175   > |6A 01  push    1                             ; /RemoveMsg = PM_REMOVE
00439177   . |6A 00  push    0                             ; |MsgFilterMax = WM_NULL
00439179   . |6A 00  push    0                             ; |MsgFilterMin = WM_NULL
0043917B   . |6A 00  push    0                             ; |hWnd = NULL
0043917D   . |8D8D 3>lea     ecx, dword ptr [ebp-9C8]          ; |
00439183   . |51     push    ecx                           ; |pMsg
00439184   . |E8 A56>call    <jmp.&USER32.PeekMessageA>      ; \PeekMessageA
00439189   . |85C0   test    eax, eax
0043918B   . |0F84 C>je      00439454
转换子窗口消息中的快捷键消息:
00439191   . |8D85 3>lea     eax, dword ptr [ebp-9C8]
00439197   . |50     push    eax                           ; /pMsg
00439198   . |8B15 8>mov     edx, dword ptr [4D3B80]       ; |
0043919E   . |52     push    edx    ; |hClient => 00020762 (class='MDIClient',parent=000607B6)
0043919F   . |E8 3E6>call    <jmp.&USER32.TranslateMDISysA>; \TranslateMDISysAccel
004391A4   . |85C0   test    eax, eax
004391A6   . |0F85 9>jnz     00439442
若子窗口有操作消息,则跳过对主窗体的消息的判断,对子窗口消息进行处理;下面是对一般消息的判断,处理还是在下面,这里跳过:
……
……
这里开始为对所有消息的处理:
00439454   > |833D 8>cmp     dword ptr [4D5780], 0
0043945B   . |0F84 9>je      004395F9
00439461   . |833D 1>cmp     dword ptr [4E3610], 0         ;  (initial cpu selection)
00439468   . |0F84 8>je      004395F9
0043946E   . |E8 F95>call    0045F36C        ; 得到加载的dll模块信息
00439473   . |E8 9C7>call    _Listmemory      ; 检查内存链表
将模块信息给edi寄存器,下面对其进行检查,DLL以及EXE程序分开检查:
00439478   . |8B3D 1>mov     edi, dword ptr [4D7218]    ; edi : pModule
检查是否为DLL,若是则初始化参数,并跳转到条件判断处,用一个循环体进行判断:
0043947E   . |833D A>cmp     dword ptr [4D6EA0], 0 
00439485   . |74 7E  je      short 00439505
00439487   . |85FF   test    edi, edi
00439489   . |74 7A  je      short 00439505
0043948B   . |33DB   xor     ebx, ebx
0043948D   . |EB 6E  jmp     short 004394FD
若是DLL则用一个循环体检查调试的模块是否是加载的模块,若是则在入口设置int3临时断点:
0043948F   > |8D049B lea     eax, dword ptr [ebx+ebx*4]
00439492   . |8D0480 lea     eax, dword ptr [eax+eax*4]
00439495   . |8D0480 lea     eax, dword ptr [eax+eax*4]
00439498   . |8D04C0 lea     eax, dword ptr [eax+eax*8]
0043949B   . |F64407>test    byte ptr [edi+eax+8], 10    ; 检查模块是否需要记录
004394A0   . |75 5A  jnz     short 004394FC        ; 不需要则遍历下个模块
004394A2   . |8D149B lea     edx, dword ptr [ebx+ebx*4]
004394A5   . |8D1492 lea     edx, dword ptr [edx+edx*4]
004394A8   . |8D1492 lea     edx, dword ptr [edx+edx*4]
004394AB   . |8D14D2 lea     edx, dword ptr [edx+edx*8]
004394AE   . |03D7   add     edx, edi
004394B0   . |83C2 5>add     edx, 50        ; 检查模块路径名与加载的DLL是否相同
004394B3   . |52     push    edx                           ; /Arg2
004394B4   . |68 805>push    004D5B80                      ; |
004394B9   . |E8 FEA>call    004A38BC                      ; \_stricmp
004394BE   . |83C4 0>add     esp, 8
004394C1   . |85C0   test    eax, eax
004394C3   . |75 37  jnz     short 004394FC    ; 不同则遍历下个模块
004394C5   . |8D0C9B lea     ecx, dword ptr [ebx+ebx*4]
004394C8   . |8D0C89 lea     ecx, dword ptr [ecx+ecx*4]
004394CB   . |8D0C89 lea     ecx, dword ptr [ecx+ecx*4]
004394CE   . |8D0CC9 lea     ecx, dword ptr [ecx+ecx*8]
004394D1   . |837C0F>cmp     dword ptr [edi+ecx+28], 0  ; 检查模块入口点是否存在
004394D6   . |74 2D  je      short 00439505      ; 不存在则跳出循环
004394D8   . |8D049B lea     eax, dword ptr [ebx+ebx*4]
004394DB   . |6A 00  push    0                             ; /Arg4 = 00000000
004394DD   . |6A 00  push    0                             ; |Arg3 = 00000000
004394DF   . |68 000>push    800                      ; |Arg2 = 00000800  临时断点
004394E4   . |8D0480 lea     eax, dword ptr [eax+eax*4]    ; |
004394E7   . |8D0480 lea     eax, dword ptr [eax+eax*4]    ; |
004394EA   . |8D04C0 lea     eax, dword ptr [eax+eax*8]    ; |
004394ED   . |8B5407>mov     edx, dword ptr [edi+eax+28]   ; |
004394F1   . |52     push    edx                           ; |Arg1
004394F2   . |E8 690>call    _Setbreakpointext             ; \_Setbreakpointext
004394F7   . |83C4 1>add     esp, 10
004394FA   . |EB 09  jmp     short 00439505
004394FC   > |43     inc     ebx
这里为循环体判断处:
004394FD   > |3B1D 0>cmp     ebx, dword ptr [4D7200]
00439503   .^|7C 8A  jl      short 0043948F
下面为对EXE程序的检查,跳转到条件判断处,用一个循环体进行判断,设置工具栏:
00439505   > |833D 5>cmp     dword ptr [4D7350], 0
0043950C   . |0F84 B>je      004395CB
00439512   . |85FF   test    edi, edi    ; 检查模块信息是否存在
00439514   . |0F84 B>je      004395CB
0043951A   . |33DB   xor     ebx, ebx
0043951C   . |EB 14  jmp     short 00439532
0043951E   > |8D049B lea     eax, dword ptr [ebx+ebx*4]
00439521   . |8D0480 lea     eax, dword ptr [eax+eax*4]
00439524   . |8D0480 lea     eax, dword ptr [eax+eax*4]
00439527   . |8D04C0 lea     eax, dword ptr [eax+eax*8]
0043952A   . |F64407>test    byte ptr [edi+eax+8], 10    ; 检查模块是否需要记录
0043952F   . |74 09  je      short 0043953A
00439531   . |43     inc     ebx
00439532   > |3B1D 0>cmp     ebx, dword ptr [4D7200]
00439538   .^|7C E4  jl      short 0043951E
0043953A   > |3B1D 0>cmp     ebx, dword ptr [4D7200]
00439540   . |7D 6B  jge     short 004395AD
00439542   . |6A 00  push    0                             ; /Arg1 = 00000000
00439544   . |E8 47A>call    _Suspendprocess               ; \_Suspendprocess 暂停线程
00439549   . |59     pop     ecx
0043954A   . |833D 2>cmp     dword ptr [4DE924], 0
00439551   . |74 05  je      short 00439558
00439553   . |E8 58E>call    00497BB0
00439558   > |833D 1>cmp     dword ptr [4E2F10], 0
0043955F   . |74 05  je      short 00439566
00439561   . |E8 223>call    0049CD88
00439566   > |8D96 8>lea     edx, dword ptr [esi+318E]
0043956C   . |52     push    edx                           ; /Arg2
0043956D   . |6A 00  push    0                             ; |Arg1 = 00000000
0043956F   . |E8 BC8>call    _Message                      ; \_Message
00439574   . |83C4 0>add     esp, 8
00439577   . |33DB   xor     ebx, ebx
00439579   . |EB 25  jmp     short 004395A0
0043957B   > |8D049B lea     eax, dword ptr [ebx+ebx*4]
0043957E   . |8D0480 lea     eax, dword ptr [eax+eax*4]
00439581   . |8D0480 lea     eax, dword ptr [eax+eax*4]
00439584   . |8D04C0 lea     eax, dword ptr [eax+eax*8]
00439587   . |F64407>test    byte ptr [edi+eax+8], 10
0043958C   . |74 11  je      short 0043959F
0043958E   . |8D149B lea     edx, dword ptr [ebx+ebx*4]
00439591   . |8D1492 lea     edx, dword ptr [edx+edx*4]
00439594   . |8D1492 lea     edx, dword ptr [edx+edx*4]
00439597   . |8D14D2 lea     edx, dword ptr [edx+edx*8]
0043959A   . |836417>and     dword ptr [edi+edx+8], FFFFFF>
0043959F   > |43     inc     ebx
004395A0   > |3B1D 0>cmp     ebx, dword ptr [4D7200]
004395A6   .^|7C D3  jl      short 0043957B
004395A8   . |E8 9F6>call    0046044C        ; 设置工具栏
004395AD   > |33DB   xor     ebx, ebx
004395AF   . |EB 12  jmp     short 004395C3
004395B1   > |8D049B lea     eax, dword ptr [ebx+ebx*4]
004395B4   . |8D0480 lea     eax, dword ptr [eax+eax*4]
004395B7   . |8D0480 lea     eax, dword ptr [eax+eax*4]
004395BA   . |8D04C0 lea     eax, dword ptr [eax+eax*8]
004395BD   . |834C07>or      dword ptr [edi+eax+8], 10    ; 检查模块是否需要记录
004395C2   . |43     inc     ebx
这里为循环体判断处:
004395C3   > |3B1D 0>cmp     ebx, dword ptr [4D7200]
004395C9   .^|7C E6  jl      short 004395B1
设置edi为线程信息,检查线程信息是否存在,循环遍历活动线程,将其激活:
004395CB   > |8B3D B>mov     edi, dword ptr [4D7DB0]  ; pThreadInfo
004395D1   . |85FF   test    edi, edi
004395D3   . |74 1C  je      short 004395F1
004395D5   . |33DB   xor     ebx, ebx
004395D7   . |EB 10  jmp     short 004395E9
004395D9   > |8B47 0>mov     eax, dword ptr [edi+C]
004395DC   . |50     push    eax                           ; /hThread
004395DD   . |E8 925>call    <jmp.&KERNEL32.ResumeThread>  ; \ResumeThread
004395E2   . |43     inc     ebx
004395E3   . |81C7 6>add     edi, 66C
循环体判断处,检查线程是否遍历完:
004395E9   > |3B1D 9>cmp     ebx, dword ptr [4D7D98]
004395EF   .^|7C E8  jl      short 004395D9
根据线程信息设置标识:
004395F1   > |33D2   xor     edx, edx
004395F3   . |8915 1>mov     dword ptr [4E3610], edx
检查被调试程序是否运行状态,若不是则遍历所有插件,用其处理异常,然后跳过运行时的处理:
004395F9   > |833D 5>cmp     dword ptr [4D5A5C], 3 
00439600   . |74 14  je      short 00439616
00439602   . |6A 00  push    0                             ; /Arg1 = 00000000
00439604   . |E8 43D>call    00496B4C                      ; \Plugin_SetDebugEvent
00439609   . |59     pop     ecx
0043960A   . |6A 01  push    1                             ; /Timeout = 1. ms
0043960C   . |E8 AB5>call    <jmp.&KERNEL32.Sleep>         ; \Sleep
00439611   . |E9 D80>jmp     0043A2EE
使用WaitForDebugEvent接收异常,并检查是否接收到异常,若接收到异常则跳过下面的处理:
00439616   > |6A 00  push    0                             ; /Timeout = 0. ms
00439618   . |68 145>push    004D5714                 ; |pDebugEvent = Ollydbg.004D5714
0043961D   . |E8 E85>call    <jmp.&KERNEL32.WaitForDebugEv>; \WaitForDebugEvent
00439622   . |85C0   test    eax, eax
00439624   . |75 44  jnz     short 0043966A
检查标识以及系统时间,根据判断结构处理,发送WM_NULL消息,设置标识为0;或者跳过这个处理让插件处理异常:
00439626   . |833D 5>cmp     dword ptr [4E3B54], 0
0043962D   . |74 27  je      short 00439656
0043962F   . |8B0D 5>mov     ecx, dword ptr [4E3B58]
00439635   . |83C1 6>add     ecx, 64
00439638   . |3B4D C>cmp     ecx, dword ptr [ebp-34]
0043963B   . |73 19  jnb     short 00439656
0043963D   . |6A 00  push    0                             ; /lParam = 0
0043963F   . |6A 00  push    0                             ; |wParam = 0
00439641   . |6A 00  push    0                             ; |Message = WM_NULL
00439643   . |A1 5C3>mov     eax, dword ptr [4E3B5C]       ; |
00439648   . |50     push    eax                           ; |ThreadId => 340
00439649   . |E8 F25>call    <jmp.&USER32.PostThreadMessag>; \PostThreadMessageA
0043964E   . |33D2   xor     edx, edx
00439650   . |8915 5>mov     dword ptr [4E3B54], edx
让插件处理0号异常然后跳过处理下面的处理:
00439656   > |6A 00  push    0                             ; /Arg1 = 00000000
00439658   . |E8 EFD>call    00496B4C                      ; \ Plugin_SetDebugEvent
0043965D   . |59     pop     ecx
0043965E   . |6A 00  push    0                             ; /Timeout = 0. ms
00439660   . |E8 575>call    <jmp.&KERNEL32.Sleep>         ; \Sleep
00439665   . |E9 840>jmp     0043A2EE
将异常事件压栈,让插件处理异常:
0043966A   > |68 145>push    004D5714                      ; /Arg1
0043966F   . |E8 D8D>call    00496B4C                      ; \Plugin_SetDebugEvent
00439674   . |59     pop     ecx
检查是否是被调试程序所报的异常,若不是则设置相关的异常信息,检查异常事件是否为调试异常:
00439675   . |8B0D 1>mov     ecx, dword ptr [4D5718]  ; DebugEvent.dwProcessId
0043967B   . |3B0D 7>cmp     ecx, dword ptr [4D5A70]
00439681   . |74 56  je      short 004396D9
00439683   . |A1 185>mov     eax, dword ptr [4D5718]
00439688   . |50     push    eax                           ; /Arg5 => 00000BA8
00439689   . |8B15 1>mov     edx, dword ptr [4D5714]       ; |
0043968F   . |52     push    edx                           ; |Arg4 => 00000001
00439690   . |8D8E 8>lea     ecx, dword ptr [esi+D86]      ; |
00439696   . |51     push    ecx                           ; |Arg3
00439697   . |6A 00  push    0                             ; |Arg2 = 00000000
00439699   . |6A 00  push    0                             ; |Arg1 = 00000000
0043969B   . |E8 6C0>call    _Addtolist                    ; \_Addtolist
004396A0   . |83C4 1>add     esp, 14
004396A3   . |833D 1>cmp     dword ptr [4D5714], 1  ; EXCEPTION_DEBUG_EVENT
004396AA   . |75 10  jnz     short 004396BC    ; 不是则跳转
004396AC   . |833D 7>cmp     dword ptr [4D5770], 0  ; STATUS_WAIT_0
004396B3   . |74 07  je      short 004396BC    ; 若是则跳转
设置ContinueStatus为DBG_EXCEPTION_NOT_HANDLED(不忽略异常):
004396B5   . |BB 010>mov     ebx, 80010001
004396BA   . |EB 05  jmp     short 004396C1  ;
设置ContinueStatus为DBG_CONTINUE(忽略异常继续执行):
004396BC   > |BB 020>mov     ebx, 10002
调用ContinueDebugEvent让调试程序继续执行,跳转到最上面继续接收消息:
004396C1   > |53     push    ebx                           ; /ContinueStatus
004396C2   . |A1 1C5>mov     eax, dword ptr [4D571C]       ; |
004396C7   . |50     push    eax                           ; |ThreadId => 340
004396C8   . |8B15 1>mov     edx, dword ptr [4D5718]       ; |
004396CE   . |52     push    edx                           ; |ProcessId => BA8
004396CF   . |E8 EA5>call    <jmp.&KERNEL32.ContinueDebugE>; \ContinueDebugEvent
004396D4   .^ E9 9EF>jmp     00439077
将调试程序的状态赋值给一个局部变量,然后将其设置为STAT_EVENT,即进程暂停、被调试;并根据int3断点表设置断点:
004396D9   > |8B0D 5>mov     ecx, dword ptr [4D5A5C]
004396DF   . |C705 5>mov     dword ptr [4D5A5C], 2    ; STAT_EVENT
004396E9   . |33C0   xor     eax, eax
004396EB   . |C705 F>mov     dword ptr [4D56FC], 1
004396F5   . |A3 745>mov     dword ptr [4D5774], eax
004396FA   . |894D B>mov     dword ptr [ebp-50], ecx
004396FD   . |8B15 3>mov     edx, dword ptr [4D8134]
00439703   . |8915 0>mov     dword ptr [4D5700], edx
00439709   . |E8 961>call    0041B5A4
检查模块数量,若为0则跳过下面的取得模块信息部分:
0043970E   . |833D 4>cmp     dword ptr [4D7348], 0
00439715   . |74 11  je      short 00439728
00439717   . |E8 505>call    0045F36C    ; 得到模块信息
0043971C   . |E8 F37>call    _Listmemory  ; 检查内存链表
00439721   . |E8 463>call    0042D56C    ; 清空临时信息表
00439726   . |EB 3C  jmp     short 00439764
检查线程、异常相关信息,设置标识:
00439728   > |833D 2>cmp     dword ptr [4D812C], 0
0043972F   . |74 29  je      short 0043975A
00439731   . |833D 9>cmp     dword ptr [4D7D98], 1  ; 线程数量是否超过1
00439738   . |7F 20  jg      short 0043975A
0043973A   . |833D 3>cmp     dword ptr [4D8130], 0  ; 异常码ExceptionCode是否存在
00439741   . |74 17  je      short 0043975A
00439743   . |833D 1>cmp     dword ptr [4D5714], 1 ;异常事件是否为EXCEPTION_DEBUG_EVENT
0043974A   . |75 0E  jnz     short 0043975A
0043974C   . |8B0D 2>mov     ecx, dword ptr [4D572C]
00439752   . |3B0D 3>cmp     ecx, dword ptr [4D8130]  ; ecx :ExceptionCode
00439758   . |74 0A  je      short 00439764
0043975A   > |C705 7>mov     dword ptr [4D7C7C], 1
初始化几个变量,调用函数处理异常,即是在内存断点的处理中提到的那个函数:
00439764   > |33C0   xor     eax, eax
00439766   . |33D2   xor     edx, edx
00439768   . |A3 308>mov     dword ptr [4D8130], eax  ; ExceptionAddress
0043976D   . |8D4D A>lea     ecx, dword ptr [ebp-54]    ; pReg
00439770   . |C605 2>mov     byte ptr [4E3A20], 0    ; rtrace_Buf
00439777   . |8915 5>mov     dword ptr [4E3B54], edx
0043977D   . |51     push    ecx                           ; /Arg1
0043977E   . |E8 4D5>call    0042EBD0                      ; \CheckDebugEvent
00439783   . |59     pop     ecx
检查更新线程信息,若开了运行跟踪,则还要将运行跟踪的信息写入文件:
00439784   . |6A 00  push    0                             ; /Arg2 = 00000000
00439786   . |8BD8   mov     ebx, eax                      ; |
00439788   . |8B45 A>mov     eax, dword ptr [ebp-54]       ; |
0043978B   . |50     push    eax                           ; |Arg1
0043978C   . |E8 871>call    0048AF18                      ; \check_ThreadInfo
00439791   . |83C4 0>add     esp, 8
00439794   . |803D 2>cmp     byte ptr [4E3A20], 0
0043979B   . |74 0B  je      short 004397A8
0043979D   . |68 203>push    004E3A20
004397A2   . |E8 A51>call    0048AE4C        set_file_rtrace
004397A7   . |59     pop     ecx
将调试程序状态重新设置回去:
004397A8   > |33D2   xor     edx, edx
004397AA   . |8B4D B>mov     ecx, dword ptr [ebp-50]
004397AD   . |8915 5>mov     dword ptr [4D8D5C], edx
004397B3   . |890D 5>mov     dword ptr [4D5A5C], ecx
检查异常信息,并做相应的跳转:
004397B9   . |833D 1>cmp  dword ptr [4D5714], 1  ; 异常事件是否为EXCEPTION_DEBUG_EVENT
004397C0   . |75 42  jnz     short 00439804
004397C2   . |833D 7>cmp     dword ptr [4D5770], 0 ; dwFirstChance == 0 ??
004397C9   . |75 39  jnz     short 00439804
004397CB   . |833D D>cmp     dword ptr [4D36D8], 2  ; 程序的执行平台是否为windows
004397D2   . |74 0C  je      short 004397E0
004397D4   . |813D 2>cmp     dword ptr [4D572C], 80000000  ; 异常地址是否大于80000000h
004397DE   . |73 24  jnb     short 00439804
这里为程序平台为windows的处理,弹出窗口,调整优先级:
004397E0   > |833D 8>cmp     dword ptr [4D578C], 0
004397E7   . |75 11  jnz     short 004397FA
004397E9   . |8D86 A>lea     eax, dword ptr [esi+31A5]
004397EF   . |50     push    eax                           ; /Arg2
004397F0   . |6A 00  push    0                             ; |Arg1 = 00000000
004397F2   . |E8 397>call    _Message                      ; \_Message
004397F7   . |83C4 0>add     esp, 8
004397FA   > |6A 00  push    0                             ; /Arg1 = 00000000
004397FC   . |E8 D78>call    _Animate                      ; \_Animate
00439801   . |59     pop     ecx
00439802   . |33DB   xor     ebx, ebx
检查调试操作是否为Execute till RET(执行到返回),若不是则跳过该处理部分:
00439804   > |833D C>cmp     dword ptr [4D57CC], 3    ; [4D57CC] == 3 Execute till RET
0043980B   . |0F85 1>jnz     00439928
检查寄存器信息是否为空,若为空也跳过该处理部分:
00439811   . |837D A>cmp     dword ptr [ebp-54], 0    ; [ebp-54] : pReg
00439815   . |0F84 0>je      00439928
将寄存器的EIP所在的机器码读取出来:
0043981B   . |8D85 9>lea     eax, dword ptr [ebp-468]
00439821   . |50     push    eax                           ; /Arg2
00439822   . |8B55 A>mov     edx, dword ptr [ebp-54]          ; |
00439825   . |8B4A 2>mov     ecx, dword ptr [edx+2C]          ; |
00439828   . |51     push    ecx                           ; |Arg1
00439829   . |E8 567>call    _Readcommand                  ; \_Readcommand
0043982E   . |83C4 0>add     esp, 8
检查第一个机器码是否为C2(retn…)C3(retn)CA(retf…)CB(retf)或者CF(iretd),若不是则跳过对其处理的部分:
00439831   . |85C0   test    eax, eax
00439833   . |0F86 E>jbe     00439928
00439839   . |33C0   xor     eax, eax
0043983B   . |8A85 9>mov     al, byte ptr [ebp-468]
00439841   . |25 F60>and     eax, 0F6
00439846   . |3D C20>cmp     eax, 0C2
0043984B   . |74 14  je      short 00439861
0043984D   . |33D2   xor     edx, edx
0043984F   . |8A95 9>mov     dl, byte ptr [ebp-468]
00439855   . |81FA C>cmp     edx, 0CF
0043985B   . |0F85 C>jnz     00439928
检查线程信息:
00439861   > |833D C>cmp     dword ptr [4D57C8], 0
00439868   . |0F84 A>je      0043991A
0043986E   . |6A 00  push    0                             ; /Arg2 = 00000000
00439870   . |8B4D A>mov     ecx, dword ptr [ebp-54]       ; |
00439873   . |51     push    ecx                           ; |Arg1
00439874   . |E8 9F1>call    0048AF18                      ; \check_ThreadInfo
00439879   . |83C4 0>add     esp, 8
0043987C   . |FF05 3>inc     dword ptr [4E3B30]
调用OD导出函数_GO使调试程序继续执行,该函数里面一样对断点进行了设置以及处理,最后检查返回值是否为0,即标识执行成功,若执行失败则跳过:
00439882   . |6A 01  push    1                             ; /Arg5 = 00000001
00439884   . |6A 00  push    0                             ; |Arg4 = 00000000
00439886   . |6A 02  push    2                             ; |Arg3 = 00000002
00439888   . |6A 00  push    0                             ; |Arg2 = 00000000
0043988A   . |6A 00  push    0                             ; |Arg1 = 00000000
0043988C   . |E8 83B>call    _Go                           ; \_Go
00439891   . |83C4 1>add     esp, 14
00439894   . |85C0   test    eax, eax
00439896   . |74 75  je      short 0043990D
调整优先级,对调试程序结构体信息、OD界面显示信息以及插件信息的更新:
00439898   . |6A 00  push    0                             ; /Arg1 = 00000000
0043989A   . |E8 398>call    _Animate                      ; \_Animate
0043989F   . |59     pop     ecx
004398A0   . |E8 0B4>call    0042E2B0          ; update_ThreadRegInfo
004398A5   . |6A 01  push    1                             ; /Arg1 = 00000001
004398A7   . |E8 CC8>call    00431978                      ; \ update_subwin
004398AC   . |59     pop     ecx
004398AD   . |68 145>push    004D5714                      ; /Arg4 = 004D5714
004398B2   . |8B45 A>mov     eax, dword ptr [ebp-54]       ; |
004398B5   . |8B15 7>mov     edx, dword ptr [4D5774]       ; |
004398BB   . |50     push    eax                           ; |Arg3
004398BC   . |83CA 0>or      edx, 0                        ; |
004398BF   . |6A 00  push    0                             ; |Arg2 = 00000000
004398C1   . |52     push    edx                           ; |Arg1
004398C2   . |E8 BDD>call    00496B84                      ; \update_Plugin
004398C7   . |83C4 1>add     esp, 10
004398CA   . |85C0   test    eax, eax
004398CC   .^ 0F85 A>jnz     00439077
004398D2   . |68 050>push    105                           ; /Arg5 = 00000105
004398D7   . |6A 00  push    0                             ; |Arg4 = 00000000
004398D9   . |6A 00  push    0                             ; |Arg3 = 00000000
004398DB   . |6A 00  push    0                             ; |Arg2 = 00000000
004398DD   . |8B0D 1>mov     ecx, dword ptr [4D571C]       ; |
004398E3   . |51     push    ecx                           ; |Arg1 => 00000340
004398E4   . |E8 2F3>call    _Setcpu                       ; \_Setcpu
004398E9   . |83C4 1>add     esp, 14
发送广播到子窗体,要求更新窗口内容,设置窗口获得焦点,最后返回到消息循环开始处继续:
004398EC   . |6A 00  push    0                             ; /Arg3 = 00000000
004398EE   . |6A 00  push    0                             ; |Arg2 = 00000000
004398F0   . |68 740>push    474                           ; |Arg1 = 00000474
004398F5   . |E8 7A0>call    _Broadcast                    ; \_Broadcast
004398FA   . |83C4 0>add     esp, 0C
004398FD   . |A1 7C3>mov     eax, dword ptr [4D3B7C]
00439902   . |50     push    eax                           ; /hWnd
00439903   . |E8 925>call    <jmp.&USER32.SetForegroundWin>; \SetForegroundWindow
00439908   .^ E9 6AF>jmp     00439077
调整优先级,返回到消息循环开始处继续:
0043990D   > |6A 04  push    4                             ; /Arg1 = 00000004
0043990F   . |E8 C48>call    _Animate                      ; \_Animate
00439914   . |59     pop     ecx
00439915   .^ E9 5DF>jmp     00439077
检查标识,调整优先级:
0043991A   > |85DB   test    ebx, ebx
0043991C   . |7E 02  jle     short 00439920
0043991E   . |33DB   xor     ebx, ebx
00439920   > |6A 00  push    0
00439922   . |E8 B18>call    _Animate
00439927   . |59     pop     ecx
检查调试操作是否为Execute till user code(执行到用户代码),若不是则跳过该处理部分:
00439928   > |833D C>cmp     dword ptr [4D57CC], 5
0043992F   . |75 30  jnz     short 00439961
一样是检查EIP寄存器信息是否存在,若不存在跳过该处理部分:
00439931   . |837D A>cmp     dword ptr [ebp-54], 0
00439935   . |74 2A  je      short 00439961
找到EIP所在的模块,检查是否是系统模块,若是则跳到该处理结束处:
00439937   . |8B45 A>mov     eax, dword ptr [ebp-54]
0043993A   . |8B50 2>mov     edx, dword ptr [eax+2C]
0043993D   . |52     push    edx                           ; /Arg1
0043993E   . |E8 D54>call    _Findmodule                   ; \_Findmodule
00439943   . |59     pop     ecx
00439944   . |8BF8   mov     edi, eax
00439946   . |85C0   test    eax, eax
00439948   . |74 09  je      short 00439953
0043994A   . |83BF F>cmp     dword ptr [edi+3F5], 0    ; issystemdll == 0 ??
00439951   . |75 0E  jnz     short 00439961
根据ebx标识设置优先级,以及进行相应的跳转:
00439953   > |85DB   test    ebx, ebx
00439955   . |7E 02  jle     short 00439959
00439957   . |33DB   xor     ebx, ebx
00439959   > |6A 00  push    0
0043995B   . |E8 788>call    _Animate
00439960   . |59     pop     ecx
00439961   > |83FB 0>cmp     ebx, 2
00439964   . |75 24  jnz     short 0043998A
检查调试操作是否为Gracefully stop animation(停止自动跟踪),若不是则跳过该处理部分,该部分的处理就是调用OD的导出函数_GO,跳转到对调试信息处理的结束判断处,不再做其他检查:
00439966   . |833D C>cmp     dword ptr [4D57CC], 8
0043996D   . |74 1B  je      short 0043998A
0043996F   . |6A 00  push    0                             ; /Arg5 = 00000000
00439971   . |6A 00  push    0                             ; |Arg4 = 00000000
00439973   . |6A 00  push    0                             ; |Arg3 = 00000000
00439975   . |6A 00  push    0                             ; |Arg2 = 00000000
00439977   . |A1 1C5>mov     eax, dword ptr [4D571C]       ; |
0043997C   . |50     push    eax                           ; |Arg1 => 00000340
0043997D   . |E8 92B>call    _Go                           ; \_Go
00439982   . |83C4 1>add     esp, 14
00439985   . |E9 640>jmp     0043A2EE
根据ebx标识跳过下面的处理函数:
0043998A   > |83FB 0>cmp     ebx, 1
0043998D   . |75 41  jnz     short 004399D0
检查调试操作是否为No animation(无自动跟踪),若不是则跳过该处理部分:
0043998F   . |833D C>cmp     dword ptr [4D57CC], 0
00439996   . |74 09  je      short 004399A1
下面对一些参数进行检查,根据检查结果设置ebx,以及是否设置所有的断点:
00439998   . |833D 1>cmp  dword ptr [4D5714], 1  ;检查异常码是否为EXCEPTION_DEBUG_EVENT
0043999F   . |74 2F  je      short 004399D0
004399A1   > |6A 00  push    0
004399A3   . |6A 00  push    0
004399A5   . |833D F>cmp     dword ptr [4D56FC], 2
004399AC   . |74 0D  je      short 004399BB
004399AE   . |833D F>cmp     dword ptr [4D56FC], 3
004399B5   . |74 04  je      short 004399BB
004399B7   . |33D2   xor     edx, edx
004399B9   . |EB 05  jmp     short 004399C0
004399BB   > |BA 010>mov     edx, 1
004399C0   > |52     push    edx                           ; |Arg2
004399C1   . |6A FF  push    -1                            ; |Arg1 = FFFFFFFF
004399C3   . |E8 687>call    00431430                      ; \Set_all_Bpoint
004399C8   . |83C4 1>add     esp, 10
004399CB   . |E9 1E0>jmp     0043A2EE    ; 跳转到消息循环体最后
下面一块是对线程信息的检查,检查完毕后设置OD的界面,发送子窗体更新广播,更新插件:
004399D0   > |43     inc     ebx
004399D1   . |0F85 9>jnz     00439A71
004399D7   . |E8 386>call    _Listmemory
004399DC   . |833D 2>cmp     dword ptr [4DE924], 0
004399E3   . |74 05  je      short 004399EA
004399E5   . |E8 C6E>call    00497BB0        ; update_topwin
004399EA   > |833D 1>cmp     dword ptr [4E2F10], 0
004399F1   . |74 05  je      short 004399F8
004399F3   . |E8 903>call    0049CD88
004399F8   > |837D A>cmp     dword ptr [ebp-54], 0
004399FC   . |74 0E  je      short 00439A0C
004399FE   . |6A 00  push    0                             ; /Arg2 = 00000000
00439A00   . |8B4D A>mov     ecx, dword ptr [ebp-54]       ; |
00439A03   . |51     push    ecx                           ; |Arg1
00439A04   . |E8 0F1>call    0048AF18                      ; \ update _ThreadInfo
00439A09   . |83C4 0>add     esp, 8
00439A0C   > |68 010>push    101                           ; /Arg5 = 00000101
00439A11   . |6A 00  push    0                             ; |Arg4 = 00000000
00439A13   . |6A 00  push    0                             ; |Arg3 = 00000000
00439A15   . |6A 00  push    0                             ; |Arg2 = 00000000
00439A17   . |A1 1C5>mov     eax, dword ptr [4D571C]       ; |
00439A1C   . |50     push    eax                           ; |Arg1 => 00000340
00439A1D   . |E8 F63>call    _Setcpu                       ; \_Setcpu
00439A22   . |83C4 1>add     esp, 14
00439A25   . |6A 00  push    0                             ; /Arg3 = 00000000
00439A27   . |6A 00  push    0                             ; |Arg2 = 00000000
00439A29   . |68 740>push    474                           ; |Arg1 = 00000474
00439A2E   . |E8 410>call    _Broadcast                    ; \_Broadcast
00439A33   . |83C4 0>add     esp, 0C
00439A36   . |8B15 7>mov     edx, dword ptr [4D3B7C]
00439A3C   . |52     push    edx                           ; /hWnd
00439A3D   . |E8 585>call    <jmp.&USER32.SetForegroundWin>; \SetForegroundWindow
00439A42   . |33C9   xor     ecx, ecx
00439A44   . |33C0   xor     eax, eax
00439A46   . |890D 3>mov     dword ptr [4E3B30], ecx
00439A4C   . |A3 343>mov     dword ptr [4E3B34], eax
00439A51   . |6A 04  push    4                             ; /Arg1 = 00000004
00439A53   . |E8 207>call    00431978                      ; \update_subwin
00439A58   . |59     pop     ecx
00439A59   . |68 145>push    004D5714                      ; /Arg4 = 004D5714
00439A5E   . |6A 00  push    0                             ; |Arg3 = 00000000
00439A60   . |6A 00  push    0                             ; |Arg2 = 00000000
00439A62   . |6A 02  push    2                             ; |Arg1 = 00000002
00439A64   . |E8 1BD>call    00496B84                      ; \update_Plugin
00439A69   . |83C4 1>add     esp, 10
00439A6C   . |E9 7D0>jmp     0043A2EE
下面省略部分是一些对OD操作的处理,跟上面雷同,一般都是调用_GO函数执行代码;检查更新一些标识;用_Broadcast函数发送更新广播;检查是否有自动跟踪文件,对其进行更新等等:
……
……
两个对系统时间全局变量的判断以及设置,更新窗口,跳转到循环体开始处:
0043A2EE   > |833D 1>cmp     dword ptr [4E3A1C], 0
0043A2F5   . |74 0A  je      short 0043A301
0043A2F7   . |A1 1C3>mov     eax, dword ptr [4E3A1C]
0043A2FC   . |3B45 C>cmp     eax, dword ptr [ebp-34]
0043A2FF   . |72 1C  jb      short 0043A31D
0043A301   > |833D 1>cmp     dword ptr [4E3814], 0
0043A308   .^ 0F84 6>je      00439077
0043A30E   . |8B15 1>mov     edx, dword ptr [4E3814]
0043A314   . |3B55 C>cmp     edx, dword ptr [ebp-34]
0043A317   .^ 0F83 5>jnb     00439077
0043A31D   > |E8 3E7>call    00431960
0043A322   .^\E9 50E>jmp     00439077

                              武汉科锐学员: angelqkm
                                2008-5-29