1.2 尝试静态分析
1.2.1 静态分析与动态分析
软件分析从方法上可大体分为“静态分析”和“动态分析”两种。简单来说,它们的区别如下。
●静态分析:在不运行目标程序的情况下进行分析
●动态分析:在运行目标程序的同时进行分析
刚才我们对sample_mal.exe进行分析的方法就属于动态分析。相对地,静态分析主要包括以下方法。
●阅读反汇编代码
●提取可执行文件中的字符串,分析使用了哪些单词
从广义上来看,用二进制编辑器查看可执行文件的内容也可以算作是一种静态分析。
下面,我们先来对chap01\wsample01a\Release中的示例程序wsample01a.exe进行静态分析。wsample01a.exe的运行结果如下所示。
▼wsample01a.exe的运行结果
运行之后,我们发现这个程序只是简单地显示了一个Hello! Windows对话框而已。
可是,这个程序真的就这么简单吗?让我们再仔细研究一下。
首先,我们用二进制编辑器打开wsample01a.exe文件。文本编辑器还是有很多人经常使用的,不过会使用二进制编辑器的人可就不多了。在软件分析中,二进制编辑器可是要从头用到尾的。就我个人来说,二进制编辑器、计算器、反汇编器和调试器可谓是逆向工程的四大法宝,不过在这方面使用什么工具也是因人而异,我说的也并不是唯一标准。
在二进制编辑器中,比较流行的主要是以下两种。
●Stirling
http://www.vector.co.jp/soft/win95/util/se079072.html
●BZ Editor
http://www.vector.co.jp/soft/win95/util/se032859.html
这两个工具可以说各有所长,大多数软件分析者都是两者并用的。笔者也是两个工具都安装了,但如果一定要二者选其一的话,笔者比较推荐Stirling,本书中的讲解也是以使用Stirling为前提来进行的(理由请参见专栏)。
专栏:Stirling与BZ Editor的区别
刚才我们提到“Stirling和BZ Editor这两个工具各有所长”,但使用Stirling基本上可以应付大多数情况。
然而,尽管Stirling功能强大,可以应付各种情况,但处理尺寸较大的文件会消耗过多的内存,因此无法处理几个GB大小的文件。
一般来说,我们处理大文件的机会还是比较少的,因此通常情况下使用Stirling就足够了,不过BZ Editor却能够弥补这一缺点,它可以轻松打开大文件,而且反应更敏捷。
尽管现实总是不完美,但其实我真心希望这两个工具能够被整合起来,变成一个既拥有强大功能,又能够轻松处理大文件的二进制编辑器。若真能如此,夫复何求?
1.2.2 用二进制编辑器查看文件内容
下面我们用Stirling打开wsample01a.exe看一看。
▼用Stirling打开wsample01a.exe的样子
用Stirling打开wsample01a.exe后,我们可以看到屏幕上显示出一串十六进制字符。这就是Windows可执行文件格式,即“PE格式”的文件内容。关于PE格式的详细信息,可以通过阅读官方文档来搞明白,不过这一次我们还不用了解得那么深入,只要看个大概就行了,不需要理解这些数据的含义。
乍一看,我们就能够发现下面这些内容。
●字符串MESSAGE和Hello! Windows
●文件路径C:\Documents and Settings\XPMUser\My Documents\Visual Studio 2010\Projects\wsample01a\Release\wsample01a.pdb
●字符串KERNEL32.dll、MessageBoxW
除此之外还有其他一些字符串貌似也能看出什么意思,不过好像又看不太明白,总之现在到这一步就可以了。
1.2.3 看不懂汇编语言也可以进行分析
接下来我们试试看对wsample01a.exe进行反汇编。
本书中我们使用IDA 5.0 Freeware版(免费版)作为反汇编工具。和正式版相比,免费版支持的处理器数量较少,而且还有一些功能限制,但它的性能依然出众,在反汇编领域可以说无出其右。工具的安装方法请参见附录。
大家也可以下载最新的6.2 Demo版,不过这个版本有使用时间限制。
●IDA 6.2 Demo version, IDA 5.0 Freeware version
http://www.hex-rays.com/products/ida/support/download.shtml
也许大家印象里觉得汇编语言非常难懂,但其实现在我们有很多功能强大的工具,可以像看流程图一样对软件进行分析。下面让我们来体验一下。
首先,将wsample01a.exe拖曳到IDA的图标上,然后会显示一个About对话框,我们按OK将它关闭。
接下来,会弹出一个Load a new file对话框,询问用什么格式打开指定的文件。
这里我们选择Portable executable for 80386 (PE),然后按OK。
随后可能还会弹出一些消息,只要点击OK就可以了。
接着,IDA会弹出一个分析窗口。
右边有一个名叫Names window的窗口,它默认是打开的,如果没有打开的话可以按Shift+F4打开,或者也可以点击菜单View→Open subviews→Names。
在Names window窗口的最上方会显示wWinMain这个函数名,双击它。
接下来,IDA View-A窗口中会显示出反汇编代码。
▼用IDA打开wsample01a.exe(Load a new file)
▼用IDA打开wsample01a.exe(分析窗口)
也可以右键点击函数名,从菜单中选择Text view或者是Graph view,用不同的视图来查看代码,默认视图为Graph view。
▼wWinMain函数的反汇编代码(Graph view)
在这个视图中,IDA会显示出调用的函数以及传递的参数,十分容易理解。
也许你曾经认为“汇编语言很难懂”,但我们现在有了很多工具,甚至在软件分析中已经几乎用不到汇编语言的知识了,大家看看IDA显示出来的汇编语言代码应该就能够明白了。
1.2.4 在没有源代码的情况下搞清楚程序的行为
下面我们来看看wWinMain函数里面的逻辑,除了Hello! Windows、MESSAGE、MessageBoxW等字符串以外,我们还能发现下列字符串。
●2012
●lstrcmpW
●GetActiveWindow
其中尤其值得寻味是Hello! Windows和Hello! 2012这两个字符串,它们是在不同的条件分支中显示的。
我们尝试在命令行中用2012作为参数来运行一下wsample01a.exe。
▼运行示例
C:\>wsample01a.exe 2012
▼向wsample01a.exe传递参数2012后的运行结果
和无参数的情况相比,这次显示出来的消息变成了Hello! 2012。
可能有人要问:“那又如何?”我们发现了通过传递2012这个参数,程序的显示结果会发生变化,这很重要。因为我们在“完全没有源代码的情况下,搞清楚了程序的行为”。
这就是逆向工程。
刚才这个参数是我们猜测出来的,其实只要阅读汇编语言代码,就可以发现其中使用了lstrcmpW对字符串2012和命令行参数进行了比较操作。
▼wsample01a.exe
00401000 ; int __stdcall wWinMain(int, int, LPCWSTR lpString1, int) 00401000 wWinMain proc near 00401000 00401000 lpString1 = dword ptr 10h 00401000 00401000 push ebp 00401001 mov ebp, esp 00401003 mov eax, [ebp+lpString1] 00401006 push offset String2 ; "2012" 0040100B push eax ; lpString1 0040100C call ds:__imp__lstrcmpW@8 ; lstrcmpW(x, x) 00401012 push 0 ; uType 00401014 push offset Caption ; "MESSAGE" 00401019 test eax, eax 0040101B jnz short loc_401035 0040101D push offset Text ; "Hello! 2012" 00401022 call ds:__imp__GetActiveWindow@0 ; GetActiveWindow() 00401028 push eax ; hWnd 00401029 call ds:__imp__MessageBoxW@16 ; MessageBoxW(x, x, x, x) 0040102F xor eax, eax 00401031 pop ebp 00401032 retn 10h ; lpCaption 00401035 loc_401035: 00401035 push offset aHelloWindows ; "Hello! Windows" 0040103A call ds:__imp__GetActiveWindow@0 ; GetActiveWindow() 00401040 push eax ; hWnd 00401041 call ds:__imp__MessageBoxW@16 ; MessageBoxW(x, x, x, x) 00401047 xor eax, eax 00401049 pop ebp 0040104A retn 10h 0040104A wWinMain endp
当然,我们没必要看懂全部的汇编语言代码。和刚才使用二进制编辑器的时候一样,只要一眼望去能大概理解这段代码做了什么事就可以了。
1.2.5 确认程序的源代码
最后让我们来看一下wsample01a.exe真正的源代码(chap01\wsample01a中的wsample01.cpp)。要编译这段代码需要安装Visual Studio。关于Visual Studio的安装方法请参见附录,关于如何编译请参见readme文件。
▼wsample01a.cpp
#include <Windows.h> #include <tchar.h> int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { if(lstrcmp(lpCmdLine, _T("2012")) == 0){ MessageBox(GetActiveWindow(), _T("Hello! 2012"), _T("MESSAGE"), MB_OK); }else{ MessageBox(GetActiveWindow(), _T("Hello! Windows"), _T("MESSAGE"), MB_OK); } return 0; }
现在大家能够理解IDA的反汇编结果是何等容易理解了吧。
刚一听到“逆向工程”“汇编”这些词的时候,大家总会以为它们很难,但实际上并非如此。使用IDA,我们就可以将可执行文件转换成像C语言一样容易理解(实际上还是有差距的)的汇编代码。尤其是它的Graph view十分强大,可以让我们十分清晰地看出程序的分支逻辑。
只要一定程度上掌握这些工具的使用方法,大家就可以完成很多软件分析工作了。