16.5 加载调试程序
调试程序的第一步骤是使用OllyDBG对程序进行加载,加载过程是通过创建新进程来完成的。OllyDBG通过CreateProcess以调试方式开启新进程,调试程序的加载过程需要监视此API,找到调用处查看OllyDBG文件的加载流程,具体分析如代码清单16-13所示。
代码清单16-13 OllyDBG文件的加载流程—IDA分析
loc_477928:;地址标号,加载调试程序
00477928 lea edx,[ebp+ProcessInformation]
0047792E lea ecx,[ebp+StartupInfo]
00477934 push edx;lpProcessInformation
00477935 push ecx;lpStartupInfo
00477936 lea eax,[ebp+path]
0047793C lea ecx,[ebp+CommandLine]
00477942 push eax;lpCurrentDirectory
00477943 push 0;lpEnvironment
00477945 mov edx,[ebp+var_4]
00477948 or edx,4000022h
0047794E push edx;dwCreationFlags,控制级别
0047794F push 0;bInheritHandles
00477951 push 0;lpThreadAttributes
00477953 push 0;lpProcessAttributes
00477955 push ecx;lpCommandLine,调试进程路径
00477956 push 0;lpApplicationName
00477958 call CreateProcessA;开启调试进程
0047795D test eax, eax;检查创建结果
0047795F jnz short loc_47797F;成功跳转,开始调试程序
;错误代码分析略
代码清单16-13中创建了调试程序的新进程,在这之前OllyDBG还需要进行一些必要的检查工作,如调试进程路径的获取、是否为合法的调试文件等相关信息。这些准备工作都是由函数OpenEXEfile来完成的,此函数是调用CreateProcessA的函数。使用IDA分析OpenEXEfile函数在开启调试进程前都进行了哪些检查,如代码清单16-14所示。
代码清单16-14 OpenEXEfile分析片段1—IDA分析
;int__cdecl OpenEXEfile(LPCSTR arglist, int);函数原型
_OpenEXEfile proc near;函数入口
0047731C var_1D2C=byte ptr-1D2Ch
;局部变量、参数标号定义略
0047731C arg_4=dword ptr 0Ch
;部分代码分析略
00477342 push edx;保存后缀名
00477343 push 0
00477345 push 0
00477347 push 0
00477349 push ebx;加载程序全路径
0047734A call j___fnsplit;提取后缀名
0047734F add esp,14h
00477352 lea ecx,[esi+701h]
00477358 push ecx;保存字符串".lnk"
00477359 lea eax,[ebp+s1]
0047735F push eax;获取调试程序后缀名
00477360 call_stricmp
00477365 add esp,8
00477368 test eax, eax;检查是否为快捷方式
0047736A jnz loc_477485;不是快捷方式的后缀名则跳转
;通过快捷方式找到对应的可执行文件路径,其获取过程分析略
;路径检查部分分析略
loc_4774C0:;地址标号,打开调试文件
004774C0 lea edx,[esi+75Ah]
004774C6 push edx;文件打开标记"rb"
004774C7 lea ecx,[ebp+String]
004774CD push ecx;打开文件路径
004774CE call_fopen;打开文件
004774D3 add esp,8
004774D6 mov edi, eax
004774D8 test edi, edi;检查文件是否成功打开
004774DA jnz short loc_4774E3;若成功打开,则跳转
004774DC mov ebx,1
004774E1 jmp short loc_4774E5
loc_4774E3:;地址标号,打开文件成功处理
004774E3 xor ebx, ebx
loc_4774E5:;地址标号,读取打开文件
004774E5 test ebx, ebx
004774E7 jnz short loc_477507
004774E9 push edi;文件指针
004774EA push 40h;n
004774EC push 1;size
004774EE lea eax,[ebp+ptr]
004774F4 push eax;存放读取信息
004774F5 call_fread;读取文件
004774FA add esp,10h
004774FD cmp eax,40h;检查读取字节数是否为0x40
00477500 jz short loc_477507;若成功,则跳转,跳转到DOS头并进行检查
00477502 mov ebx,1
;DOS头检查首地址字符串是否为MZ,分析略
;根据DOS头中的记录,找到NT头结构再次检查,查看是否为合法的PE文件格式
;对NT头结构的检查分析略
loc_4775F7:;地址标号,关闭打开的文件
004775F7 test edi, edi
004775F9 jz short loc_477602
004775FB push edi;文件指针
004775FC call_fclose;关闭文件
00477601 pop ecx
根据代码清单16-14的分析,函数OpenEXEfile的第一部分检查工作是针对快捷方式的检查。OllyDBG根据路径中可执行程序的后缀名来判断分析程序是否为一个快捷方式,如果是快捷方式,则会找到这个快捷方式所对应的可执行程序的全路径。通过检查DOS头与NT头来判定分析文件是否为合法的PE文件。这只是一个简单的“通行证”检查过程,接下来将会进入更加严密的“安检”过程,如代码清单16-15所示。
代码清单16-15 OpenEXEfile分析片段2—IDA分析
loc_477625:;地址标号
00477625 cmp ebx,2;ebx中保存PE文件的类型
;相关检查分析略
loc_4776C3:;DLL文件处理
004776C3 mov edx,[ebp+var_14]
004776C6 test byte ptr[edx+13h],20h
004776CA jz short loc_477722
004776CC cmp[ebp+arg_4],0FFFFFFFFh
004776D0 jz short loc_47771B
004776D2 lea ecx,[ebp+String]
004776D8 push ecx
004776D9 lea eax,[esi+841h]
004776DF push eax;保存格式化信息
004776E0 lea edx,[ebp+buffer]
004776E6 push edx;保存字符串缓冲区
004776E7 call_sprintf;格式化字符串
004776EC add esp,0Ch
004776EF lea ecx,[esi+89Fh]
004776F5 lea eax,[ebp+buffer]
004776FB mov edx, hWnd
00477701 push 2024h;MB_OK|MB_ICONQUESTION|MB_TASKMODAL
00477706 push ecx;lpCaption
00477707 push eax;lpText
00477708 push edx;hWnd
00477709 call MessageBoxA
0047770E cmp eax,6;比较选择结果
;如果分析文件为DLL,进入DLL加载调试部分,利用LoadDll.exe加载DLL文件
00477711 jz short loc_47771B
00477713 or eax,0FFFFFFFFh
00477716 jmp loc_477A87
loc_47771B:;地址标号,LoadDll.exe加载部分
0047771B mov[ebp+var_8],1;设置加载文件为DLL标识
loc_477722:
00477722 push 1
00477724 call sub_4758A4;检查是否还有进程被加载调试,如果有将其关闭
00477729 pop ecx
0047772A test eax, eax;检查是否关闭成功
0047772C jz short loc_477736;关闭成功,执行跳转
0047772E or eax,0FFFFFFFFh
00477731 jmp loc_477A87;跳转到结束处
loc_477736:;地址标号
00477736 call ub_47540C;清除原调试程序中的所有相关信息
0047773B test eax, eax;检查结果
0047773D jz short loc_477754;成功跳转
;错误检查分析略
loc_477754:;地址标号
00477754 mov edx,[ebp+var_8];保存DLL文件标识符
00477757 xor ecx, ecx
00477759 mov dword_4D6EA0,edx;保存DLL文件标识符
0047775F mov dword_4D6EA4,ecx
00477765 cmp dword_4D6EA0,0;检查是否为DLL文件
0047776C jz short loc_47778C;若不是DLL文件,则跳过LoadDll.exe的检查
;判断OllyDBG是否与LoadDll在同一目录中,若不在,则释放一个LoadDll到目录下
0047776E call sub_40F40C
00477773 test eax, eax;检查结果
00477775 jge short loc_47778C;成功跳转
;通过完整的文件路径名来获取对应的文件夹,检查调试程序的相关配置文件
;相关检查结束后,便根据PE文件类型设置命令行信息,并加载调试程序,代码分析略
代码清单16-15展示了PE文件类型的处理过程,当调试文件为DLL动态库时,OllyDBG会使用自带的LoadDll.exe将DLL文件进行加载。当调试文件为exe可执行程序时,便会跳过DLL文件的处理部分,直接获取相关的配置文件信息并进行加载和调试。