这是本系列文档的第七篇,因本人水平有限,不足和疏漏之处请各位批评指正,谢谢。
文件加载调试原理主要是使用CreateProcess函数,以调试方式加载文件进程,在加载的过程中对被加载程序的有效性进行检验,然后通过查询PE头结构,得到其OEP,并通过单步方式在OEP处下Int3断点,这样OD打开的程序就停在OEP,进而可以让调试人员在入口处开始调试程序。
在文件加载时,调用了OpenExeFile这个函数,得到打开文件的相关信息,并判断其是否为有效的PE文件;然后再根据得到的信息通过上述方法停在入口。由于比较仓促,只分析了前一部分函数的代码,其主要流程如下:
1. 判断打开的是否为快捷方式,若为快捷方式则通过相关函数找到对应的可执行程序;
2. 调用SearchPath查找是否有该文件,然后调用文件操作相关的库函数,打开文件,进行相关的判断;
3. 关于其是否为有效的PE文件的判断有几个方面:
a) 是否有MZ头;
b) 是否有PE头;
c) NT头中的Machine字段是否为14Ch;
d) NT头中的Characteristics是否为可执行;
e) NT头中的SizeOfOptionalHeader是否为0E0h。
等等,最后还根据判断的标识做了相应的处理;
4. 设置加载文件为DLL标识;
5. 检查是否还有活动的调试线程,将其暂停,并将那些线程有关的调试信息全部清除,检查是否清除成功,若失败则返回-1并退出;
6. 判断打开的是否为Dll文件,如果不是则跳过检查文件LoadDll.exe是否存在;
7. 调用函数0040F40C判断与OD同一目录下是否存在LoadDll.exe,若不存在,则从OD可执行程序中解压资源RES_LOADDLL,生成LoadDll.exe程序,若生成失败则报错,返回-1并退出;
8. 通过全文件路径名,得到其所在的文件夹,检查该调试程序的相关配置文件common.arg,若存在则加载处理;
9. 处理Ini文件
10. 检查加载的是DLL还是EXE,根据加载的不同生成不同的命令行参数:
a) 如果加载的是DLL,组合出命令行:"\Path\LoadDll.exe" \Path\XXX.dll传递给下面的CreateProcess函数;
b) 如果加载的是EXE,将EXE文件名传给下面的CreateProcess函数;
c) ……还有EXE情况未知;
11. 使用CreateProcessA创建调试进程,其中,CreationFlags = DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS | CREATE_DEFAULT_ERROR_MODE,检查是否打开成功,若失败则返回-1并退出;
12. 将CreateProcess中获得的PROCESS_INFORMATION结构体的值赋值给全局变量;
13. 设置OD的标题等界面的显示内容;
14. 读写配置文件,主要是操作一些最近打开的文件之类的配置值,然后退出。
这里为OpenExeFile函数的汇编代码,除了上述的流程,下面会对一些关键的地方做注释:
这部分检查打开的是否为快捷方式,如果不是快捷方式就跳过查找对应的可执行文件的路径部分:
0047731C >/$ 55 push ebp
0047731D |. 8BEC mov ebp, esp
0047731F |. 81C4 04F0FFF>add esp, -0FFC
00477325 |. 50 push eax
00477326 |. 81C4 D4F2FFF>add esp, -0D2C
0047732C |. 53 push ebx
0047732D |. 56 push esi
0047732E |. 57 push edi
0047732F |. 8B5D 08 mov ebx, dword ptr [ebp+8]
00477332 |. BE EC164C00 mov esi, 004C16EC ;ASCII "Table of DLL handles"
00477337 |. 33C0 xor eax, eax
00477339 |. 8945 F8 mov dword ptr [ebp-8], eax
0047733C |. 8D95 D8FAFFF>lea edx, dword ptr [ebp-528]
00477342 |. 52 push edx
00477343 |. 6A 00 push 0
00477345 |. 6A 00 push 0
00477347 |. 6A 00 push 0
00477349 |. 53 push ebx
0047734A |. E8 6DDE0200 call 004A51BC ;__fnsplit
0047734F |. 83C4 14 add esp, 14
00477352 |. 8D8E 0107000>lea ecx, dword ptr [esi+701]
00477358 |. 51 push ecx ; /Arg2
00477359 |. 8D85 D8FAFFF>lea eax, dword ptr [ebp-528] ; |
0047735F |. 50 push eax ; |Arg1
00477360 |. E8 57C50200 call 004A38BC ; \ _stricmp
00477365 |. 83C4 08 add esp, 8
00477368 |. 85C0 test eax, eax ;判断是否为快捷方式
0047736A |. 0F85 1501000>jnz 00477485 ;不是则跳过下面的查找部分
该部分通过加载COM库中的函数来查找快捷方式对应的可执行文件路径:
00477370 |. 6A 00 push 0 ;pvReserved
00477372 |. E8 A3820300 call <jmp.&OLE32.CoInitialize>
00477377 |. C685 D8FCFFF>mov byte ptr [ebp-328], 0
0047737E |. 8D55 E8 lea edx, dword ptr [ebp-18]
00477381 |. 52 push edx ;ppv
00477382 |. 68 20A84C00 push 004CA820 ; riid
00477387 |. 6A 01 push 1 ; dwClsContext
00477389 |. 6A 00 push 0 ; pUnkOuter
0047738B |. 68 30A84C00 push 004CA830 ; rclsid
00477390 |. E8 7F820300 call <jmp.&OLE32.CoCreateInstance>
00477395 |. 85C0 test eax, eax
00477397 |. 0F8C BC00000>jl 00477459
0047739D |. 8D4D E4 lea ecx, dword ptr [ebp-1C]
004773A0 |. 51 push ecx
004773A1 |. 68 40A84C00 push 004CA840
004773A6 |. 8B45 E8 mov eax, dword ptr [ebp-18]
004773A9 |. 50 push eax
004773AA |. 8B10 mov edx, dword ptr [eax]
004773AC |. FF12 call dword ptr [edx]
004773AE |. 85C0 test eax, eax
004773B0 |. 0F8C 9A00000>jl 00477450
004773B6 |. 68 04010000 push 104 ; /WideBufSize = 104 (260.)
004773BB |. 8D8D 48E5FFF>lea ecx, dword ptr [ebp-1AB8] ; |
004773C1 |. 51 push ecx ; |WideCharBuf
004773C2 |. 6A FF push -1 ; |StringSize = FFFFFFFF (-1.)
004773C4 |. 53 push ebx ; |StringToMap
004773C5 |. 6A 01 push 1 ; |Options = MB_PRECOMPOSED
004773C7 |. 6A 00 push 0 ; |CodePage = CP_ACP
004773C9 |. E8 887D0300 call <jmp.&KERNEL32.MultiByteToWid>; \MultiByteToWideChar
004773CE |. 6A 00 push 0
004773D0 |. 8D85 48E5FFF>lea eax, dword ptr [ebp-1AB8]
004773D6 |. 50 push eax
004773D7 |. 8B55 E4 mov edx, dword ptr [ebp-1C]
004773DA |. 52 push edx
004773DB |. 8B0A mov ecx, dword ptr [edx]
004773DD |. FF51 14 call dword ptr [ecx+14]
004773E0 |. 85C0 test eax, eax
004773E2 |. 7C 63 jl short 00477447
004773E4 |. 6A 00 push 0
004773E6 |. A1 7C3B4D00 mov eax, dword ptr [4D3B7C]
004773EB |. 50 push eax
004773EC |. 8B55 E8 mov edx, dword ptr [ebp-18]
004773EF |. 52 push edx
004773F0 |. 8B0A mov ecx, dword ptr [edx]
004773F2 |. FF51 4C call dword ptr [ecx+4C]
004773F5 |. 85C0 test eax, eax
004773F7 |. 7C 4E jl short 00477447
004773F9 |. 8D85 D4E2FFF>lea eax, dword ptr [ebp-1D2C]
004773FF |. 6A 00 push 0
00477401 |. 50 push eax
00477402 |. 8D95 D8FCFFF>lea edx, dword ptr [ebp-328]
00477408 |. 68 04010000 push 104
0047740D |. 52 push edx
0047740E |. 8B4D E8 mov ecx, dword ptr [ebp-18]
00477411 |. 51 push ecx
00477412 |. 8B01 mov eax, dword ptr [ecx]
00477414 |. FF50 0C call dword ptr [eax+C]
00477417 |. 85C0 test eax, eax
00477419 |. 7D 07 jge short 00477422
0047741B |. C685 D8FCFFF>mov byte ptr [ebp-328], 0
00477422 |> 68 00100000 push 1000
00477427 |. 68 885D4D00 push 004D5D88
0047742C |. 8B55 E8 mov edx, dword ptr [ebp-18]
0047742F |. 52 push edx
00477430 |. 8B0A mov ecx, dword ptr [edx]
00477432 |. FF51 28 call dword ptr [ecx+28]
00477435 |. 85C0 test eax, eax
00477437 |. 7C 07 jl short 00477440
00477439 |. 33C0 xor eax, eax
0047743B |. 8945 0C mov dword ptr [ebp+C], eax
0047743E |. EB 07 jmp short 00477447
00477440 |> C605 885D4D0>mov byte ptr [4D5D88], 0
00477447 |> 8B55 E4 mov edx, dword ptr [ebp-1C]
0047744A |. 52 push edx
0047744B |. 8B0A mov ecx, dword ptr [edx]
0047744D |. FF51 08 call dword ptr [ecx+8]
00477450 |> 8B45 E8 mov eax, dword ptr [ebp-18]
00477453 |. 50 push eax
00477454 |. 8B10 mov edx, dword ptr [eax]
00477456 |. FF52 08 call dword ptr [edx+8]
00477459 |> E8 C2810300 call <jmp.&OLE32.CoUninitialize>
检查是否完全释放com库,若释放失败则报错、返回-1并退出:
0047745E |. 80BD D8FCFFF>cmp byte ptr [ebp-328], 0
00477465 |. 75 18 jnz short 0047747F
00477467 |. 53 push ebx ; /Arg2
00477468 |. 8D8E 0607000>lea ecx, dword ptr [esi+706] ; |
0047746E |. 51 push ecx ; |Arg1
0047746F |. E8 A8CBFDFF call _Error ; \_Error
00477474 |. 83C4 08 add esp, 8
00477477 |. 83C8 FF or eax, FFFFFFFF ;返回-1
0047747A |. E9 08060000 jmp 00477A87 ;跳转到结束处
得到路径后用SearchPathA查找路径是否正确,路径不正确则报错、返回-1并退出:
0047747F |> 8D9D D8FCFFF>lea ebx, dword ptr [ebp-328]
00477485 |> 8D45 F0 lea eax, dword ptr [ebp-10]
00477488 |. 8D95 E0FEFFF>lea edx, dword ptr [ebp-120]
0047748E |. 50 push eax ; /ppFilePart
0047748F |. 52 push edx ; |ReturnBuffer
00477490 |. 8D8E 1704000>lea ecx, dword ptr [esi+417] ; |
00477496 |. 68 04010000 push 104 ; |BufSize = 104 (260.)
0047749B |. 51 push ecx ; |Extension
0047749C |. 53 push ebx ; |FileName
0047749D |. 6A 00 push 0 ; |Path = NULL
0047749F |. E8 DC7C0300 call <jmp.&KERNEL32.SearchPathA> ; \SearchPathA
004774A4 |. 85C0 test eax, eax
004774A6 |. 75 18 jnz short 004774C0
004774A8 |. 53 push ebx ; /Arg2
004774A9 |. 8D86 3F07000>lea eax, dword ptr [esi+73F] ; |
004774AF |. 50 push eax ; |Arg1
004774B0 |. E8 67CBFDFF call _Error ; \_Error
004774B5 |. 83C4 08 add esp, 8
004774B8 |. 83C8 FF or eax, FFFFFFFF ;返回-1
004774BB |. E9 C7050000 jmp 00477A87 ;t跳转到结束处
调用C库函数打开可执行文件,并检查打开是否成功,根据检查结果做相应处理:
004774C0 |> 8D96 5A07000>lea edx, dword ptr [esi+75A]
004774C6 |. 52 push edx ; /Arg2
004774C7 |. 8D8D E0FEFFF>lea ecx, dword ptr [ebp-120] ; |
004774CD |. 51 push ecx ; |Arg1
004774CE |. E8 A1DE0200 call 004A5374 ; \ _fopen
004774D3 |. 83C4 08 add esp, 8
004774D6 |. 8BF8 mov edi, eax
004774D8 |. 85FF test edi, edi ;检查是否打开成功
004774DA |. 75 07 jnz short 004774E3 ;打开成功则使ebx = 0
004774DC |. BB 01000000 mov ebx, 1 ;打开失败则使ebx = 1
004774E1 |. EB 02 jmp short 004774E5
004774E3 |> 33DB xor ebx, ebx
根据上面的打开情况做处理,如果打开失败则跳过读取IMAGE_DOS_HEADER部分代码:
004774E5 |> 85DB test ebx, ebx ;检查打开文件标识
004774E7 |. 75 1E jnz short 00477507 ;如果失败则跳过读取部分代码
检查读取IMAGE_DOS_HEADER是否成功,如果失败则使ebx = 1:
004774E9 |. 57 push edi ; /Arg4
004774EA |. 6A 40 push 40 ; |Arg3 = 00000040
004774EC |. 6A 01 push 1 ; |Arg2 = 00000001
004774EE |. 8D85 58FAFFF>lea eax, dword ptr [ebp-5A8] ; |文件头指针
004774F4 |. 50 push eax ; |Arg1
004774F5 |. E8 D6E00200 call 004A55D0 ; \ _fread
004774FA |. 83C4 10 add esp, 10
004774FD |. 83F8 40 cmp eax, 40 ;检查是否读取了40h的IMAGE_DOS_HEADER
00477500 |. 74 05 je short 00477507
00477502 |. BB 01000000 mov ebx, 1 ;读取失败ebx = 1
将文件头指针放入寄存器,继续检查读取标志ebx,读取失败则跳过检查DOS头的正确性:
00477507 |> 8D85 58FAFFF>lea eax, dword ptr [ebp-5A8]
0047750D |. 85DB test ebx, ebx ;检查读取标志ebx
0047750F |. 75 0C jnz short 0047751D ;读取失败则跳过检查DOS头的正确性
检查IMAGE_DOS_HEADER的正确性,并做相应的标识:
00477511 |. 66:8138 4D5A cmp word ptr [eax], 5A4D ;检查IMAGE_DOS_HEADER的正确性
00477516 |. 74 05 je short 0047751D
00477518 |. BB 02000000 mov ebx, 2 ;若IMAGE_DOS_HEADER不正确,设置ebx = 2
检查读取标识ebx,若读取失败则跳过文件移位:
0047751D |> 85DB test ebx, ebx
0047751F |. 75 18 jnz short 00477539
偏移文件指针到DOS头的3C处,偏移完后一样做检查,并做相应标识:
00477521 |. 6A 00 push 0 ; /Arg3 = 00000000
00477523 |. 8B40 3C mov eax, dword ptr [eax+3C] ; |
00477526 |. 50 push eax ; |Arg2
00477527 |. 57 push edi ; |Arg1
00477528 |. E8 33E10200 call 004A5660 ; \_fseek
0047752D |. 83C4 0C add esp, 0C
00477530 |. 85C0 test eax, eax
00477532 |. 74 05 je short 00477539
00477534 |. BB 01000000 mov ebx, 1 ;偏移失败ebx = 1
对标识做相应检查,标识非0则跳过对文件的处理:
00477539 |> 85DB test ebx, ebx
0047753B |. 75 1E jnz short 0047755B
读取IMAGE_NT_HEADERS的Signature和IMAGE_FILE_HEADER,并检查是否成功,做相应标识:
0047753D |. 57 push edi ; /Arg4
0047753E |. 6A 18 push 18 ; |Arg3 = 00000018
00477540 |. 6A 01 push 1 ; |Arg2 = 00000001
00477542 |. 8D85 58FAFFF>lea eax, dword ptr [ebp-5A8] ; |
00477548 |. 50 push eax ; |Arg1
00477549 |. E8 82E00200 call 004A55D0 ; \_fread
0047754E |. 83C4 10 add esp, 10
00477551 |. 83F8 18 cmp eax, 18
00477554 |. 74 05 je short 0047755B
00477556 |. BB 01000000 mov ebx, 1 ;失败则ebx = 1
对标识做相应检查,标识非0则跳过对文件的处理:
0047755B |> 85DB test ebx, ebx
0047755D |. 75 11 jnz short 00477570
检查NT头的正确性,并做相应的标识:
0047755F |. 81BD 58FAFFF>cmp dword ptr [ebp-5A8], 4550 ;NT头的Signature是否为4550h
00477569 |. 74 05 je short 00477570
0047756B |. BB 02000000 mov ebx, 2 ;不是则ebx = 2
00477570 |> 8D85 5CFAFFF>lea eax, dword ptr [ebp-5A4]
对标识做相应检查,标识非0则跳过对文件的处理:
00477576 |. 85DB test ebx, ebx
00477578 |. 8945 EC mov dword ptr [ebp-14], eax
0047757B |. 75 1D jnz short 0047759A
检查NT头中的几个参数是否正确,并做相应的标识:
0047757D |. 8B55 EC mov edx, dword ptr [ebp-14]
00477580 |. 66:813A 4C01 cmp word ptr [edx], 14C ;判断是否为14Ch - Intel 365 - CPU
00477585 |. 74 05 je short 0047758C
00477587 |. BB 02000000 mov ebx, 2
0047758C |> 8B45 EC mov eax, dword ptr [ebp-14]
0047758F |. F640 12 02 test byte ptr [eax+12], 2 ;NtHeader.Characteristics是否可执行
00477593 |. 75 05 jnz short 0047759A
00477595 |. BB 02000000 mov ebx, 2
0047759A |> 33C0 xor eax, eax
对标识做相应检查,标识非0则跳过对文件的处理:
0047759C |. 85DB test ebx, ebx
0047759E |. 8945 FC mov dword ptr [ebp-4], eax
004775A1 |. 75 54 jnz short 004775F7
检查NT头中NtHeader.SizeOfOptionalHeader是否等于E0h,即检查有无特殊的数据目录,如有则跳过读取数据目录部分代码:
004775A3 |. 8B55 EC mov edx, dword ptr [ebp-14]
004775A6 |. 66:817A 10 E>cmp word ptr [edx+10], 0E0
004775AC |. 75 49 jnz short 004775F7
读取数据目录,并检查结果:
004775AE |. 57 push edi ; /Arg4
004775AF |. 68 E0000000 push 0E0 ; |Arg3 = 000000E0
004775B4 |. 6A 01 push 1 ; |Arg2 = 00000001
004775B6 |. 8D8D 24E4FFF>lea ecx, dword ptr [ebp-1BDC] ; |
004775BC |. 51 push ecx ; |Arg1
004775BD |. E8 0EE00200 call 004A55D0 \_fread
004775C2 |. 83C4 10 add esp, 10
004775C5 |. 3D E0000000 cmp eax, 0E0
004775CA |. 75 2B jnz short 004775F7
检查NT头中相关信息,并做相应的标识:
004775CC |. 66:83BD 68E4>cmp word ptr [ebp-1B98], 3
004775D4 |. 75 07 jnz short 004775DD
004775D6 |. C745 FC 1000>mov dword ptr [ebp-4], 10
004775DD |> 81BD 44E4FFF>cmp dword ptr [ebp-1BBC], 1000
004775E7 |. 73 0E jnb short 004775F7
004775E9 |. 833D D8364D0>cmp dword ptr [4D36D8], 2 ;检查是否WinNT平台
004775F0 |. 74 05 je short 004775F7
004775F2 |. BB 03000000 mov ebx, 3
最后关闭文件:
004775F7 |> 85FF test edi, edi
004775F9 |. 74 07 je short 00477602
004775FB |. 57 push edi
004775FC |. E8 D7D80200 call _fclose
00477601 |. 59 pop ecx
这里根据上面的信息所做的标识ebx对文件做相应的处理:
ebx = 1时,弹出错误信息,返回-1并退出:
00477602 |> 83FB 01 cmp ebx, 1 ; Switch (cases 1..3)
00477605 |. 75 1E jnz short 00477625
00477607 |. 8D85 E0FEFFF>lea eax, dword ptr [ebp-120] ; Case 1 of switch 00477602
0047760D |. 50 push eax ; /Arg2
0047760E |. 8D96 5D07000>lea edx, dword ptr [esi+75D] ; |
00477614 |. 52 push edx ; |Arg1
00477615 |. E8 02CAFDFF call _Error ; \_Error
0047761A |. 83C4 08 add esp, 8
0047761D |. 83C8 FF or eax, FFFFFFFF ;返回-1
00477620 |. E9 62040000 jmp 00477A87 ;跳转到结束处
ebx = 2时,弹出选择对话框,根据选择做相应的处理:
00477625 |> 83FB 02 cmp ebx, 2
00477628 |. 75 4C jnz short 00477676
0047762A |. 8D95 E0FEFFF>lea edx, dword ptr [ebp-120] ; Case 2 of switch 00477602
00477630 |. 52 push edx ; /Arg3
00477631 |. 8D8E 7E07000>lea ecx, dword ptr [esi+77E] ; |
00477637 |. 51 push ecx ; |Arg2
00477638 |. 8D85 54F8FFF>lea eax, dword ptr [ebp-7AC] ; |
0047763E |. 50 push eax ; |Arg1
0047763F |. E8 E8F50200 call 004A6C2C ; \_sprintf
00477644 |. 83C4 0C add esp, 0C
00477647 |. 8D96 CD07000>lea edx, dword ptr [esi+7CD]
0047764D |. 8D8D 54F8FFF>lea ecx, dword ptr [ebp-7AC]
00477653 |. A1 7C3B4D00 mov eax, dword ptr [4D3B7C]
00477658 |. 68 24210000 push 2124 ; /Style
0047765D |. 52 push edx ; |Title
0047765E |. 51 push ecx ; |Text
0047765F |. 50 push eax ; |hOwner
00477660 |. E8 B17E0300 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00477665 |. 83F8 06 cmp eax, 6 ;检查选择是否为IDYES
00477668 |. 0F84 B400000>je 00477722
0047766E |. 83C8 FF or eax, FFFFFFFF ;选择为IDNO时,返回-1
00477671 |. E9 11040000 jmp 00477A87 ;跳转到结束处
ebx = 3时,弹出选择对话框,根据选择做相应的处理:
00477676 |> 83FB 03 cmp ebx, 3
00477679 |. 75 48 jnz short 004776C3
0047767B |. 8D95 E0FEFFF>lea edx, dword ptr [ebp-120] ; Case 3 of switch 00477602
00477681 |. 52 push edx ; /Arg3
00477682 |. 8D8E E107000>lea ecx, dword ptr [esi+7E1] ; |
00477688 |. 51 push ecx ; |Arg2
00477689 |. 8D85 54F8FFF>lea eax, dword ptr [ebp-7AC] ; |
0047768F |. 50 push eax ; |Arg1
00477690 |. E8 97F50200 call 004A6C2C ; \_sprintf
00477695 |. 83C4 0C add esp, 0C
00477698 |. 8D96 2E08000>lea edx, dword ptr [esi+82E]
0047769E |. 8D8D 54F8FFF>lea ecx, dword ptr [ebp-7AC]
004776A4 |. A1 7C3B4D00 mov eax, dword ptr [4D3B7C]
004776A9 |. 68 24210000 push 2124 ; /Style
004776AE |. 52 push edx ; |Title
004776AF |. 51 push ecx ; |Text
004776B0 |. 50 push eax ; |hOwner
004776B1 |. E8 607E0300 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004776B6 |. 83F8 06 cmp eax, 6 ;检查选择是否为IDYES
004776B9 |. 74 67 je short 00477722
004776BB |. 83C8 FF or eax, FFFFFFFF ;选择为IDNO时,返回-1
004776BE |. E9 C4030000 jmp 00477A87 ;跳转到结束处
这里为默认处理处,弹出选择对话框,根据选择做相应的处理::
004776C3 |> 8B55 EC mov edx, dword ptr [ebp-14] ; Default
004776C6 |. F642 13 20 test byte ptr [edx+13], 20
004776CA |. 74 56 je short 00477722
004776CC |. 837D 0C FF cmp dword ptr [ebp+C], -1
004776D0 |. 74 49 je short 0047771B
004776D2 |. 8D8D E0FEFFF>lea ecx, dword ptr [ebp-120]
004776D8 |. 51 push ecx ; /Arg3
004776D9 |. 8D86 4108000>lea eax, dword ptr [esi+841] ; |
004776DF |. 50 push eax ; |Arg2
004776E0 |. 8D95 54F8FFF>lea edx, dword ptr [ebp-7AC] ; |
004776E6 |. 52 push edx ; |Arg1
004776E7 |. E8 40F50200 call 004A6C2C ; \_sprintf
004776EC |. 83C4 0C add esp, 0C
004776EF |. 8D8E 9F08000>lea ecx, dword ptr [esi+89F]
004776F5 |. 8D85 54F8FFF>lea eax, dword ptr [ebp-7AC]
004776FB |. 8B15 7C3B4D0>mov edx, dword ptr [4D3B7C]
00477701 |. 68 24200000 push 2024 ; /Style
00477706 |. 51 push ecx ; |Title
00477707 |. 50 push eax ; |Text
00477708 |. 52 push edx ; |hOwner
00477709 |. E8 087E0300 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
0047770E |. 83F8 06 cmp eax, 6 ;检查选择是否为IDYES
00477711 |. 74 08 je short 0047771B
00477713 |. 83C8 FF or eax, FFFFFFFF ;选择为IDNO时,返回-1
00477716 |. E9 6C030000 jmp 00477A87 ;跳转到结束处
设置加载文件为DLL标识:
0047771B |> C745 F8 0100>mov dword ptr [ebp-8], 1
检查是否还有进程被加载调试,将其关闭,并检查返回值,失败则返回-1并退出:
00477722 |> 6A 01 push 1 ; /Arg1 = 00000001
00477724 |. E8 7BE1FFFF call 004758A4 ; \Ollydbg.004758A4
00477729 |. 59 pop ecx
0047772A |. 85C0 test eax, eax
0047772C |. 74 08 je short 00477736
0047772E |. 83C8 FF or eax, FFFFFFFF
00477731 |. E9 51030000 jmp 00477A87 ;跳转到结束处
清除原调试程序中的所有相关信息,检查返回值,成功则跳过错误处理:
00477736 |> E8 D1DCFFFF call 0047540C
0047773B |. 85C0 test eax, eax
0047773D |. 74 15 je short 00477754
报错、返回-1,并退出:
0047773F |. 8D96 B308000>lea edx, dword ptr [esi+8B3]
00477745 |. 52 push edx ; /Arg1
00477746 |. E8 D1C8FDFF call _Error ; \_Error
0047774B |. 59 pop ecx
0047774C |. 83C8 FF or eax, FFFFFFFF
0047774F |. E9 33030000 jmp 00477A87 ;跳转到结束处
判断打开的是否为Dll文件,如果不是则跳过检查文件是否存在:
00477754 |> 8B55 F8 mov edx, dword ptr [ebp-8] ;ebp-8 标识是否为dll文件
00477757 |. 33C9 xor ecx, ecx
00477759 |. 8915 A06E4D0>mov dword ptr [4D6EA0], edx ;设置全局变量4D6EA0,保存是否为dll文件,1为dll,0为非dll
0047775F |. 890D A46E4D0>mov dword ptr [4D6EA4], ecx
00477765 |. 833D A06E4D0>cmp dword ptr [4D6EA0], 0 ;检查是否为DLL文件
0047776C |. 74 1E je short 0047778C ;如果不是DLL文件则跳过检查LoadDll.exe是否存在
若不存在则报错,返回-1并退出:
0047776E |. E8 997CF9FF call 0040F40C ; 该函数判断与OD同一目录下是否存在LoadDll.exe,若不存在,则从OD可执行程序中解压资源RES_LOADDLL,生成LoadDll.exe程序
00477773 |. 85C0 test eax, eax
00477775 |. 7D 15 jge short 0047778C
00477777 |. 8D86 D408000>lea eax, dword ptr [esi+8D4]
0047777D |. 50 push eax ; /Arg1
0047777E |. E8 99C8FDFF call _Error ; \_Error
00477783 |. 59 pop ecx
00477784 |. 83C8 FF or eax, FFFFFFFF ;返回-1
00477787 |. E9 FB020000 jmp 00477A87 ;跳转到结束处
通过全文件路径名,得到其所在的文件夹,检查该调试程序的相关配置文件:
0047778C |> 33C0 xor eax, eax
0047778E |. 56 push esi
0047778F |. 8DBD E0FEFFF>lea edi, dword ptr [ebp-120]
00477795 |. 83C9 FF or ecx, FFFFFFFF
00477798 |. F2:AE repne scas byte ptr es:[edi]
0047779A |. F7D1 not ecx
0047779C |. 2BF9 sub edi, ecx
0047779E |. BE 805B4D00 mov esi, 004D5B80 ; ASCII "D:\CrackMe.exe"
004777A3 |. 87F7 xchg edi, esi
004777A5 |. 8BD1 mov edx, ecx
004777A7 |. 8BC7 mov eax, edi
004777A9 |. C1E9 02 shr ecx, 2
004777AC |. 8D85 E0FEFFF>lea eax, dword ptr [ebp-120]
004777B2 |. F3:A5 rep movs dword ptr es:[edi], dwor>
004777B4 |. 8BCA mov ecx, edx
004777B6 |. 83E1 03 and ecx, 3
004777B9 |. F3:A4 rep movs byte ptr es:[edi], byte >
004777BB |. 5E pop esi
004777BC |. 6A 00 push 0
004777BE |. 68 7C5A4D00 push 004D5A7C ; ASCII "CrackMe"
004777C3 |. 6A 00 push 0
004777C5 |. 6A 00 push 0
004777C7 |. 50 push eax
004777C8 |. E8 EFD90200 call 004A51BC
004777CD |. 83C4 14 add esp, 14
004777D0 |. 6A 00 push 0 ; /Arg2 = 00000000
004777D2 |. 68 7C5A4D00 push 004D5A7C ; |Arg1 = 004D5A7C ASCII "CrackMe"
004777D7 |. E8 941BF9FF call 00409370 ; \判断与OD可执行程序同目录下是否存在common.arg文件,若有就加载处理
004777DC |. 83C4 08 add esp, 8
004777DF |. E8 743AFFFF call 0046B258 ; 读取OD的配置文件,获取导入库等信息
004777E4 |. 803D 845C4D0>cmp byte ptr [4D5C84], 0
004777EB |. 74 2C je short 00477819
004777ED |. 33C0 xor eax, eax
004777EF |. 56 push esi
004777F0 |. 83C9 FF or ecx, FFFFFFFF
004777F3 |. BF 845C4D00 mov edi, 004D5C84
004777F8 |. F2:AE repne scas byte ptr es:[edi]
004777FA |. F7D1 not ecx
004777FC |. 2BF9 sub edi, ecx
004777FE |. 8DB5 DCFDFFF>lea esi, dword ptr [ebp-224]
00477804 |. 87F7 xchg edi, esi
00477806 |. 8BD1 mov edx, ecx
00477808 |. 8BC7 mov eax, edi
0047780A |. C1E9 02 shr ecx, 2
0047780D |. F3:A5 rep movs dword ptr es:[edi], dwor>
0047780F |. 8BCA mov ecx, edx
00477811 |. 83E1 03 and ecx, 3
00477814 |. F3:A4 rep movs byte ptr es:[edi], byte >
00477816 |. 5E pop esi
00477817 |. EB 3C jmp short 00477855
将全路径名分解成驱动器名、路径名、文件名、后缀名:
00477819 |> 6A 00 push 0
0047781B |. 6A 00 push 0
0047781D |. 8D85 D8FBFFF>lea eax, dword ptr [ebp-428]
00477823 |. 50 push eax
00477824 |. 8D55 F5 lea edx, dword ptr [ebp-B]
00477827 |. 52 push edx
00477828 |. 8D8D E0FEFFF>lea ecx, dword ptr [ebp-120]
0047782E |. 51 push ecx
0047782F |. E8 88D90200 call 004A51BC ; _fnsplit
00477834 |. 83C4 14 add esp, 14
将拆分出来的文件名重新组合:
00477837 |. 8D85 D8FBFFF>lea eax, dword ptr [ebp-428]
0047783D |. 8D55 F5 lea edx, dword ptr [ebp-B]
00477840 |. 8D8D DCFDFFF>lea ecx, dword ptr [ebp-224]
00477846 |. 6A 00 push 0 ; / ext = 00000000
00477848 |. 6A 00 push 0 ; | name = 00000000
0047784A |. 50 push eax ; | dir
0047784B |. 52 push edx ; | drive
0047784C |. 51 push ecx ; | path
0047784D |. E8 46D90200 call 004A5198 ; \ _fnmerge
00477852 |. 83C4 14 add esp, 14
以下是STARTUPINFO类型的变量赋值:
00477855 |> C785 04E5FFF>mov dword ptr [ebp-1AFC], 44
0047785F |. 33C0 xor eax, eax
00477861 |. 33D2 xor edx, edx
00477863 |. 8985 08E5FFF>mov dword ptr [ebp-1AF8], eax
00477869 |. 33C9 xor ecx, ecx
0047786B |. 8995 0CE5FFF>mov dword ptr [ebp-1AF4], edx
00477871 |. 898D 10E5FFF>mov dword ptr [ebp-1AF0], ecx
00477877 |. C785 30E5FFF>mov dword ptr [ebp-1AD0], 81
00477881 |. 66:C785 34E5>mov word ptr [ebp-1ACC], 0A
0047788A |. 66:C785 36E5>mov word ptr [ebp-1ACA], 0
00477893 |. 33C0 xor eax, eax
00477895 |. 8985 38E5FFF>mov dword ptr [ebp-1AC8], eax
0047789B |. 837D 0C 01 cmp dword ptr [ebp+C], 1
0047789F |. 74 09 je short 004778AA
检查加载的是DLL还是EXE,根据加载的不同生成不同的命令行参数:
004778A1 |. 833D A06E4D0>cmp dword ptr [4D6EA0], 0
004778A8 |. 74 07 je short 004778B1
004778AA |> C605 885D4D0>mov byte ptr [4D5D88], 0
004778B1 |> 833D A06E4D0>cmp dword ptr [4D6EA0], 0
004778B8 |. 74 24 je short 004778DE
如果加载的是DLL,组合出命令行:"\Path\LoadDll.exe" \Path\XXX.dll传递给下面的CreateProcess函数:
004778BA |. 8D95 E0FEFFF>lea edx, dword ptr [ebp-120]
004778C0 |. 8D8E 5809000>lea ecx, dword ptr [esi+958]
004778C6 |. 52 push edx ; /Arg4
004778C7 |. 68 68384D00 push 004D3868 ; |Arg3
004778CC |. 51 push ecx ; |Arg2
004778CD |. 8D85 50E7FFF>lea eax, dword ptr [ebp-18B0] ; |
004778D3 |. 50 push eax ; |Arg1
004778D4 |. E8 53F30200 call 004A6C2C ; \_sprintf
004778D9 |. 83C4 10 add esp, 10
004778DC |. EB 4A jmp short 00477928
如果加载的是EXE,将EXE文件名传给下面的CreateProcess函数:
004778DE |> 803D 885D4D0>cmp byte ptr [4D5D88], 0
004778E5 |. 74 24 je short 0047790B
004778E7 |. 68 885D4D00 push 004D5D88 ; /Arg4 = 004D5D88
004778EC |. 8D95 E0FEFFF>lea edx, dword ptr [ebp-120] ; |
004778F2 |. 52 push edx ; |Arg3
004778F3 |. 8D8E 6C09000>lea ecx, dword ptr [esi+96C] ; |
004778F9 |. 51 push ecx ; |Arg2
004778FA |. 8D85 50E7FFF>lea eax, dword ptr [ebp-18B0] ; |
00477900 |. 50 push eax ; |Arg1
00477901 |. E8 26F30200 call 004A6C2C ; \_sprintf
00477906 |. 83C4 10 add esp, 10
00477909 |. EB 1D jmp short 00477928
0047790B |> 8D95 E0FEFFF>lea edx, dword ptr [ebp-120]
00477911 |. 52 push edx ; /Arg3
00477912 |. 8D8E C403000>lea ecx, dword ptr [esi+3C4] ; |
00477918 |. 51 push ecx ; |Arg2
00477919 |. 8D85 50E7FFF>lea eax, dword ptr [ebp-18B0] ; |
0047791F |. 50 push eax ; |Arg1
00477920 |. E8 07F30200 call 004A6C2C ; \_sprintf
00477925 |. 83C4 0C add esp, 0C
调用CreateProcessA这个函数打开调试线程,其中,CreationFlags = DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS | CREATE_DEFAULT_ERROR_MODE,检查是否打开成功,若失败则返回-1并退出:
00477928 |> 8D95 14E4FFF>lea edx, dword ptr [ebp-1BEC]
0047792E |. 8D8D 04E5FFF>lea ecx, dword ptr [ebp-1AFC]
00477934 |. 52 push edx ; /pProcessInfo
00477935 |. 51 push ecx ; |pStartupInfo
00477936 |. 8D85 DCFDFFF>lea eax, dword ptr [ebp-224] ; |
0047793C |. 8D8D 50E7FFF>lea ecx, dword ptr [ebp-18B0] ; |
00477942 |. 50 push eax ; |CurrentDir
00477943 |. 6A 00 push 0 ; |pEnvironment = NULL
00477945 |. 8B55 FC mov edx, dword ptr [ebp-4] ; |
00477948 |. 81CA 2200000>or edx, 4000022 ; |
0047794E |. 52 push edx ; |CreationFlags
0047794F |. 6A 00 push 0 ; |InheritHandles = FALSE
00477951 |. 6A 00 push 0 ; |pThreadSecurity = NULL
00477953 |. 6A 00 push 0 ; |pProcessSecurity = NULL
00477955 |. 51 push ecx ; |CommandLine
00477956 |. 6A 00 push 0 ; |ModuleFileName = NULL
00477958 |. E8 73760300 call <jmp.&KERNEL32.CreateProcessA>; \CreateProcessA
0047795D |. 85C0 test eax, eax ;检查返回值
0047795F |. 75 1E jnz short 0047797F ;成功则跳过错误处理
打开线程的错误处理部分,返回-1并退出:
00477961 |. 8D85 E0FEFFF>lea eax, dword ptr [ebp-120]
00477967 |. 50 push eax ; /Arg2
00477968 |. 8D96 7409000>lea edx, dword ptr [esi+974] ; |
0047796E |. 52 push edx ; |Arg1
0047796F |. E8 A8C6FDFF call _Error ; \_Error
00477974 |. 83C4 08 add esp, 8
00477977 |. 83C8 FF or eax, FFFFFFFF ;返回-1
0047797A |. E9 08010000 jmp 00477A87 ;跳转结束处
将CreateProcess中获得的PROCESS_INFORMATION的四个值赋值给全局变量:
0047797F |> 8B95 14E4FFF>mov edx, dword ptr [ebp-1BEC]
00477985 |. 8915 605A4D0>mov dword ptr [4D5A60], edx
0047798B |. 8B8D 18E4FFF>mov ecx, dword ptr [ebp-1BE8]
00477991 |. 890D 645A4D0>mov dword ptr [4D5A64], ecx
00477997 |. C705 685A4D0>mov dword ptr [4D5A68], 6
004779A1 |. C705 6C5A4D0>mov dword ptr [4D5A6C], 6
004779AB |. 8B85 1CE4FFF>mov eax, dword ptr [ebp-1BE4]
004779B1 |. A3 705A4D00 mov dword ptr [4D5A70], eax
004779B6 |. 8B95 20E4FFF>mov edx, dword ptr [ebp-1BE0]
004779BC |. 8915 745A4D0>mov dword ptr [4D5A74], edx
004779C2 |. 8B4D F0 mov ecx, dword ptr [ebp-10]
设置OD的标题显示内容:
004779C5 |. 51 push ecx ; /Arg4
004779C6 |. 8D86 A503000>lea eax, dword ptr [esi+3A5] ; |
004779CC |. 50 push eax ; |Arg3
004779CD |. 8D96 8E09000>lea edx, dword ptr [esi+98E] ; |
004779D3 |. 52 push edx ; |Arg2
004779D4 |. 8D8D E0FEFFF>lea ecx, dword ptr [ebp-120] ; |
004779DA |. 51 push ecx ; |Arg1
004779DB |. E8 4CF20200 call 004A6C2C ; \_sprintf
004779E0 |. 83C4 10 add esp, 10
004779E3 |. 8D85 E0FEFFF>lea eax, dword ptr [ebp-120]
004779E9 |. 50 push eax ; /Text
004779EA |. 8B15 7C3B4D0>mov edx, dword ptr [4D3B7C] ; |
004779F0 |. 52 push edx ; |hWnd
004779F1 |. E8 C87B0300 call <jmp.&USER32.SetWindowTextA> ; \SetWindowTextA
004779F6 |. C705 88574D0>mov dword ptr [4D5788], 1
下面是一些设置界面部分的代码:
00477A00 |. 33C9 xor ecx, ecx
00477A02 |. 890D 94574D0>mov dword ptr [4D5794], ecx
00477A08 |. 8D46 14 lea eax, dword ptr [esi+14]
00477A0B |. 50 push eax ; /Arg3
00477A0C |. 6A 00 push 0 ; |Arg2 = 00000000
00477A0E |. 6A 00 push 0 ; |Arg1 = 00000000
00477A10 |. E8 F72BFEFF call _Addtolist ; \_Addtolist
00477A15 |. 83C4 0C add esp, 0C
00477A18 |. 837D FC 00 cmp dword ptr [ebp-4], 0
00477A1C |. 74 18 je short 00477A36
00477A1E |. 68 805B4D00 push 004D5B80 ; /Arg3 = 004D5B80 ASCII "D:\CrackMe.exe"
00477A23 |. 8D96 9609000>lea edx, dword ptr [esi+996] ; |
00477A29 |. 52 push edx ; |Arg2
00477A2A |. 6A 00 push 0 ; |Arg1 = 00000000
00477A2C |. E8 FF9BFBFF call _Message ; \_Message
00477A31 |. 83C4 0C add esp, 0C
00477A34 |. EB 16 jmp short 00477A4C
00477A36 |> 68 805B4D00 push 004D5B80 ; /Arg3 = 004D5B80 ASCII "D:\CrackMe.exe"
00477A3B |. 8D8E A809000>lea ecx, dword ptr [esi+9A8] ; |
00477A41 |. 51 push ecx ; |Arg2
00477A42 |. 6A 00 push 0 ; |Arg1 = 00000000
00477A44 |. E8 E79BFBFF call _Message ; \_Message
00477A49 |. 83C4 0C add esp, 0C
00477A4C |> 803D 885D4D0>cmp byte ptr [4D5D88], 0
00477A53 |. 74 16 je short 00477A6B
00477A55 |. 68 885D4D00 push 004D5D88 ; /Arg3 = 004D5D88
00477A5A |. 8D86 B209000>lea eax, dword ptr [esi+9B2] ; |
00477A60 |. 50 push eax ; |Arg2
00477A61 |. 6A 00 push 0 ; |Arg1 = 00000000
00477A63 |. E8 C89BFBFF call _Message ; \_Message
00477A68 |. 83C4 0C add esp, 0C
读写配置文件,主要是操作一些最近打开的文件之类的配置值:
00477A6B |> 68 885D4D00 push 004D5D88 ; /Arg2 = 004D5D88
00477A70 |. 68 805B4D00 push 004D5B80 ; |Arg1 = 004D5B80 ASCII "D:\CrackMe.exe"
00477A75 |. E8 8AF3FFFF call 00476E04 ; \Ollydbg.00476E04
00477A7A |. 83C4 08 add esp, 8
00477A7D |. 6A 03 push 3 ; /Arg1 = 00000003
00477A7F |. E8 F49EFBFF call 00431978 ; \Ollydbg.00431978
00477A84 |. 59 pop ecx
返回0,恢复现场,并退出:
00477A85 |. 33C0 xor eax, eax
00477A87 |> 5F pop edi
00477A88 |. 5E pop esi
00477A89 |. 5B pop ebx
00477A8A |. 8BE5 mov esp, ebp
00477A8C |. 5D pop ebp
00477A8D \. C3 retn
OD打开被调试程序之后,进入调试循环体,在调试循环体中通过读取文件的OEP,在单步的方式下对OEP下Int3断点,断下程序后,恢复OEP处Int3断点为初始指令码。
这个流程可以在本系列前几个文档中得到验证,这里就不再加以说明了。
武汉科锐学员:driverox
2008-5-31
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!