这是分析报告的第二部分,请多多指教。
Ollydbg(以下均简称为OD)中的内存断点的主要功能是:修改要下内存断点的内存页属性,如访问断点就设置禁止访问、执行断点就设置禁止执行。这样当程序要用到这个内存页时就会报异常,由OD捕获,OD比较一下是否是下了断点的内存区域,如果不是就继续执行,否则就断下等待调试人员操作。
内存断点的添加、设置以及判断部分是由不同的函数处理的,先说一下这三个函数的关系,然后写出其流程,最后分析代码:
内存断点添加函数一般只是设置内存断点信息表,并不修改内存访问属性,若是在运行状态时设置内存断点,则会修改内存页属性;内存断点设置函数是在按下F9时才会被调用的,并且每走一步调用一次,其主要作用就是根据内存断点信息表设置内存页属性;内存断点处理函数则是在一个大的异常处理函数中的一部分,OD通过异常事件结构体处理对应的各种异常,下面只提取有关的部分进行分析。
OD中用一个结构体来存储内存断点的信息,且只能下一个内存断点,下第二个断点会将前面的记录覆盖:
第一个4字节 00000000 未知
第二个4字节 00400654 标识内存断点首地址
第三个4字节 00000004 内存断点字节的长度
第四个4字节 00400000 内存断点首地址所在内存页的地址
第五个4字节 00401000 内存断点尾地址所在内存页的地址
第六个4字节 00000001 01-标识内存访问断点 20-标识内存写入断点
第七个4字节 00000000 未知
004D8138 00 00 00 00 33 05 40 00 02 00 00 00 00 00 40 00 ....3 @. .....@.
004D8148 00 10 40 00 01 00 00 00 00 00 00 00 . @. .......
此外还有一个存放内存信息的结构体:
typedef struct t_memory { // Memory block descriptor
ulong base; // Base address of memory block
ulong size; // Size of block
ulong type; // Service information, TY_xxx
ulong owner; // Address of owner of the memory
ulong initaccess; // Initial read/write access
ulong access; // Actual status and read/write access
ulong threadid; // Block belongs to this thread or 0
char sect[SHORTLEN]; // Name of module section
char *copy; // Copy used in CPU window or NULL
ulong reserved[8]; // Reserved for plugin compatibility
} t_memory;
首先是添加部分的函数:
1. 内存断点的添加是通过消息来处理的,而且反汇编窗口和数据窗口的消息还不一样,这样就有了两组对应的消息,数据窗口中:访问断点-7Eh、写入断点-7Fh、清除断点-80h;反汇编窗口中:访问断点-23h、写入断点-24h、清除断点-25h;
2. 将Setmembreakpoint函数参数传入,让函数做相应的处理。该函数有三个参数,分别为标识断点属性、首地址以及长度,这里先概括的描述一下这个函数的流程:
a) 将参数赋值给寄存器,并得到内存断点所在的内存页;
b) 检查是否在系统内存处、资源内存处、堆栈内存处下断点,若是则弹出警告,并返回-1退出函数;
c) 将内存断点的信息写入一个结构体中,便于查询;
d) 写完结构体后检查是否运行状态,如果是则调用函数修改内存页属性,值得一提的这里修改内存页属性的API并不是直接调用,而是用一个指针指向这两个API:VirtualQuery、VirtualProtectEx,在使用前还会检查两个API是否存在;
e) 最后返回0并退出
这部分为数据窗口中设置内存断点部分的代码:
判断是否为访问断点,并填入相应的参数让Setmembreakpoint函数处理:
00451C29 > \83FF 7>cmp edi, 7E
00451C2C . 75 2E jnz short 00451C5C
00451C2E . 8B45 A>mov eax, dword ptr [ebp-54] ; Case 7E of switch 0045115A
00451C31 . 2B45 B>sub eax, dword ptr [ebp-50]
00451C34 . 50 push eax ; /Arg3
00451C35 . 8B55 B>mov edx, dword ptr [ebp-50] ; |
00451C38 . 52 push edx ; |Arg2
00451C39 . 6A 03 push 3 ; |Arg1 = 00000003
00451C3B . E8 987>call _Setmembreakpoint ; \_Setmembreakpoint
00451C40 . 83C4 0>add esp, 0C
00451C43 . F683 5>test byte ptr [ebx+25D], 10
00451C4A . 0F84 2>je 00452C7C
00451C50 . 53 push ebx ; /Arg1
00451C51 . E8 F6C>call 0044E54C ; \Ollydbg.0044E54C
00451C56 . 59 pop ecx
00451C57 . E9 201>jmp 00452C7C
判断是否为写入断点,并填入相应的参数让Setmembreakpoint函数处理:
00451C5C > 83FF 7>cmp edi, 7F
00451C5F . 75 2E jnz short 00451C8F
00451C61 . 8B4D A>mov ecx, dword ptr [ebp-54] ; Case 7F of switch 0045115A
00451C64 . 2B4D B>sub ecx, dword ptr [ebp-50]
00451C67 . 51 push ecx ; /Arg3
00451C68 . 8B45 B>mov eax, dword ptr [ebp-50] ; |
00451C6B . 50 push eax ; |Arg2
00451C6C . 6A 02 push 2 ; |Arg1 = 00000002
00451C6E . E8 657>call _Setmembreakpoint ; \_Setmembreakpoint
00451C73 . 83C4 0>add esp, 0C
00451C76 . F683 5>test byte ptr [ebx+25D], 10
00451C7D . 0F84 F>je 00452C7C
00451C83 . 53 push ebx ; /Arg1
00451C84 . E8 C3C>call 0044E54C ; \Ollydbg.0044E54C
00451C89 . 59 pop ecx
00451C8A . E9 ED0>jmp 00452C7C
判断是否为清除断点,并填入相应的参数让Setmembreakpoint函数处理:
00451C8F > 81FF 8>cmp edi, 80
00451C95 . 75 13 jnz short 00451CAA
00451C97 . 6A 00 push 0 ; /Arg3 = 00000000;
00451C99 . 6A 00 push 0 ; |Arg2 = 00000000
00451C9B . 6A 00 push 0 ; |Arg1 = 00000000
00451C9D . E8 367>call _Setmembreakpoint ; \_Setmembreakpoint
00451CA2 . 83C4 0>add esp, 0C
00451CA5 . E9 D20>jmp 00452C7C
这部分为反汇编窗口中设置内存断点部分的代码:
判断是否为访问断点,并填入相应的参数让Setmembreakpoint函数处理:
004238D3 > \83FB 23 cmp ebx, 23
004238D6 . 75 22 jnz short 004238FA
004238D8 . 8B0D 31DA4>mov ecx, dword ptr [4CDA31] ; Case 23 of switch 00422DD4
004238DE . A1 2DDA4C0>mov eax, dword ptr [4CDA2D]
004238E3 . 2B0D 2DDA4>sub ecx, dword ptr [4CDA2D]
004238E9 . 51 push ecx ; /Arg3
004238EA . 50 push eax ; |Arg2 => 00000000
004238EB . 6A 03 push 3 ; |Arg1 = 00000003
004238ED . E8 E659FFF>call _Setmembreakpoint ; \_Setmembreakpoint
004238F2 . 83C4 0C add esp, 0C
004238F5 . E9 E224000>jmp 00425DDC
判断是否为写入断点,并填入相应的参数让Setmembreakpoint函数处理:
004238FA > 83FB 24 cmp ebx, 24
004238FD . 75 23 jnz short 00423922
004238FF . 8B15 31DA4>mov edx, dword ptr [4CDA31] ; Case 24 of switch 00422DD4
00423905 . 8B0D 2DDA4>mov ecx, dword ptr [4CDA2D]
0042390B . 2B15 2DDA4>sub edx, dword ptr [4CDA2D]
00423911 . 52 push edx ; /Arg3
00423912 . 51 push ecx ; |Arg2 => 00000000
00423913 . 6A 02 push 2 ; |Arg1 = 00000002
00423915 . E8 BE59FFF>call _Setmembreakpoint ; \_Setmembreakpoint
0042391A . 83C4 0C add esp, 0C
0042391D . E9 BA24000>jmp 00425DDC
判断是否为清除断点,并填入相应的参数让Setmembreakpoint函数处理:
00423922 > 83FB 25 cmp ebx, 25
00423925 . 75 13 jnz short 0042393A
00423927 . 6A 00 push 0 ; /Arg3 = 00000000; Case 25 of switch 00422DD4
00423929 . 6A 00 push 0 ; |Arg2 = 00000000
0042392B . 6A 00 push 0 ; |Arg1 = 00000000
0042392D . E8 A659FFF>call _Setmembreakpoint ; \_Setmembreakpoint
00423932 . 83C4 0C add esp, 0C
00423935 . E9 A224000>jmp 00425DDC
下面就来详细的分析Setmembreakpoint这个函数:
首先将参数赋值给寄存器,并得到内存断点所在的内存页:
004192D8 >/$ 55 push ebp
004192D9 |. 8BEC mov ebp, esp
004192DB |. 53 push ebx
004192DC |. 56 push esi
004192DD |. 57 push edi
004192DE |. 833D 38814D00>cmp dword ptr [4D8138], 0
004192E5 |. 8B7D 10 mov edi, dword ptr [ebp+10] 内存断点长度
004192E8 |. 8B75 0C mov esi, dword ptr [ebp+C] 内存断点首地址赋值
004192EB |. 8B5D 08 mov ebx, dword ptr [ebp+8] 内存断点标识赋值
004192EE |. 0F85 99000000 jnz 0041938D
004192F4 |. 833D D8364D00>cmp dword ptr [4D36D8], 2
004192FB |. 0F84 8C000000 je 0041938D
00419301 |. 56 push esi ; /Arg1
00419302 |. E8 41870400 call _Findmemory ; \_Findmemory
00419307 |. 59 pop ecx
检查是否在系统内存处下断点,并弹出警告:
00419308 |. 81FE 00000080 cmp esi, 80000000
0041930E |. 72 24 jb short 00419334
00419310 |. 6A 14 push 14
00419312 |. 68 CA224B00 push 004B22CA
00419317 |. 68 2E224B00 push 004B222E
0041931C |. A1 7C3B4D00 mov eax, dword ptr [4D3B7C] ; |
00419321 |. 50 push eax
00419322 |. E8 EF610900 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00419327 |. 83F8 06 cmp eax, 6
0041932A |. 74 61 je short 0041938D
0041932C |. 83C8 FF or eax, FFFFFFFF
0041932F |. E9 EA000000 jmp 0041941E
检查是否在资源内存处下断点,并弹出警告:
00419334 |> 85C0 test eax, eax
00419336 |. 74 2B je short 00419363
00419338 |. F640 0B 01 test byte ptr [eax+B], 1
0041933C |. 74 25 je short 00419363
0041933E |. 6A 14 push 14
00419340 |. 68 A1234B00 push 004B23A1
00419345 |. 68 EB224B00 push 004B22EB
0041934A |. 8B15 7C3B4D00 mov edx, dword ptr [4D3B7C] ; |
00419350 |. 52 push edx
00419351 |. E8 C0610900 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00419356 |. 83F8 06 cmp eax, 6
00419359 |. 74 32 je short 0041938D
0041935B |. 83C8 FF or eax, FFFFFFFF
0041935E |. E9 BB000000 jmp 0041941E
检查是否在堆栈内存处下断点,并弹出警告:
00419363 |> 85C0 test eax, eax
00419365 |. 74 26 je short 0041938D
00419367 |. F640 0B 04 test byte ptr [eax+B], 4
0041936B |. 74 20 je short 0041938D
0041936D |. 6A 10 push 10
0041936F |. 68 24244B00 push 004B2424
00419374 |. 68 BF234B00 push 004B23BF
00419379 |. 8B15 7C3B4D00 mov edx, dword ptr [4D3B7C] ; |
0041937F |. 52 push edx
00419380 |. E8 91610900 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00419385 |. 83C8 FF or eax, FFFFFFFF
00419388 |. E9 91000000 jmp 0041941E
函数中该部分主要设置内存属性:
0041938D |> \E8 92FAFFFF call 00418E24 该函数主要用于设置内存属性
00419392 |. 85C0 test eax, eax
00419394 |. 74 08 je short 0041939E 设置成功就去设置结构体,否则退出
00419396 |. 83C8 FF or eax, FFFFFFFF
00419399 |. E9 80000000 jmp 0041941E
函数中该部分主要用于设置断点结构体:
0041939E |> \8BC6 mov eax, esi
004193A0 |. 8BD7 mov edx, edi
004193A2 |. A3 3C814D00 mov dword ptr [4D813C], eax ;填写结构体第二个字节
004193A7 |. 8BC8 mov ecx, eax
004193A9 |. 03C2 add eax, edx
004193AB |. 81E1 00F0FFFF and ecx, FFFFF000
004193B1 |. 05 FF0F0000 add eax, 0FFF
004193B6 |. 8915 40814D00 mov dword ptr [4D8140], edx ;填写结构体第三个字节
004193BC |. 25 00F0FFFF and eax, FFFFF000
004193C1 |. 890D 44814D00 mov dword ptr [4D8144], ecx ;填写结构体第四个字节
004193C7 |. F6C7 10 test bh, 10
004193CA |. A3 48814D00 mov dword ptr [4D8148], eax ;填写结构体第五个字节
004193CF |. 0F95C0 setne al
004193D2 |. 83E0 01 and eax, 1
004193D5 |. 83E3 03 and ebx, 3
004193D8 |. A3 38814D00 mov dword ptr [4D8138], eax
004193DD |. C705 5C8D4D00>mov dword ptr [4D8D5C], 1
004193E7 |. 85DB test ebx, ebx
004193E9 |. 74 04 je short 004193EF
004193EB |. 85FF test edi, edi
004193ED |. 75 04 jnz short 004193F3
004193EF |> 33C0 xor eax, eax
004193F1 |. EB 2B jmp short 0041941E
004193F3 |> 83FB 02 cmp ebx, 2
004193F6 |. 75 0C jnz short 00419404
004193F8 |. C705 4C814D00>mov dword ptr [4D814C], 20 ;填写结构体第六个字节
00419402 |. EB 0A jmp short 0041940E
00419404 |> C705 4C814D00>mov dword ptr [4D814C], 1
设置完内存断点记录后,检查是否是运行状态,如果是则调用函数设置内存页属性:
0041940E |> 833D 5C5A4D00>cmp dword ptr [4D5A5C], 3 ;查看是否是运行状态
00419415 |. 75 05 jnz short 0041941C ;不是则结束
00419417 |. E8 18FCFFFF call 00419034 ;如果是则调用函数修改内存页属性
恢复现场,返回0:
0041941C |> 33C0 xor eax, eax ;返回0
0041941E |> 5F pop edi
0041941F |. 5E pop esi
00419420 |. 5B pop ebx
00419421 |. 5D pop ebp
00419422 \. C3 retn 其次是设置部分的函数:
1. 一些参数的检查,错误则返回-1并结束;
2. 检查VirtualQuery、VirtualProtectEx这两个函数是否加载成功,若失败则返回-1并结束;
3. 这里是一个循环体,用于设置内存断点范围内的内存页属性,主要流程如下:
a) 初始化循环体,得到内存断点所在的第一个内存页地址,并检查其合法性;
b) 加上内存页最小单位(1000h),检查是否大于等于内存断点的尾地址,若小于则得到其内存断点的范围减去1000h,用于下次判断;
c) 一些标志、长度的判断以及设置;
d) 按内存断点的范围设置内存页属性,将内存页原来的属性保存到两个数组中去,并检查是否设置成功,若设置失败则跳出循环体;
e) 判断判断是否设置完内存断点范围内的所有内存页,并检查是否超出最大内存断点范围(1000h*100h),若超过或者设置完则退出循环,否则跳转到b步骤;
4. 检查设置内存页属性后其地址是否等于内存断点范围首地址,若等于说明一开始就设置失败,删除内存断点表,并给出相应的提示以及弹出窗口;
5. 检查设置内存页属性后其地址是否大于等于内存断点范围尾地址,若小于说明有一部分设置失败,缩小内存断点的范围,并给出相应的提示以及弹出窗口;
该函数我命名为SetMembpoint,主要用于F9运行后内地断点的设置,下面来详细分析:
首先是一些参数的检查,错误则跳转到错误处理处:
00419034 /$ 53 push ebx
00419035 |. 56 push esi
00419036 |. 57 push edi
00419037 |. 55 push ebp
00419038 |. 81C4 E4FDFFFF add esp, -21C
0041903E |. BD 588D4D00 mov ebp, 004D8D58
00419043 |. 833D 685A4D00 0>cmp dword ptr [4D5A68], 0 ; 检查线程句柄
0041904A |. 74 12 je short 0041905E
0041904C |. 833D 40814D00 0>cmp dword ptr [4D8140], 0 ; 检查断点长度
00419053 |. 74 09 je short 0041905E
00419055 |. 833D 34814D00 0>cmp dword ptr [4D8134], 0 ; 检查是否已经检查的标识
0041905C |. 74 07 je short 00419065 ; 若正确则跳过下面的错误处理
错误处理,返回-1并跳转到结束处:
0041905E |> 33C0 xor eax, eax
00419060 |. E9 66020000 jmp 004192CB ; 跳转到结束处
下面检查VirtualQuery、VirtualProtectEx这两个函数是否加载成功:
00419065 |> 833D 145A4D00 0>cmp dword ptr [4D5A14], 0 ; 检查VirtualQuery
0041906C |. 74 09 je short 00419077
0041906E |. 833D 185A4D00 0>cmp dword ptr [4D5A18], 0 ; 检查VirtualProtectEx
00419075 |. 75 08 jnz short 0041907F ; 若正确则跳过下面的错误处理
错误处理,返回-1并跳转到结束处:
00419077 |> 83C8 FF or eax, FFFFFFFF
0041907A |. E9 4C020000 jmp 004192CB
通过内存断点所在页的首地址得到其内存相关信息结构体t_memory,检查是否取得成功;并检查该内存断点所在页是否是TY_GUARDED(被保护状态),若是则跳转到最后检查是否比较完处,初始化循环体:
0041907F |> 33D2 xor edx, edx
00419081 |. 8955 00 mov dword ptr [ebp], edx
00419084 |. A1 44814D00 mov eax, dword ptr [4D8144]
00419089 |. 8BD8 mov ebx, eax
0041908B |. 8125 4C814D00 F>and dword ptr [4D814C], FFFFFEFF>
00419095 |. 50 push eax ; /Arg1
00419096 |. E8 AD890400 call _Findmemory ; \_Findmemory
0041909B |. 59 pop ecx
0041909C |. 85C0 test eax, eax ;检查是否取得成功
0041909E |. 0F84 25010000 je 004191C9
004190A4 |. F640 0B 20 test byte ptr [eax+B], 20 ; 检查是否为TY_GUARDED
004190A8 |. 0F84 1B010000 je 004191C9
004190AE |. 810D 4C814D00 0>or dword ptr [4D814C], 100 ; 将写入标志与0x100或
004190B8 |. E9 0C010000 jmp 004191C9
首先取得内存断点所在的首内存页的内存属性:
004190BD |> 6A 1C /push 1C
004190BF |. 8D8424 04020000 |lea eax, dword ptr [esp+204]
004190C6 |. 50 |push eax
004190C7 |. 53 |push ebx
004190C8 |. 8B15 685A4D00 |mov edx, dword ptr [4D5A68]
004190CE |. 52 |push edx
004190CF |. FF15 145A4D00 |call dword ptr [4D5A14] ; kernel32.VirtualQueryEx
加上内存页最小单位(1000h),检查是否已经包含了内存断点的范围:
004190D5 |. 8B9424 0C020000 |mov edx, dword ptr [esp+20C]
004190DC |. 8BCA |mov ecx, edx
004190DE |. 03CB |add ecx, ebx ; ecx :BP_Begin_Page + 1000
004190E0 |. A1 48814D00 |mov eax, dword ptr [4D8148] ; eax :BreakPoint_End_Page
004190E5 |. 3BC8 |cmp ecx, eax ; 检查是否包含内存断点的范围
004190E7 |. 73 04 |jnb short 004190ED ; 不包含则跳到下面处理代码
004190E9 |. 8BF2 |mov esi, edx ; esi :内存对齐最小单位
004190EB |. EB 04 |jmp short 004190F1 ; 跳过处理代码
若没有完全包含,则得到其内存断点的范围:
004190ED |> 8BF0 |mov esi, eax
004190EF |. 2BF3 |sub esi, ebx
下面是一些标志位的比较以及设置:
004190F1 |> 833D 38814D00 0>|cmp dword ptr [4D8138], 0
004190F8 |. 74 1B |je short 00419115
004190FA |. 3B1D 50814D00 |cmp ebx, dword ptr [4D8150]
00419100 |. 73 13 |jnb short 00419115
00419102 |. 8D041E |lea eax, dword ptr [esi+ebx]
00419105 |. 3B05 50814D00 |cmp eax, dword ptr [4D8150]
0041910B |. 76 08 |jbe short 00419115
0041910D |. 8B35 50814D00 |mov esi, dword ptr [4D8150]
00419113 |. 2BF3 |sub esi, ebx
00419115 |> 833D 38814D00 0>|cmp dword ptr [4D8138], 0
0041911C |. 74 1B |je short 00419139
0041911E |. 3B1D 54814D00 |cmp ebx, dword ptr [4D8154]
00419124 |. 73 13 |jnb short 00419139
00419126 |. 8D041E |lea eax, dword ptr [esi+ebx]
00419129 |. 3B05 54814D00 |cmp eax, dword ptr [4D8154]
0041912F |. 76 08 |jbe short 00419139
00419131 |. 8B35 54814D00 |mov esi, dword ptr [4D8154]
00419137 |. 2BF3 |sub esi, ebx
00419139 |> 833D 38814D00 0>|cmp dword ptr [4D8138], 0
00419140 |. 74 2A |je short 0041916C
00419142 |. 3B1D 50814D00 |cmp ebx, dword ptr [4D8150]
00419148 |. 75 22 |jnz short 0041916C
0041914A |. BE 00100000 |mov esi, 1000
0041914F |. 8B55 00 |mov edx, dword ptr [ebp]
00419152 |. 8B8424 14020000 |mov eax, dword ptr [esp+214]
00419159 |. 890495 58814D00 |mov dword ptr [edx*4+4D8158],>
00419160 |. 8B4D 00 |mov ecx, dword ptr [ebp]
00419163 |. 89048D 58854D00 |mov dword ptr [ecx*4+4D8558],>
0041916A |. EB 4E |jmp short 004191BA
0041916C |> 833D 38814D00 0>|cmp dword ptr [4D8138], 0
00419173 |. 74 14 |je short 00419189
00419175 |. 3B1D 54814D00 |cmp ebx, dword ptr [4D8154]
0041917B |. 75 0C |jnz short 00419189
0041917D |. BE 00100000 |mov esi, 1000
00419182 |. BF 02000000 |mov edi, 2
00419187 |. EB 06 |jmp short 0041918F
根据内存断点表设置内存页属性,并检查是否设置成功:
00419189 |> 8B3D 4C814D00 |mov edi, dword ptr [4D814C]
0041918F |> 8B45 00 |mov eax, dword ptr [ebp]
00419192 |. 8B15 685A4D00 |mov edx, dword ptr [4D5A68]
00419198 |. C1E0 02 |shl eax, 2
0041919B |. 81C0 58814D00 |add eax, 004D8158
004191A1 |. 50 |push eax
004191A2 |. 57 |push edi
004191A3 |. 56 |push esi
004191A4 |. 53 |push ebx
004191A5 |. 52 |push edx
004191A6 |. FF15 185A4D00 |call dword ptr [4D5A18] ; kernel32.VirtualProtectEx
004191AC |. 85C0 |test eax, eax ;检查是否设置成功
004191AE |. 74 2E |je short 004191DE ;设置失败跳到错误处理处
将内存页原属性放到全局变量数组中去,并将计数器加一:
004191B0 |. 8B4D 00 |mov ecx, dword ptr [ebp]
004191B3 |. 893C8D 58854D00 |mov dword ptr [ecx*4+4D8558],>
004191BA |> 8B45 00 |mov eax, dword ptr [ebp]
004191BD |. 893485 58894D00 |mov dword ptr [eax*4+4D8958],>
004191C4 |. 03DE |add ebx, esi
004191C6 |. FF45 00 |inc dword ptr [ebp]
循环体条件检查部分,设定了内存断点的最大范围是1000h*100h,若超过了则不再设置内存断点;另外检查是否已经设置完内存断点范围内的所有内存页,若没有设置完继续设置:
004191C9 |> 817D 00 0001000> cmp dword ptr [ebp], 100 ;检查内存断点是否超过最大范围
004191D0 |. 7D 0C |jge short 004191DE
004191D2 |. 3B1D 48814D00 |cmp ebx, dword ptr [4D8148] ; 检查是否设置完内存属性
004191D8 |.^ 0F82 DFFEFFFF \jb 004190BD ; 若没有设置完则继续
检查设置内存页属性结构体的循环体结束后,其地址是否等于内存断点范围的首内存页地址,若不等于则跳过下面的错误处理:
004191DE |> 3B1D 44814D00 cmp ebx, dword ptr [4D8144] ;
004191E4 |. 75 64 jnz short 0041924A
这里为设置内存断点失败的处理处,得到内存无法设置的范围,并给出错误提示和弹出窗口:
004191E6 |. 8D9424 00010000 lea edx, dword ptr [esp+100]
004191ED |. 52 push edx ; /Arg3
004191EE |. 8B0D 40814D00 mov ecx, dword ptr [4D8140] ; |
004191F4 |. 51 push ecx ; |Arg2 => 00000002
004191F5 |. A1 3C814D00 mov eax, dword ptr [4D813C] ; |
004191FA |. 50 push eax ; |Arg1 => 00400533
004191FB |. E8 E04D0400 call _Decoderange ; \_Decoderange
00419200 |. 83C4 0C add esp, 0C
00419203 |. 8D9424 00010000 lea edx, dword ptr [esp+100]
0041920A |. 52 push edx ; /Arg3
0041920B |. 68 FA204B00 push 004B20FA ; |ollydbg 在地址范围 %s 中无法激活内存断点。断点已经被完全删除。
00419210 |. 8D4C24 08 lea ecx, dword ptr [esp+8] ; |
00419214 |. 51 push ecx ; |Arg1
00419215 |. E8 12DA0800 call 004A6C2C ; \_sprintf
0041921A |. 83C4 0C add esp, 0C
0041921D |. 6A 10 push 10 ; /Style = MB_OK
0041921F |. 68 61214B00 push 004B2161 ; |无法激活内存中的断点
00419224 |. 8D4424 08 lea eax, dword ptr [esp+8] ; |
00419228 |. 50 push eax ; |Text
00419229 |. 8B15 7C3B4D00 mov edx, dword ptr [4D3B7C] ; |
0041922F |. 52 push edx ; |hOwner
00419230 |. E8 E1620900 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
将内存页属性还原回来,将内存断点长度设置为0,返回-1并退出:
00419235 |. E8 EAFBFFFF call 00418E24
0041923A |. 33C9 xor ecx, ecx
0041923C |. 83C8 FF or eax, FFFFFFFF
0041923F |. 890D 40814D00 mov dword ptr [4D8140], ecx
00419245 |. E9 81000000 jmp 004192CB
检查设置内存页属性结构体的循环体结束后,其地址是否大于等于内存断点范围的尾内存页地址,若大于则跳过下面的错误处理:
0041924A |> 3B1D 48814D00 cmp ebx, dword ptr [4D8148] ; Ollydbg.<模块入口点>
00419250 |. 73 6D jnb short 004192BF
这里为设置内存断点范围尾部设置失败的错误处理处,设置相应的错误提示和弹出窗口:
00419252 |. 8D9424 00010000 lea edx, dword ptr [esp+100]
00419259 |. 52 push edx ; /Arg3
0041925A |. 8B0D 40814D00 mov ecx, dword ptr [4D8140] ; |
00419260 |. 51 push ecx ; |Arg2 => 00000002
00419261 |. A1 3C814D00 mov eax, dword ptr [4D813C] ; |
00419266 |. 50 push eax ; |Arg1 => 00400533
00419267 |. E8 744D0400 call _Decoderange ; \_Decoderange
0041926C |. 83C4 0C add esp, 0C
0041926F |. 8BD3 mov edx, ebx
00419271 |. 4A dec edx
00419272 |. 52 push edx ; /Arg5
00419273 |. 8B0D 3C814D00 mov ecx, dword ptr [4D813C] ; |Ollydbg.00400533
00419279 |. 51 push ecx ; |Arg4 => 00400533
0041927A |. 8D8424 08010000 lea eax, dword ptr [esp+108] ; |
00419281 |. 50 push eax ; |Arg3
00419282 |. 68 86214B00 push 004B2186 ; |ollydbg 在全部指定的地址范围(%s)中无法激活内存断点。断点已经减少范围为 %08lx..%08lx.
00419287 |. 8D5424 10 lea edx, dword ptr [esp+10] ; |
0041928B |. 52 push edx ; |Arg1
0041928C |. E8 9BD90800 call 004A6C2C ; \_sprintf
00419291 |. 83C4 14 add esp, 14
00419294 |. 6A 10 push 10 ; /Style = MB_OK
00419296 |. 68 0E224B00 push 004B220E ; |内存断点的范围被减少
0041929B |. 8D4C24 08 lea ecx, dword ptr [esp+8] ; |
0041929F |. 51 push ecx ; |Text
004192A0 |. A1 7C3B4D00 mov eax, dword ptr [4D3B7C] ; |
004192A5 |. 50 push eax ; |hOwner
004192A6 |. E8 6B620900 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
将内存断点的范围缩小为设置失败前已经成功设置的内存页范围:
004192AB |. 8BD3 mov edx, ebx
004192AD |. 2B15 3C814D00 sub edx, dword ptr [4D813C] ; Ollydbg.00400533
004192B3 |. 8915 40814D00 mov dword ptr [4D8140], edx
004192B9 |. 891D 48814D00 mov dword ptr [4D8148], ebx
设置检查标识为1,标识已经检查完毕,然后返回0并退出:
004192BF |> C705 34814D00 0>mov dword ptr [4D8134], 1
004192C9 |. 33C0 xor eax, eax
004192CB |> 81C4 1C020000 add esp, 21C
004192D1 |. 5D pop ebp
004192D2 |. 5F pop edi
004192D3 |. 5E pop esi
004192D4 |. 5B pop ebx
004192D5 \. C3 retn 最后是内存断点的处理,该部分用WaitForDebugEvent函数捕获了内存断点异常,然后对内存断点进行检查以及OD界面进行相关设置,由于之后没有用ContinueDebugEvent函数,被调试程序被断在了该异常处:
1. 得到线程信息结构体,将结构体指针赋值给局部变量;
2. 根据异常信息结构体中的异常事件标识,跳转到相应的异常的处理分支处;
3. 给异常地址变量赋值,若得到线程信息,则根据线程信息的eip赋值,否则根据异常地址赋值,并且将异常地址赋值给几个全局变量;
4. 得到异常所在的模块信息,提取异常所在处的汇编代码,并检查模块信息是否正确,汇编代码有没有获得,根据情况做相应的错误处理;
5. 若是模块为自解压(SFX)模式,则进行相应的检查以及错误处理;
6. 检查内存断点是否在kernel32.dll中,弹出提示窗口,并将断点去除;
7. 最后调整优先级并退出
这里是所有异常的处理函数,除了内存断点相关的代码,其他都会被省略:
首先保存环境,拉伸栈空间:
0042EBD0 /$ 55 push ebp
0042EBD1 |. 8BEC mov ebp, esp
0042EBD3 |. 81C4 04F0F>add esp, -0FFC
0042EBD9 |. 50 push eax
0042EBDA |. 81C4 00F5F>add esp, -0B00
得到调试线程的线程信息结构体,该函数在《OD获得当前cpu工作状态的方法》中已详细分析:
0042EBE0 |. 53 push ebx
0042EBE1 |. 56 push esi
0042EBE2 |. 57 push edi
0042EBE3 |. 8B35 1C574>mov esi, dword ptr [4D571C] ; DebugEvent.dwThreadId
0042EBE9 |. 56 push esi
0042EBEA |. E8 5DF8FFF>call 0042E44C ; GetThreadInfo
将得到的寄存器结构体指针赋值给参数:
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 ; [ebp+8] = pReg
根据异常事件标识标识跳转到相应的处理函数:
0042EBF7 |. 8B15 14574>mov edx, dword ptr [4D5714] ; DebugEvent.dwDebugEventCode
0042EBFD |. 83FA 09 cmp edx, 9 ; Switch (cases 1..9)
0042EC00 |. 0F87 EE270>ja 004313F4
0042EC06 |. FF2495 0DE>jmp dword ptr [edx*4+42EC0D]
调试异常的跳表:
0042EC0D |. F4134300 dd Ollydbg.004313F4 ; Default
0042EC11 |. 35EC4200 dd Ollydbg.0042EC35 ; EXCEPTION_DEBUG_EVENT
0042EC15 |. FF0C4300 dd Ollydbg.00430CFF ; CREATE_THREAD_DEBUG_EVENT
0042EC19 |. D70D4300 dd Ollydbg.00430DD7 ; CREATE_PROCESS_DEBUG_EVENT
0042EC1D |. 3F0F4300 dd Ollydbg.00430F3F ; EXIT_THREAD_DEBUG_EVENT
0042EC21 |. 37104300 dd Ollydbg.00431037 ; EXIT_PROCESS_DEBUG_EVENT
0042EC25 |. 2D114300 dd Ollydbg.0043112D ; LOAD_DLL_DEBUG_EVENT
0042EC29 |. B7114300 dd Ollydbg.004311B7 ; UNLOAD_DLL_DEBUG_EVENT
0042EC2D |. 76124300 dd Ollydbg.00431276 ; OUTPUT_DEBUG_STRING_EVENT
0042EC31 |. C7134300 dd Ollydbg.004313C7 ; RIP_EVENT
这里为调试异常处理处,给异常标识赋值,并将异常结构体指针赋值给局部变量:
0042EC35 |> 8B0D 0C364>mov ecx, dword ptr [4E360C] ;
0042EC3B |. 33C0 xor eax, eax
0042EC3D |. 894D EC mov dword ptr [ebp-14], ecx
0042EC40 |. A3 0C364E0>mov dword ptr [4E360C], eax
0042EC45 |. C745 A4 20>mov dword ptr [ebp-5C], 004D5720 ; DebugEvent.u
检查异常信息结构体中寄存器结构体是否得到,若得到则跳过下面取寄存器信息:
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 ; 参数赋值为ExceptionAddress
0042EC5B |. EB 22 jmp short 0042EC7F
若得到了寄存器信息,则将寄存器中的EIP地址赋值给参数,检查异常标识,若不为0则修改寄存器里面的标识,并设置寄存器已被修改:
0042EC5D |> 8B47 2C mov eax, dword ptr [edi+2C]
0042EC60 |. 8945 D8 mov dword ptr [ebp-28], eax ; 参数赋值为t_reg.r_eip
0042EC63 |. 837D EC 00 cmp dword ptr [ebp-14], 0 ; 检查异常标识
0042EC67 |. 8B5F 10 mov ebx, dword ptr [edi+10] ; ebx : t_reg.r_ecx
0042EC6A |. 74 13 je short 0042EC7F ; 若标识为0则跳过下面的操作
0042EC6C |. F647 31 01 test byte ptr [edi+31], 1
0042EC70 |. 74 0D je short 0042EC7F
0042EC72 |. 8167 30 FF>and dword ptr [edi+30], FFFFFE> ; 修改标识
0042EC79 |. C707 01000>mov dword ptr [edi], 1 ; 设置寄存器修改标识
检查是否是单步异常,若是则跳过下面的代码,若不是则跳转到下面继续判断是什么异常:
0042EC7F |> 8B45 A4 mov eax, dword ptr [ebp-5C]
0042EC82 |. 8138 03000>cmp dword ptr [eax], 80000003
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 6926030>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 CC00000>cmp eax, 0CC
0042ECBC |. 75 09 jnz short 0042ECC7
0042ECBE |. C745 DC 01>mov dword ptr [ebp-24], 1
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 ; |
0042ECDD |. 51 push ecx ; |Arg2
0042ECDE |. 8D45 BB lea eax, dword ptr [ebp-45] ; |
0042ECE1 |. 50 push eax ; |Arg1
0042ECE2 |. E8 2526030>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 CD000>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 02>mov dword ptr [ebp-24], 2
检查参数中的值是eip还是exceptionaddr,若是eip则跳过对几个全局变量的赋值:
0042ED0A |> 8B45 DC mov eax, dword ptr [ebp-24]
0042ED0D |. 2945 D8 sub dword ptr [ebp-28], eax
0042ED10 |. 8B15 08574>mov edx, dword ptr [4D5708] ; edx = reg_eip
0042ED16 |. 3B55 D8 cmp edx, dword ptr [ebp-28]
0042ED19 |. 75 08 jnz short 0042ED23 ; 参数为exceptionaddr时跳转
0042ED1B |. 3B1D 0C574>cmp ebx, dword ptr [4D570C] ; 检查ecx = reg_ecx?
0042ED21 |. 74 16 je short 0042ED39 ; 参数为eip时跳转
对全局变量赋值:
0042ED23 |> 33C9 xor ecx, ecx
0042ED25 |. 8B45 D8 mov eax, dword ptr [ebp-28]
0042ED28 |. 890D 10574>mov dword ptr [4D5710], ecx
0042ED2E |. A3 08574D0>mov dword ptr [4D5708], eax ; reg_eip
0042ED33 |. 891D 0C574>mov dword ptr [4D570C], ebx ; reg_ecx
检查到底是什么异常,并做相应的跳转,我们主要处理的是内存断点,其他略过,即是这里的访问异常EXCEPTION_ACCESS_VIOLATION:
0042ED39 |> 8B55 A4 mov edx, dword ptr [ebp-5C]
0042ED3C |. 8B0A mov ecx, dword ptr [edx]
0042ED3E |. 81F9 8F000>cmp ecx, C000008F ; EXCEPTION_FLT_INEXACT_RESULT
0042ED44 |. 7F 69 jg short 0042EDAF
0042ED46 |. 0F84 3F1A0>je 0043078B
0042ED4C |. 81F9 1D000>cmp ecx, C000001D ; EXCEPTION_ILLEGAL_INSTRUCTION
0042ED52 |. 7F 33 jg short 0042ED87
0042ED54 |. 0F84 D01D0>je 00430B2A
0042ED5A |. 81E9 01000>sub ecx, 80000001 ; EXCEPTION_GUARD_PAGE
0042ED60 |. 0F84 1A180>je 00430580
0042ED66 |. 83E9 02 sub ecx, 2 ; EXCEPTION_BREAKPOINT
0042ED69 |. 0F84 95000>je 0042EE04
0042ED6F |. 49 dec ecx ; EXCEPTION_SINGLE_STEP
0042ED70 |. 0F84 F70E0>je 0042FC6D
0042ED76 |. 81E9 01000>sub ecx, 40000001 ; EXCEPTION_ACCESS_VIOLATION
0042ED7C |. 0F84 12120>je 0042FF94
0042ED82 |. E9 CD1E000>jmp 00430C54
下面有对上面提到的几个异常的处理,这里先略过。。。:
……
……
查找异常所在的模块,并得到其模块信息:
0042FF94 |> 8B45 D8 mov eax, dword ptr [ebp-28]
0042FF97 |. 50 push eax ; /Arg1
0042FF98 |. E8 7BDE020>call _Findmodule ; \_Findmodule
0042FF9D |. 59 pop ecx
0042FF9E |. 8945 AC mov dword ptr [ebp-54], eax ; 模块首地址赋值给一个局部变量
通过比较模块中的各种信息判断内存断点是否正常,若不正常跳转到错误处理处:
0042FFA1 |. 8B45 A4 mov eax, dword ptr [ebp-5C]
0042FFA4 |. 8B55 A4 mov edx, dword ptr [ebp-5C]
0042FFA7 |. 8378 10 02 cmp dword ptr [eax+10], 2 ; ExceptionFlags > 2 ?
0042FFAB |. 8B7A 18 mov edi, dword ptr [edx+18]
0042FFAE |. 0F82 65040>jb 00430419
0042FFB4 |. 833D 40814>cmp dword ptr [4D8140], 0 ; 内存断点的长度是否为0
0042FFBB |. 0F84 58040>je 00430419
0042FFC1 |. 833D 00574>cmp dword ptr [4D5700], 0
0042FFC8 |. 0F84 4B040>je 00430419
0042FFCE |. 3B3D 44814>cmp edi, dword ptr [4D8144] ;异常地址 < 断点内存页首地址?
0042FFD4 |. 0F82 3F040>jb 00430419
0042FFDA |. 3B3D 48814>cmp edi, dword ptr [4D8148] ;异常地址 > 断点内存页尾地址?
0042FFE0 |. 0F83 33040>jnb 00430419
读取异常部分的机器码10h字节,由于OpCode不会超过16个字节,所以一定够用了:
0042FFE6 |. 830D 74574>or dword ptr [4D5774], 20
0042FFED |. 8D95 98FDF>lea edx, dword ptr [ebp-268]
0042FFF3 |. 52 push edx ; /Arg2
0042FFF4 |. 830D 10574>or dword ptr [4D5710], 2 ; |
0042FFFB |. 8B4D D8 mov ecx, dword ptr [ebp-28] ; |
0042FFFE |. 51 push ecx ; |Arg1
0042FFFF |. E8 8016030>call _Readcommand ; \_Readcommand
00430004 |. 83C4 08 add esp, 8
检查读取的机器码长度,若为小于等于0则跳转到错误处理:
00430007 |. 8945 C8 mov dword ptr [ebp-38], eax
0043000A |. 837D C8 00 cmp dword ptr [ebp-38], 0
0043000E |. 76 28 jbe short 00430038
将内存异常的机器码反汇编,并将汇编代码的机器码长度给一个局部变量:
00430010 |. 56 push esi ; /Arg7 threadid
00430011 |. 6A 05 push 5 ; |Arg6 = 00000005 DISASM_ALL
00430013 |. 8D85 80E5F>lea eax, dword ptr [ebp-1A80] ; |
00430019 |. 50 push eax ; |Arg5 pt_Disasm结构体
0043001A |. 6A 00 push 0 ; |Arg4 = 00000000
0043001C |. 8B55 D8 mov edx, dword ptr [ebp-28] ; |
0043001F |. 52 push edx ; |Arg3 addr of command
00430020 |. 8B4D C8 mov ecx, dword ptr [ebp-38] ; |
00430023 |. 51 push ecx ; |Arg2
00430024 |. 8D85 98FDF>lea eax, dword ptr [ebp-268] ; |
0043002A |. 50 push eax ; |Arg1
0043002B |. E8 185FFEF>call _Disasm ; \_Disasm
00430030 |. 83C4 1C add esp, 1C
00430033 |. 8945 F4 mov dword ptr [ebp-C], eax ; 将长度给局部变量
00430036 |. EB 05 jmp short 0043003D ;跳过错误处理
读取机器码失败的错误处理,设置读取长度为0:
00430038 |> 33D2 xor edx, edx
0043003A |. 8955 F4 mov dword ptr [ebp-C], edx
检查读取长度,若小于等于0,则跳转到错误处理:
0043003D |> 837D F4 00 cmp dword ptr [ebp-C], 0
00430041 |. 0F8E 9A010>jle 004301E1
将异常地址加上其汇编代码长度,比较其地址是否低于等于异常地址,若是则跳到异常处理:
00430047 |. 8B4D D8 mov ecx, dword ptr [ebp-28]
0043004A |. 034D F4 add ecx, dword ptr [ebp-C]
0043004D |. 3B0D 3C814>cmp ecx, dword ptr [4D813C] ; Ollydbg.0040100C
00430053 |. 0F86 88010>jbe 004301E1
将内存断点地址加断点范围,比较其地址是否小于等于异常地址,若是则跳到异常处理:
00430059 |. A1 3C814D0>mov eax, dword ptr [4D813C]
0043005E |. 0305 40814>add eax, dword ptr [4D8140]
00430064 |. 3B45 D8 cmp eax, dword ptr [ebp-28]
00430067 |. 0F86 74010>jbe 004301E1
继续检查标志,并跳转到相应的处理函数处:
0043006D |. 833D 38814>cmp dword ptr [4D8138], 0
00430074 |. 0F84 43010>je 004301BD
0043007A |. 833D 688D4>cmp dword ptr [4D8D68], 0
00430081 |. 74 78 je short 004300FB
检查模块信息是否存在,并检查模块信息中的值是否正确,若入口在代码段的外面则要求:
00430083 |. 837D AC 00 cmp dword ptr [ebp-54], 0 ; 检查模块信息是否存在
00430087 |. 74 72 je short 004300FB
00430089 |. 8B55 AC mov edx, dword ptr [ebp-54] ; [ebp-54]为模块信息结构体首地址
0043008C |. 8B45 AC mov eax, dword ptr [ebp-54]
0043008F |. 8B8A E1030>mov ecx, dword ptr [edx+3E1]
00430095 |. 3B48 0C cmp ecx, dword ptr [eax+C] ; 入口点是否在代码段前面
00430098 |. 72 61 jb short 004300FB
0043009A |. 8B55 AC mov edx, dword ptr [ebp-54]
0043009D |. 8B45 AC mov eax, dword ptr [ebp-54]
004300A0 |. 8B4A 0C mov ecx, dword ptr [edx+C]
004300A3 |. 8B55 AC mov edx, dword ptr [ebp-54]
004300A6 |. 0388 E9030>add ecx, dword ptr [eax+3E9]
004300AC |. 3B8A E1030>cmp ecx, dword ptr [edx+3E1] ; 入口点是否在代码段后面
004300B2 |. 76 47 jbe short 004300FB
004300B4 |. 8B4D AC mov ecx, dword ptr [ebp-54]
004300B7 |. 8B81 E1030>mov eax, dword ptr [ecx+3E1]
004300BD |. 3B45 D8 cmp eax, dword ptr [ebp-28] ;入口点与内存断点地址是否相同
004300C0 |. 74 0A je short 004300CC
004300C2 |. B8 0200000>mov eax, 2 ; 返回2
004300C7 |. E9 5913000>jmp 00431425 ; 跳转到结束处
设置OD的CPU显示信息,以及相关的提示信息,跳过错误处理:
004300CC |> 68 0D80000>push 800D ; /Arg5 = 0000800D
004300D1 |. 6A 00 push 0 ; |Arg4 = 00000000
004300D3 |. 6A 00 push 0 ; |Arg3 = 00000000
004300D5 |. 8B55 D8 mov edx, dword ptr [ebp-28] ; |
004300D8 |. 52 push edx ; |Arg2
004300D9 |. 6A 00 push 0 ; |Arg1 = 00000000
004300DB |. E8 38D5FFF>call _Setcpu ; \_Setcpu
004300E0 |. 83C4 14 add esp, 14
004300E3 |. E8 E4E4FEF>call _Redrawdisassembler
004300E8 |. 68 F7614B0>push 004B61F7 ; /自解压(sfx)代码理论上的入口点
004300ED |. 8B4D D8 mov ecx, dword ptr [ebp-28] ; |
004300F0 |. 51 push ecx ; |Arg1
004300F1 |. E8 0AE0FFF>call 0042E100 ; \SetInfoMsg
004300F6 |. 83C4 08 add esp, 8
004300F9 |. EB 34 jmp short 0043012F
错误处理,检查一些参数,返回2并退出:
004300FB |> 8B9D 84EBF>mov ebx, dword ptr [ebp-147C]
00430101 |. 81E3 F0000>and ebx, 0F0
00430107 |. 81FB 80000>cmp ebx, 80
0043010D |. 74 05 je short 00430114
0043010F |. 83FB 50 cmp ebx, 50
00430112 |. 75 0A jnz short 0043011E
00430114 |> B8 0200000>mov eax, 2 ; 返回2
00430119 |. E9 0713000>jmp 00431425 ; 跳转到结束处
设置提示信息,并根据清除内存断点表的信息,最后检查是否清除成功,否则跳转到错误处理:
0043011E |> 68 17624B0>push 004B6217 ; /自解压(sfx)代码可能的入口点
00430123 |. 8B55 D8 mov edx, dword ptr [ebp-28] ; |
00430126 |. 52 push edx ; |Arg1
00430127 |. E8 D4DFFFF>call 0042E100 ; \ SetInfoMsg
0043012C |. 83C4 08 add esp, 8
0043012F |> 6A 00 push 0 ; /Arg3 = 00000000
00430131 |. 6A 00 push 0 ; |Arg2 = 00000000
00430133 |. 6A 00 push 0 ; |Arg1 = 00000000
00430135 |. E8 9E91FEF>call _Setmembreakpoint ; \_Setmembreakpoint
0043013A |. 83C4 0C add esp, 0C
0043013D |. 837D AC 00 cmp dword ptr [ebp-54], 0
00430141 |. 74 71 je short 004301B4
写UDD文件,判断模块信息结构体中的SFX代码的入口点是否存在,若不存在则将内存断点的首地址赋值给他:
00430143 |. 8B4D AC mov ecx, dword ptr [ebp-54]
00430146 |. 8B01 mov eax, dword ptr [ecx]
00430148 |. 3B05 64734>cmp eax, dword ptr [4D7364]
0043014E |. 75 64 jnz short 004301B4
00430150 |. 6A 00 push 0 ; /Arg4 = 00000000
00430152 |. 6A 00 push 0 ; |Arg3 = 00000000
00430154 |. 6A 00 push 0 ; |Arg2 = 00000000
00430156 |. 8B55 AC mov edx, dword ptr [ebp-54] ; |
00430159 |. 52 push edx ; |Arg1
0043015A |. E8 91DF020>call 0045E0F0 ; \ write_udd
0043015F |. 83C4 10 add esp, 10
00430162 |. 8B4D AC mov ecx, dword ptr [ebp-54]
00430165 |. 83B9 E1030>cmp dword ptr [ecx+3E1], 0
0043016C |. 74 09 je short 00430177
0043016E |. 833D 688D4>cmp dword ptr [4D8D68], 0
00430175 |. 75 0C jnz short 00430183
00430177 |> 8B45 AC mov eax, dword ptr [ebp-54]
0043017A |. 8B55 D8 mov edx, dword ptr [ebp-28]
0043017D |. 8990 E1030>mov dword ptr [eax+3E1], edx
检查模块的类型以及基地址,若错误则重新得到其模块信息,检查有没有得到模块信息,若没有得到则分析模块得到其信息:
00430183 |> 833D 0C924>cmp dword ptr [4D920C], 0
0043018A |. 74 28 je short 004301B4
0043018C |. 8B4D AC mov ecx, dword ptr [ebp-54]
0043018F |. F641 08 04 test byte ptr [ecx+8], 4
00430193 |. 74 1F je short 004301B4
00430195 |. 6A 00 push 0 ; /Arg2 = 00000000
00430197 |. 8B45 AC mov eax, dword ptr [ebp-54] ; |
0043019A |. 8B50 0C mov edx, dword ptr [eax+C] ; |
0043019D |. 52 push edx ; |Arg1
0043019E |. E8 5DDD020>call _Finddecode ; \_Finddecode
004301A3 |. 83C4 08 add esp, 8
004301A6 |. 85C0 test eax, eax
004301A8 |. 75 0A jnz short 004301B4
004301AA |. 8B4D AC mov ecx, dword ptr [ebp-54]
004301AD |. 51 push ecx
004301AE |. E8 D1F0040>call _Analysecode
004301B3 |. 59 pop ecx
设置断点表的第一个变量为0,并跳转到下面调整优先级:
004301B4 |> 33C0 xor eax, eax
004301B6 |. A3 38814D0>mov dword ptr [4D8138], eax
004301BB |. EB 15 jmp short 004301D2
设置断点相关的信息,并调整优先级,最后返回0退出:
004301BD |> 8B55 D8 mov edx, dword ptr [ebp-28]
004301C0 |. 52 push edx ; /Arg3
004301C1 |. 68 38624B0>push 004B6238 ; |执行 [%08lx] 时设置内存断点
004301C6 |. 8B4D D8 mov ecx, dword ptr [ebp-28] ; |
004301C9 |. 51 push ecx ; |Arg1
004301CA |. E8 31DFFFF>call 0042E100 ; \Ollydbg.0042E100
004301CF |. 83C4 0C add esp, 0C
004301D2 |> 6A 00 push 0 ; /Arg1 = 00000000
004301D4 |. E8 FF18000>call _Animate ; \_Animate
004301D9 |. 59 pop ecx
004301DA |. 33C0 xor eax, eax ; 返回0
004301DC |. E9 4412000>jmp 00431425 ; 跳转到结束处
这里为读取机器码失败之后的判断部分,为一个循环体,初始化ebx值为0,跳转到下面的循环体判断处:
004301E1 |> 33DB xor ebx, ebx
004301E3 |. 8D85 CCEBF>lea eax, dword ptr [ebp-1434]
004301E9 |. E9 0C02000>jmp 004303FA
检查异常事件的信息是否正确:
004301EE |> 8338 00 /cmp dword ptr [eax], 0 eax : pDebugEvent
004301F1 |. 0F84 FF010>|je 004303F6 ; 跳转到循环体判断处
004301F7 |. F640 F4 20 |test byte ptr [eax-C], 20 ; 检查是否是内存断点异常
004301FB |. 0F85 F5010>|jnz 004303F6 ; 跳转到循环体判断处
00430201 |. 8B50 18 |mov edx, dword ptr [eax+18] ; 检查异常地址是否正确
00430204 |. 8B0D 3C814>|mov ecx, dword ptr [4D813C]
0043020A |. 030D 40814>|add ecx, dword ptr [4D8140]
00430210 |. 3BD1 |cmp edx, ecx
00430212 |. 0F83 DE010>|jnb 004303F6 ; 跳转到循环体判断处
00430218 |. 0310 |add edx, dword ptr [eax]
0043021A |. 3B15 3C814>|cmp edx, dword ptr [4D813C] ; Ollydbg.0040100C
00430220 |. 0F86 D0010>|jbe 004303F6 ; 跳转到循环体判断处
00430226 |. 833D 38814>|cmp dword ptr [4D8138], 0
0043022D |. 0F84 85010>|je 004303B8
00430233 |. 833D 50814>|cmp dword ptr [4D8150], 0 ; exception_addr_begin_page
0043023A |. 74 15 |je short 00430251
0043023C |. 8B50 18 |mov edx, dword ptr [eax+18] ; ExceptionAddress
0043023F |. 81E2 00F0F>|and edx, FFFFF000
00430245 |. 3B15 50814>|cmp edx, dword ptr [4D8150] ; 检查异常地址首内存页
0043024B |. 0F84 A5010>|je 004303F6
检查异常调试信息结构体以及异常地址是否正确:
00430251 |> 833D 54814>|cmp dword ptr [4D8154], 0 ; exception_addr_begin_page
00430258 |. 74 1E |je short 00430278
0043025A |. 8B4D A4 |mov ecx, dword ptr [ebp-5C] ; ExceptionInformation
0043025D |. 8379 14 00 |cmp dword ptr [ecx+14], 0
00430261 |. 75 15 |jnz short 00430278
00430263 |. 8B50 18 |mov edx, dword ptr [eax+18] ; ExceptionAddress
00430266 |. 81E2 00F0F>|and edx, FFFFF000
0043026C |. 3B15 54814>|cmp edx, dword ptr [4D8154] ; exception_addr_begin_page
00430272 |. 0F84 7E010>|je 004303F6
00430278 |> 8B4D A4 |mov ecx, dword ptr [ebp-5C]
0043027B |. 8379 14 00 |cmp dword ptr [ecx+14], 0 ; ExceptionInformation
0043027F |. 75 14 |jnz short 00430295
将异常地址的内存页首地址赋值给两个全局变量:
00430281 |. 8B40 18 |mov eax, dword ptr [eax+18] ; ExceptionAddress
00430284 |. 25 00F0FFF>|and eax, FFFFF000
00430289 |. A3 403B4E0>|mov dword ptr [4E3B40], eax
0043028E |. A3 54814D0>|mov dword ptr [4D8154], eax
00430293 |. EB 15 |jmp short 004302AA
00430295 |> 8B50 18 |mov edx, dword ptr [eax+18]
00430298 |. 81E2 00F0F>|and edx, FFFFF000
0043029E |. 8915 443B4>|mov dword ptr [4E3B44], edx
004302A4 |. 8915 50814>|mov dword ptr [4D8150], edx
比较几个全局变量中代表的异常内存页首地址是否一样,若不一样跳转到下面比较:
004302AA |> A1 403B4E0>|mov eax, dword ptr [4E3B40]
004302AF |. 3B05 483B4>|cmp eax, dword ptr [4E3B48]
004302B5 |. 75 12 |jnz short 004302C9
004302B7 |. 8B0D 443B4>|mov ecx, dword ptr [4E3B44]
004302BD |. 3B0D 4C3B4>|cmp ecx, dword ptr [4E3B4C]
004302C3 |. 0F84 8A000>|je 00430353
设置提示信息:
004302C9 |> 68 61624B0>|push 004B6261 ; /跟踪 sfx:
004302CE |. 8D85 98FDF>|lea eax, dword ptr [ebp-268] ; |
004302D4 |. 50 |push eax ; |Arg1
004302D5 |. E8 5269070>|call 004A6C2C ; \_sprintf
004302DA |. 83C4 08 |add esp, 8
004302DD |. 8945 F4 |mov dword ptr [ebp-C], eax
004302E0 |. 833D 54814>|cmp dword ptr [4D8154], 0
004302E7 |. 74 21 |je short 0043030A
004302E9 |. 8B15 403B4>|mov edx, dword ptr [4E3B40]
004302EF |. 8D8D 98FDF>|lea ecx, dword ptr [ebp-268]
004302F5 |. 52 |push edx ; /Arg3 => 00000000
004302F6 |. 68 6E624B0>|push 004B626E ; | read=%08x
004302FB |. 034D F4 |add ecx, dword ptr [ebp-C] ; |
004302FE |. 51 |push ecx ; |Arg1
004302FF |. E8 2869070>|call 004A6C2C ; \_sprintf
00430304 |. 83C4 0C |add esp, 0C
00430307 |. 0145 F4 |add dword ptr [ebp-C], eax
0043030A |> 833D 50814>|cmp dword ptr [4D8150], 0
00430311 |. 74 1D |je short 00430330
00430313 |. A1 443B4E0>|mov eax, dword ptr [4E3B44]
00430318 |. 8D95 98FDF>|lea edx, dword ptr [ebp-268]
0043031E |. 50 |push eax ; /Arg3 => 00000000
0043031F |. 68 79624B0>|push 004B6279 ; | write=%08x
00430324 |. 0355 F4 |add edx, dword ptr [ebp-C] ; |
00430327 |. 52 |push edx ; |Arg1
00430328 |. E8 FF68070>|call 004A6C2C ; \_sprintf
0043032D |. 83C4 0C |add esp, 0C
00430330 |> 8D8D 98FDF>|lea ecx, dword ptr [ebp-268]
00430336 |. 51 |push ecx ; /Arg1
00430337 |. E8 2C14000>|call _Infoline ; \_Infoline
0043033C |. 59 |pop ecx
0043033D |. A1 403B4E0>|mov eax, dword ptr [4E3B40]
00430342 |. A3 483B4E0>|mov dword ptr [4E3B48], eax
00430347 |. 8B15 443B4>|mov edx, dword ptr [4E3B44]
0043034D |. 8915 4C3B4>|mov dword ptr [4E3B4C], edx
检查模块信息结构体是否正确:
00430353 |> 833D 648D4>|cmp dword ptr [4D8D64], 2
0043035A |. 74 43 |je short 0043039F
0043035C |. 833D 648D4>|cmp dword ptr [4D8D64], 1
00430363 |. 75 49 |jnz short 004303AE
00430365 |. 833D 688D4>|cmp dword ptr [4D8D68], 0
0043036C |. 74 40 |je short 004303AE
0043036E |. 837D AC 00 |cmp dword ptr [ebp-54], 0
00430372 |. 74 3A |je short 004303AE
00430374 |. 8B4D AC |mov ecx, dword ptr [ebp-54]
00430377 |. 8B55 AC |mov edx, dword ptr [ebp-54]
0043037A |. 8B81 E1030>|mov eax, dword ptr [ecx+3E1]
00430380 |. 3B42 0C |cmp eax, dword ptr [edx+C] ; 检查入口点是否在模块首前面
00430383 |. 72 29 |jb short 004303AE
00430385 |. 8B4D AC |mov ecx, dword ptr [ebp-54]
00430388 |. 8B55 AC |mov edx, dword ptr [ebp-54]
0043038B |. 8B41 0C |mov eax, dword ptr [ecx+C]
0043038E |. 8B4D AC |mov ecx, dword ptr [ebp-54]
00430391 |. 0382 E9030>|add eax, dword ptr [edx+3E9]
00430397 |. 3B81 E1030>|cmp eax, dword ptr [ecx+3E1] ; 检查入口点是否在模块尾的后面
0043039D |. 76 0F |jbe short 004303AE
将临时变量置空:
0043039F |> 33C0 |xor eax, eax
004303A1 |. 33D2 |xor edx, edx
004303A3 |. A3 54814D0>|mov dword ptr [4D8154], eax
004303A8 |. 8915 50814>|mov dword ptr [4D8150], edx
错误处理的部分:
004303AE |> B8 0200000>|mov eax, 2 ; 返回2
004303B3 |. E9 6D10000>|jmp 00431425 ; 跳转到结束处
设置内存断点的提示信息:
004303B8 |> 8B55 A4 |mov edx, dword ptr [ebp-5C]
004303BB |. 837A 14 00 |cmp dword ptr [edx+14], 0
004303BF |. 75 14 |jnz short 004303D5
004303C1 |. 57 |push edi ; /Arg3
004303C2 |. 68 85624B0>|push 004B6285 ; |读取 [%08lx] 时设置内存断点
004303C7 |. 8B4D D8 |mov ecx, dword ptr [ebp-28] ; |
004303CA |. 51 |push ecx ; |Arg1
004303CB |. E8 30DDFFF>|call 0042E100 ; \SetInfoMsg
004303D0 |. 83C4 0C |add esp, 0C
004303D3 |. EB 12 |jmp short 004303E7
004303D5 |> 57 |push edi ; /Arg3
004303D6 |. 68 AC624B0>|push 004B62AC ; |写到 [%08lx] 时设置内存断点
004303DB |. 8B45 D8 |mov eax, dword ptr [ebp-28] ; |
004303DE |. 50 |push eax ; |Arg1
004303DF |. E8 1CDDFFF>|call 0042E100 ; \ SetInfoMsg
004303E4 |. 83C4 0C |add esp, 0C
调整优先级:
004303E7 |> 6A 00 |push 0 ; /Arg1 = 00000000
004303E9 |. E8 EA16000>|call _Animate ; \_Animate
004303EE |. 59 |pop ecx
004303EF |. 33C0 |xor eax, eax ; 返回0
004303F1 |. E9 2F10000>|jmp 00431425 ; 跳转到结束处
循环体判断条件以及自加部分,小于三的时候继续比较:
004303F6 |> 43 |inc ebx
004303F7 |. 83C0 04 |add eax, 4
004303FA |> 83FB 03 cmp ebx, 3
004303FD |. 7D 0A |jge short 00430409
检查读取机器码的长度,如果大于0则继续跳转到上面判断,否则就结束程序,返回2:
004303FF |. 837D F4 00 |cmp dword ptr [ebp-C], 0
00430403 |.^ 0F8F E5FDF>\jg 004301EE
设置错误返回值,并退出
00430409 |> FF05 303B4>inc dword ptr [4E3B30]
0043040F |. B8 0200000>mov eax, 2 ; 设置返回值为2
00430414 |. E9 0C10000>jmp 00431425 ; 跳转到结束处
设置错误信息到全局变量,返回2并退出:
00430419 |> 833D 5C8D4>cmp dword ptr [4D8D5C], 0
00430420 |. 74 19 je short 0043043B
00430422 |. 830D 74574>or dword ptr [4D5774], 20
00430429 |. 33D2 xor edx, edx
0043042B |. 8915 5C8D4>mov dword ptr [4D8D5C], edx
00430431 |. B8 0200000>mov eax, 2 ; 返回2
00430436 |. E9 EA0F000>jmp 00431425 ; 跳转到结束处
检查内存断点是否在kernel32模块中,若是则弹出错误提示窗口:
0043043B |> 810D 74574>or dword ptr [4D5774], 204
00430445 |. 833D A0574>cmp dword ptr [4D57A0], 0
0043044C |. 74 52 je short 004304A0
0043044E |. 8B55 D8 mov edx, dword ptr [ebp-28]
00430451 |. 52 push edx ; /Arg1
00430452 |. E8 C1D9020>call _Findmodule ; \_Findmodule
00430457 |. 59 pop ecx
00430458 |. 8945 AC mov dword ptr [ebp-54], eax
0043045B |. 837D AC 00 cmp dword ptr [ebp-54], 0
0043045F |. 74 3F je short 004304A0
00430461 |. 6A 08 push 8 ; /Arg3 = 00000008
00430463 |. 68 D6624B0>push 004B62D6 ; |kernel32
00430468 |. 8B4D AC mov ecx, dword ptr [ebp-54] ; |
0043046B |. 83C1 48 add ecx, 48 ; |
0043046E |. 51 push ecx ; |Arg1
0043046F |. E8 E034070>call 004A3954 ; \Ollydbg.004A3954
00430474 |. 83C4 0C add esp, 0C
00430477 |. 85C0 test eax, eax
00430479 |. 75 25 jnz short 004304A0
0043047B |. 68 DF624B0>push 004B62DF ; /访问违反在 kernel32 中,根据请求已忽略
00430480 |. 8B45 D8 mov eax, dword ptr [ebp-28] ; |
00430483 |. 50 push eax ; |Arg1
00430484 |. E8 A711000>call _Message ; \_Message
00430489 |. 83C4 08 add esp, 8
0043048C |. C705 FC564>mov dword ptr [4D56FC], 2
00430496 |. B8 0100000>mov eax, 1 ; 返回1
0043049B |. E9 850F000>jmp 00431425 ; 跳到程序结束处
根据上面设置的变量,设置相关的错误信息以及弹出窗口:
004304A0 |> 8B55 A4 mov edx, dword ptr [ebp-5C]
004304A3 |. 837A 10 02 cmp dword ptr [edx+10], 2
004304A7 |. 72 3E jb short 004304E7
004304A9 |. 68 C6614B0>push 004B61C6 ; $使用“shift+f7/f8/f9”键跳过异常以继续执行程序
004304AE |. 57 push edi
004304AF |. 8B4D A4 mov ecx, dword ptr [ebp-5C]
004304B2 |. 8379 14 01 cmp dword ptr [ecx+14], 1
004304B6 |. 75 07 jnz short 004304BF
004304B8 |. B8 32634B0>mov eax, 004B6332 ; 写入到
004304BD |. EB 11 jmp short 004304D0
004304BF |> 3B7D D8 cmp edi, dword ptr [ebp-28]
004304C2 |. 75 07 jnz short 004304CB
004304C4 |. B8 3D634B0>mov eax, 004B633D ; 正在执行
004304C9 |. EB 05 jmp short 004304D0
设置错误提示:
004304CB |> B8 47634B0>mov eax, 004B6347 ; 读取
004304D0 |> 50 push eax ; |Arg3
004304D1 |. 68 0F634B0>push 004B630F ; |访问违反: %s [%08lx]%s
004304D6 |. 8D95 98FDF>lea edx, dword ptr [ebp-268] ; |
004304DC |. 52 push edx ; |Arg1
004304DD |. E8 4A67070>call 004A6C2C ; \_sprintf
004304E2 |. 83C4 14 add esp, 14
004304E5 |. EB 19 jmp short 00430500
设置错误提示:
004304E7 |> 68 C6614B0>push 004B61C6 ; /Arg3 = 004B61C6
004304EC |. 68 4F634B0>push 004B634F ; |Arg2 = 004B634F
004304F1 |. 8D8D 98FDF>lea ecx, dword ptr [ebp-268] ; |
004304F7 |. 51 push ecx ; |Arg1
004304F8 |. E8 2F67070>call 004A6C2C ; \_sprintf
004304FD |. 83C4 0C add esp, 0C
在OD的子窗口中设置各类错误信息:
00430500 |> 8D85 98FDF>lea eax, dword ptr [ebp-268]
00430506 |. 50 push eax ; /Arg2
00430507 |. 8B55 D8 mov edx, dword ptr [ebp-28] ; |
0043050A |. 52 push edx ; |Arg1
0043050B |. E8 F0DBFFF>call 0042E100 ; \SetInfoMsg
00430510 |. 83C4 08 add esp, 8
检查一些全局变量,并做相应的处理:
00430513 |. C705 84574>mov dword ptr [4D5784], C0000005
0043051D |. 833D AC574>cmp dword ptr [4D57AC], 0
00430524 |. 75 16 jnz short 0043053C
00430526 |. 833D 38814>cmp dword ptr [4D8138], 0
0043052D |. 74 09 je short 00430538
0043052F |. 833D 6C8D4>cmp dword ptr [4D8D6C], 0
00430536 |. 75 04 jnz short 0043053C
00430538 |> 33C9 xor ecx, ecx
0043053A |. EB 05 jmp short 00430541
0043053C |> B9 0100000>mov ecx, 1
00430541 |> 51 push ecx ; /Arg2
00430542 |. 68 050000C>push C0000005 ; |Arg1 = C0000005
00430547 |. E8 2CE6FFF>call 0042EB78 ; \Ollydbg.0042EB78
0043054C |. 83C4 08 add esp, 8
0043054F |. 85C0 test eax, eax
00430551 |. 74 14 je short 00430567
00430553 |. C705 FC564>mov dword ptr [4D56FC], 3
0043055D |. B8 0200000>mov eax, 2 ; 返回2
00430562 |. E9 BE0E000>jmp 00431425 ; 跳转到结束处
调整优先级:
00430567 |> C705 FC564>mov dword ptr [4D56FC], 2
00430571 |. 6A 00 push 0 ; /Arg1 = 00000000
00430573 |. E8 6015000>call _Animate ; \_Animate
00430578 |. 59 pop ecx
00430579 |. 33C0 xor eax, eax ; 返回0
0043057B |. E9 A50E000>jmp 00431425 ; 跳转到结束处
下面是对其他异常的处理,这里忽略:
……
……
最后恢复现场并退出:
00431425 |> 5F pop edi
00431426 |. 5E pop esi
00431427 |. 5B pop ebx
00431428 |. 8BE5 mov esp, ebp
0043142A |. 5D pop ebp
0043142B \. C3 retn
武汉科锐学员: angelqkm
2008-5-21
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!