有趣的二进制:软件安全与逆向分析
上QQ阅读APP看书,第一时间看更新

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十分强大,可以让我们十分清晰地看出程序的分支逻辑。

只要一定程度上掌握这些工具的使用方法,大家就可以完成很多软件分析工作了。