实验操作手册
####请先下载实验文件
实验环境
操作机: Windows XP
实验工具:
Tools | Path |
---|---|
IDA Pro | C:\Tools\Ida61 |
OllyICE | C:\Tools\OllyICE |
PEiD | C:\Tools\PEid |
Spy++ | C:\Tools\spy++ |
实验文件:
Lab16-02.exe
请访问http://172.16.4.2/46c6f0b7
下载实验文件。
提示:
在本次实验中,请注意实验工具、实验文件存放路径,不同的文件路径可能会出现不一样的实验结果。
在实验环境中无法连接互联网,请使用您本地的网络环境。
这里我们结合实验问题来分析这次的恶意程序
。
###解答第一题
####在命令行中运行Lab16-02.exe
时,会发生什么?
我们打开命令提示符
(cmd.exe),尝试运行这次的恶意程序:
可见,程序输出了一行字符串,要求我们输入4个字符的密码。
###解答第二题
####当使用猜测的命令参数运行Lab16-02.exe
时,会发生什么?
我们可以尝试一下,随便输入4个字符的密码:
可见,如果我们输入的密码不正确,程序给我们回应的是“Incorrect password,Try again”
。
###解答第三题
####命令行密码是什么?密码是byrr
。
###解答第四题
####使用IDA Pro加载Lab16-02.exe。在main函数的何处可以找到strncmp函数
?
由这问题我们可以知道,程序应该使用的是strncmp函数对密码进行匹配的。我们可以利用IDA Pro
来分析一下这个程序:
可见,程序在0x0040123A的位置调用了strncmp函数
。
###解答第五题
####在默认设置下,将这个恶意代码加载到OllyDbg中会发生什么?
我们可以使用OD载入这个程序,并且尝试在0x0040123A
的位置下一个断点。但是由于我们所使用的OD自身具备很强的反调试能力
,因此这里我们使用原版的OD来实验一下。将这次的程序载入原版的英文OD,可以发现程序直接停止了,来到了retn
的位置:
###解答第六题
####Lab16-02.exe中PE结构的独特之处是什么?
这里我们使用PEiD来查看一下这个程序的区段表:
可以发现,这里有一个.tls的区段
。通常情况下,可执行程序是不会使用.tls区段的,如果我们在分析某一个程序的时候发现了这个区段,那么这也就说明,该程序很可能使用了反调试技术
。.tls的区段中包含有TLS回调函数
,该函数可以在程序入口点处的代码执行之前,得到执行。那么我们现在可以怀疑,之所以原版的OD载入程序后就直接停止了,很可能就是在执行入口代码之前,执行了TLS回调函数。
###解答第七题
####回调(callback)
发生在哪些位置?(提示:在IDA Pro中使用Ctrl+E组合键。)
在IDA中,我们利用快捷键Ctrl+E,就可以查看这个程序的每一个入口点的情况:
可以看到,TlsCallback
就是回调函数的位置,它的地址为0x00401060
。
###解答第八题
####恶意代码使用哪一种反调试技术使它在调试器中立即终止运行?如何避免这种检查?
在IDA中来到0x00401060
的位置进行分析:
这个TLS回调函数一开始,就将arg_4和1进行比较,来确定TLS回调函数
是否作为启动过程的一个结果被调用。也就是说,这种反调试技术仅仅在程序启动过程中被执行。可以看到,程序调用了FindWindowA
这个函数,用于查找当前所打开的窗口中,是否有类名为“OLLYDBG”
的这个窗口(注意这里检查的是窗口的类名,而不是窗口标题栏的名称)。如果这个窗口存在,那么返回值就是该窗口的句柄值
,它是一个非零值。这也就解释了,为什么当我们使用英文原版OD载入程序时,会直接来到retn的位置。就是由于在执行入口点代码之前,执行了TLS回调函数,检测到了OD已经打开,所以直接调用了exit函数
。可以使用spy++
查看窗口的类名。比如我们所使用的原版英文OD的类名如下:
其类名为“OLLYDBG”
,所以这次的实验程序所采用的反调试技术能够很好地针对我们的OD。再看一下我们平时所采用的加强版的OD:
可见其类名为“1212121”
,这样就能够很好地对抗采用了FindWindow
这个函数的反调试技术了。为了对抗这种反调试技术,我们可以使用OD的PhantOm插件
。由于我们当前使用的OD是原版的,它是不包含有插件的,我们可以手动来进行添加。首先在我们当前的OD目录中新建一个名为“plugin”的文件夹,将“PhantOm”插件拷贝过来。之后修改ollydbg.ini这个文件,将“Plugin path”
的内容修改为我们所创建的插件文件夹的路径。然后利用OD载入实验程序,来到PhantOm的选项界面,勾选“load driver”以及“hide OllyDbg windows”即可。
###解答第九题
####当你禁用反调试技术后,你在调试器中看到的命令行密码是什么?
现在我们就可以用原版的OD来调试这次的实验程序了。打开OD,选择“File”中的“Open”,选择这次的实验文件
,并且加上四个字符的“密码”,比如“1234”,再点击打开:
在strncmp的位置,也就是0x0040123A
的位置下一个断点,并执行过来。通过栈空间的情况可以知道,程序似乎在比较我们所输入的“1234”以及“[email protected]”这两个字符串前4个字节的内容。那么也就可以推测,这个程序的密码可能就是“bzqr”
。
###解答第十题
####调试器中找到的密码在命令行中运行有效吗?
可以尝试一下,在命令行中尝试使用“bzqr”这个密码:
可见,这里依旧显示密码不正确,说明我们还需要进一步的研究。
###解答第十一题
####哪种反调试技术为调试器和命令行设置不同的密码?如何防御它们?
这里我们首先在IDA中对strncmp
的第二个参数重新设置一下,方便接下来的分析。首先双击进入这个参数:
由于程序只验证前四个字符
,所以这里我们可以将其转化为4个字节的数组。在“Str2”上单击鼠标右键,选择“Array”,并且设置4个字符的大小,再单击OK。之后给它改个名字,比如“encoded_password”(注意设置名称的长度)。接下来,可以看到在strncmp函数
调用之前,有一个CreateThread
的函数调用。为了查看这个函数调用所创建的线程代码
,我们可以双击查看一下它的lpStartAddress参数情况。可以发现这个线程函数似乎是一个解密
的过程,因为它包含对encoded_password数组中的内容的多种运算操作。这里我们不必理会解密的原理,即便是利用IDA的F5功能,也不容易分析出其解密方式,这里我们只关注几个重要的地方。进一步检查这个解密的过程,可以发现它使用了BeingDebugged
这个属性:
在0x0040112B的位置,程序将PEB的地址赋给了ebx,接着在0x0040118B的位置,将BeingDebugged属性保存在了bl寄存器
中。之后再用bl与encoded_password进行运算。为了对抗使用了BeingDebugged属性的反调试技术,我们需要保证它的值为0。上节课讲过应对的方法,这次我选择使用PhantOm插件
。之后进入OD,勾选“PhantOm”插件中的“hide form PEB”。再载入程序,执行到0x0040123A的位置,查看当前栈空间的情况。可见此时的密码已经变成了“bzrr”。但是如果我们在命令行中使用这个密码,那么又会出现密码错误的情况。
我们再回到IDA中的解密函数:
程序在0x0040109B
的位置将byte_40A968赋给了bl,并在0x00401111的位置,将bl与encoded_password进行运算。双击进入byte_40A968查看,它的初始值为0。对其进行交叉引用:
可见它的值在sub_401020处被修改。来到这个位置进行分析:
可以看到,程序首先在0x0040102F
的位置调用了SetLastError函数
,用于将错误码设置为0x3039。接下来在0x0040103A处调用了OutputDebugStringA
这个函数,它可以向调试器发送一个字符串,让调试器打印显示(本实验中所打印的是“b”)。之后使用GetLastError,并比较当前的错误码是否还是0x3039。这也就说明,假设我们是在调试器中运行这个程序,那么错误码就不会改变,依旧是0x3039。并且下面将byte_40A968的值赋给cl,再将cl的值加1,之后再赋给byte_40A968,也就是实现了byte_40A968自增
的操作。如果是在命令行中运行此程序,错误码就会改变,那么byte_40A968就不会自增。这也就解释了为什么在命令行中输入“bzrr”依旧会得出不正确的结果。
由于这里我们是希望无论在什么情况下,cl都是自增1
的。那么为了对抗这种验证方式,我们可以将0x00401051处的语句用nop
代替,这里使用OD修改即可。然后用OD载入修改后的程序,再次来到0x0040123A的位置查看密码,那么密码就是“byrr”。在命令行中测试新修改的文件与密码:
可见,此时验证就得到通过了。接下来继续研究TLS函数
:
当前这个流程是在利用FindWindow
函数,没有检测到OD的存在时,所走的流程。这里一开始就将arg_4与2进行比较,之前曾经与1进行比较,说明在进程启动的时候,调用TLS函数
。而这里的2表示一个线程启动时,调用TLS函数。如果有3的话,则说明表示进程终止时
调用。因此,当CreateThread
运行,并使得OutputDebugStringA运行时,TLS回调函数
会被调用。
原文来自「鸢尾楚楚」|侵删