有趣的二进制:软件安全与逆向分析(txt+pdf+epub+mobi电子书下载)


发布时间:2020-05-21 20:06:01

点击下载

作者:爱甲健二

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

有趣的二进制:软件安全与逆向分析

有趣的二进制:软件安全与逆向分析试读:

前言

中所说的那样,希望大家能够借此体会到底层技术所特有的快乐。周自恒2015 年 8 月于上海免责声明

本书的内容以提供信息为目的,在使用本书的过程中,读者需要自己做出判断并承担相应的责任。对于读者因使用本书中的信息所造成的任何后果,作者、技术评论社、译者、人民邮电出版社恕不负责。

本书中的内容基于 2013 年 7 月 12 日的最新信息编写,在读者实际阅读时可能已经发生变化。

此外,软件方面由于其版本的更新,可能会与本书中所描述的功能和画面存在差异。在购买本书之前,请务必确认您所使用的软件版本。

各位读者在阅读本书之前,请同意并遵守上述注意事项。如果没有阅读上述事项,那么对于由此产生的问题,出版社和作译者可能也无法解决,敬请各位读者理解。前言

如今,计算机已经深入千家万户,为我们的生活带来了很多方便。但与此同时,计算机系统也变得越来越复杂,技术人员需要学习的知识也与日俱增。和过去相比,计算机技术中难以理解的黑箱也越来越多了。● 操作系统到底是干什么的?● CPU 和内存到底是干什么的?● 软件为什么能够运行?● 为什么会存在安全漏洞?● 为什么攻击者能够运行任意代码?

要想回答上面这些问题,我们需要用到以汇编为代表的二进制层面的知识。

尽管现在正是 Web 应用如日中天的时候,但二进制层面的知识依然能够在关键时刻发挥作用。例如:“用 C/C++ 开发的程序出现了不明原因的 bug,看了源代码还是找不到原因。”

在这样的情况下,即便不会编写汇编代码,只要能看懂一些汇编语言,就可以通过调试器立刻锁定发生 bug 的位置,迅速应对。

此外,如果别人编写的库里有 bug,那么即便看不到源代码,我们也能够对其内部结构进行分析,并找到避开问题的方法,也可以为库的开发者提供更有帮助的信息。

再举个例子。学习汇编能够更好地理解 CPU 的工作原理,从而能够处理系统内核、驱动程序这一类近乎于黑箱的底层问题,对于实际的底层开发工作也非常有帮助。

不过,说实在的,“有没有帮助”“流不流行”这些都不重要,从个人经验来看,因为感觉“好像有用”“好像有帮助”而开始学习的东西,最后基本上都没有真正掌握(笑)。当然,也许是因为我天资愚钝,不过我们在上学的时候,老师天天教导我们要好好学习,可是实际上有几个人真的好好学习了呢?虽然我没做过统计,但从感觉来看,整个日本也许还不到 1% 吧。

那么问题来了,要想真正学会一件事,到底需要什么呢?

我是从初中时代开始学习编程的,尽管当时完全没有想过将来要当程序员,靠技术吃饭,但我依然痴迷于计算机,每天编程到深更半夜,甚至影响了学习成绩,令父母担忧。

为什么当时的我如此痴迷于计算机而无法自拔呢?那是因为“编程太有趣了”。自己编写的代码能够按照设想运行起来,或者是没有按照设想运行起来,再去查找原因,这些事情都为我带来了莫大的乐趣。

我编写这本书,也是为了让大家对技术感到“有趣”,并且“想了解得更多”。而在编写这本书的过程中,我再一次感到,在不计其数的编程语言中,汇编语言是最“有趣”的一种。

如果你突然觉得“讲底层问题的书好像挺有意思的”而买了这本书,那么我相信,这本书一定能够为你带来超出预期的价值。

希望大家能够通过这本书,感受到二进制世界的乐趣。第1章通过逆向工程学习如何读懂二进制代码

大家是否听说过“逆向工程”这个词呢?

逆向工程原本是指通过拆解机器装置并观察其运行情况来推导其制造方法、工作原理和原始设计的行为,但在软件领域,逆向工程主要指的是阅读反汇编(将机器语言代码转换成汇编语言代码)后的代码,以及使用调试器分析软件行为等工作。

程序员都应该知道,处理器是通过解释和执行机器语言代码来运行程序的,但对现在的程序员来说,对机器语言代码进行反汇编并跟踪其行为并不是一项必备技能。换句话说,“知道是知道,但没亲自尝试过”这种情况比较普遍。

笔者是一位喜爱汇编语言的工程师,但也并不认为上面的现象有什么问题。实际上,我自己除了汇编以外,平时也经常使用 C、Python、JavaScript 等其他语言。不过,有些东西适合用 C、Python、JavaScript 来编写,同样也有一些东西适合用汇编语言来编写。更进一步说,在某些技术领域中,不懂汇编就无法工作。1

经常和处理器层面的东西打交道的工程师被称为 Binarian。尽管这些人并不能说多么伟大,但他们的确运用着很多鲜为人知的技术,你想不想玩玩看呢?

这是一个日本人造出来的词,英文中没有这个词。——译者注1

在本章中,我们将通过软件的逆向工程,探索一下二进制世界的奥秘。1.1 先来实际体验一下软件分析吧

下面我们就来动手尝试一下逆向工程。“咦?你还什么都没教呢!”

没关系,也许大家印象里觉得逆向工程是很难的,其实这里面有一半是误会,因为分析的难度取决于你要分析的对象。有些软件很难进行分析,但也有一些则很容易。

这里我们准备了一个简单的“恶意”程序,然后从下面三个要点来进行分析。● 文件的创建、修改和删除● 注册表项目的创建、修改和删除● 网络通信

如果我们能对上述三个方面进行监控,那么就不难跟踪软件的行为。

这里我们需要下面三个工具。2● Stirling(二进制编辑器)http://www.vector.co.jp/soft/win95/util/se079072.html● Process Monitor(文件和注册表监控)http://technet.microsoft.com/en-us/sysinternals/bb896645● Wireshark(网络监控)http://www.wireshark.org/这个软件仅在日本的圈子里有名,软件也只有日文界面,如果2不习惯可以使用其他类似工具(如 WinHex)来替代。——译者注

我们先启动 Process Monitor 和 Wireshark,修改配置以启用日志输出。

本书中的所有示例文件均可从以下地址下载。3

https://github.com/kenjiaiko/binarybook译者 fork 了这个项目,并对其中的说明文件和源代码注释等进3行了翻译,大家可以从这里访问:https://github.com/shyujikou/binarybook。——译者注

本次的分析对象为 chap01\sample_mal\Release 目录中的 sample_mal.exe 文件,请大家运行这个文件。

运行 sample_mal.exe 后,应该会弹出一个内容为“Hello Malware!”的对话框。

关闭对话框之后,sample_mal.exe 文件本身也会消失。1.1.1 通过 Process Monitor 的日志来确认程序的行为

下面我们来看一下 Process Monitor 的日志。

▲ Process Monitor 的运行结果(文件访问)

通过跟踪 Process Monitor 的日志,我们可以发现程序在以下位置进行了 CreateFile 操作。● C:\Documents and Settings\XPMUser\「开始」菜单 \ 程序 \

启动 \0.exe※Windows XP 的情况。● C:\Users\ 用户名 \AppData\Roaming\Microsoft\Windows

\Start Menu\Programs\Startup\0.exe※Windows Vista 及更高版本的情况。AppData 为隐藏文件

夹。

存放在“启动”文件夹中的程序,会随着 Windows 启动自动运行。

请大家注意,我们的示例程序连续执行了 CreateFile、WriteFile 和 CloseFile 这几个操作,这些操作加起来的功能相当于“在指定文件夹创建并写入一个名为 0.exe 的文件”。

我们来实际确认一下。

▲ 确认“启动”文件夹中的内容

果然和日志所描述的一样,创建了一个 0.exe 文件。

下面我们用二进制编辑器 Stirling 对比一下 0.exe 和 sample_mal.exe 的内容。在菜单中点击搜索 / 移动→比较,在弹出的窗口中选择比较对象,点击 OK 即可。

通过对比我们发现,两个文件的内容完全一致,也就是说,程序将自己复制了一份。

▲ 用 Stirling 对文件进行对比(在菜单中点击搜索 / 移动→比

4较)图中弹出的对话框中的日文“違いはありません”是“没有差4异”的意思。——译者注

由于“启动”文件夹中的程序会在 Windows 启动时自动运行,因此当我们重启 Windows 时,0.exe 就会被运行。这个程序并不会带来什么实际的危害,所以大家可以重启系统试试看。1.1.2 从注册表访问中能发现些什么

下面我们来确认一下注册表的访问情况。

Process Monitor 会列出程序访问过的注册表项目和文件。注册表是 Windows 系统提供给应用程序的一个用于保存配置信息的数据库,其中保存的数据包括浏览器设置、文件类型关联、用户密码等。

通过查看 Process Monitor 输出的日志,我们可以知道程序向“启动”文件夹复制了一个文件。

进一步分析日志,我们还可以发现程序对注册表进行了一些可疑的访问。

▲ Process Monitor 的运行结果(注册表访问)

看来程序在 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Current Version\Run 中创建了一个名为 sample_mal 的注册表项目。

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Current Version\Run 和“启动”文件夹一样,其中注册的程序会在 Windows 重启时自动运行。

Windows 重启时自动运行的程序可以注册在下列任一注册表的位置。● HKEY_LOCAL_MACHINE\Software\Microsoft\Windows

\CurrentVersion\Run● HKEY_CURRENT_USER\Software\Microsoft\Windows

\CurrentVersion\Run● HKEY_LOCAL_MACHINE\Software\Microsoft\Windows

\CurrentVersion\RunOnce● HKEY_CURRENT_USER\Software\Microsoft\Windows

\CurrentVersion\RunOnce

此外,我们发现程序还在 C:\Documents and Settings\XPMUser\My Documents 目录下,也就是“我的文档”文件夹下创建了一个名为 1.exe 的文件。

▲ 确认“我的文档”文件夹的内容

和 0.exe 一样,1.exe 也是 sample_mal.exe 的一个副本。

由于 1.exe 的路径已经被注册在注册表 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Current Version\Run 下面,因此当 Windows 启动时就会自动运行 1.exe。

下面我们来看一下 Windows 注册表的内容。使用 Windows 自带的 regedit 工具就可以查看注册表,点击开始菜单→运行,输入 regedit 即可。

▲ 确认注册表内容

可以发现注册表里面的确注册了 C:\Documents and Settings\XPMUser\My Documents\1.exe 这样的内容。

因此,如果我们删除 0.exe 和 1.exe,那么 Windows 重启时就不会再运行 sample_mal.exe 了。

其实,sample_mal.exe 只会弹出一个 Hello Malware! 的对话框,并没有进行其他任何操作。因此,我们只要将“启动”文件夹、“我的文档”以及注册表中新增的内容(文件路径)删除,系统环境就可以完全恢复原状了。1.1.3 什么是逆向工程

通过上面的结果我们可以发现,sample_mal.exe 程序会执行以下操作。● 修改注册表以便在系统重启时自动运行● 将自己复制到“启动”文件夹以便在系统重启时自动运行

由于程序没有进行网络通信,因此我们暂时不需要用到 Wireshark。

当然,由于在一开始我们不知道要分析的软件具体会执行怎样的操作,因此应该尽可能地收集完整的操作日志,对于不需要的部分只要放着不用就好了。

像上面这样对软件进行分析并搞清楚其行为的工作就是“逆向工程”。逆向工程是指一般意义上的软件分析,其对象不仅限于恶意软件,因此也不一定和计算机安全有关。

逆向工程原本是指通过拆解机器装置并观察其运行情况来推导其制造方法、工作原理和原始设计的行为,但在软件领域,逆向工程主要指的是阅读反汇编(将机器语言代码转换成汇编语言代码)后的代码,以及使用调试器分析软件行为等工作。

一直以来,在计算机病毒分析、防止软件非法使用的防拷贝技术,以及评估软件强度的抗篡改测试等领域都会用到逆向工程技术。一般认为,和软件开发所使用的编程技术相比,逆向工程属于另一种完全不同的技能。此外,由于逆向工程常常被用于恶意软件分析、防拷贝等领域,因此也经常被归为安全技术的一种。专栏:逆向工程技术大赛在一些国家,政府和民间社区会举办一些以 CTF(Capture the Flag)为代表的逆向工程技术大赛,以推动信息安全技术的发展。● SECCON CTF(日本)http://www.seccon.jp/● DEFCON CTF(美国)http://www.defcon.org/html/defcon-20/dc-20-ctf.html● CODEGATE CTF(韩国)http://yut.codegate.org/近年来,随着需求的不断增加,世界各地都开始开展各种安全竞赛活动。这些竞赛基本上都是通过线上预赛选出成绩最好的 10 ~ 20 个队伍进入决赛。尽管很多比赛的水平很高,但比赛本身也十分有趣,有兴趣的话去参加一下也未尝不可。1.2 尝试静态分析1.2.1 静态分析与动态分析

软件分析从方法上可大体分为“静态分析”和“动态分析”两种。简单来说,它们的区别如下。● 静态分析:在不运行目标程序的情况下进行分析● 动态分析:在运行目标程序的同时进行分析

刚才我们对 sample_mal.exe 进行分析的方法就属于动态分析。相对地,静态分析主要包括以下方法。● 阅读反汇编代码● 提取可执行文件中的字符串,分析使用了哪些单词

从广义上来看,用二进制编辑器查看可执行文件的内容也可以算作是一种静态分析。

下 面,我们先来对 chap01\wsample01a\Release 中的示例程序 wsample01a.exe 进行静态分析。wsample01a.exe 的运行结果如下所示。

▲ wsample01a.exe 的运行结果

运行之后,我们发现这个程序只是简单地显示了一个 Hello! Windows 对话框而已。

可是,这个程序真的就这么简单吗?让我们再仔细研究一下。

首先,我们用二进制编辑器打开 wsample01a.exe 文件。文本编辑器还是有很多人经常使用的,不过会使用二进制编辑器的人可就不多了。在软件分析中,二进制编辑器可是要从头用到尾的。就我个人来说,二进制编辑器、计算器、反汇编器和调试器可谓是逆向工程的四大法宝,不过在这方面使用什么工具也是因人而异,我说的也并不是唯一标准。

在二进制编辑器中,比较流行的主要是以下两种。● Stirlinghttp://www.vector.co.jp/soft/win95/util/se079072.html● BZ Editorhttp://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 D e m o 版,不过这个版本有使用时间限制。● IDA 6.2 Demo version, IDA 5.0 Freeware versionhttp://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.exe00401000 ; int __stdcall wWinMain(int,int,LPCWSTR lpString1,int)00401000 wWinMain proc near0040100000401000 lpString1 = dword ptr 10h0040100000401000 push ebp00401001 mov ebp, esp00401003 mov eax, [ebp+lpString1]00401006 push offset String2 ; "2012"0040100B push eax ; lpString10040100C call ds:__imp__lstrcmpW@8 ; lstrcmpW(x,x)00401012 push 0 ; uType00401014 push offset Caption ; "MESSAGE"00401019 test eax, eax0040101B jnz short loc_4010350040101D push offset Text ; "Hello! 2012"00401022 call ds:__imp__GetActiveWindow@0 ;GetActiveWindow()00401028 push eax ; hWnd00401029 call ds:__imp__MessageBoxW@16 ;MessageBoxW(x,x,x,x)0040102F xor eax, eax00401031 pop ebp00401032 retn 10h ; lpCaption00401035 loc_401035:00401035 push offset aHelloWindows ; "Hello! Windows"0040103A call ds:__imp__GetActiveWindow@0 ;GetActiveWindow()00401040 push eax ; hWnd00401041 call ds:__imp__MessageBoxW@16 ;MessageBoxW(x,x,x,x)00401047 xor eax, eax00401049 pop ebp0040104A retn 10h0040104A wWinMain endp

当然,我们没必要看懂全部的汇编语言代码。和刚才使用二进制编辑器的时候一样,只要一眼望去能大概理解这段代码做了什么事就可以了。1.2.5 确认程序的源代码

最后让我们来看一下 wsample01a.exe 真正的源代码(chap01\wsample01a 中的 wsample01.cpp)。要编译这段代码需要安装 Visual Studio。关于 Visual Studio 的安装方法请参见附录,关于如何编译请参见 readme 文件。

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

只要一定程度上掌握这些工具的使用方法,大家就可以完成很多软件分析工作了。1.3 尝试动态分析 设置 Process Monitor 的过滤规则

接下来,我们来尝试一下动态分析。

相对于静态分析而言,动态分析是在目标程序运行的同时跟踪其行为的方法。在这里,我们主要用调试器来跟踪程序逻辑,除此以外,下面这些方法也被称为动态分析。● 获取文件和注册表访问日志● 抓取网络包

下面我们来分析一下 chap01\wsample01b\Release 中的示例程序 wsample01b.exe。

我们先来看一下 wsample01b.exe 的运行结果。

▲ wsample01b.exe 的运行结果

这个程序看起来只是在屏幕上显示了一条 Copied! 消息,实际上背后发生了什么呢?我们还不得而知。下面我们来仔细研究一下。

我们可以用 Process Monitor 来输出示例程序 wsample01b.exe 的运行日志。

启动 Procmon.exe 之后,会弹出过滤规则设置窗口,我们在这里设置为 wsample01b.exe。

如果没有弹出过滤规则设置窗口,可以按下 Ctrl+L 或者点击菜单中的 Filter → Filter...。

▲ 在 Process Monitor 的过滤规则中设置 wsample01b.exe

在过滤规则里面可以进行各种设置。

这里我们希望实现的是“当进程名称为 wsample01b.exe 时输出日志”,设置好之后显示的文字描述如下。

Process Name is wsample01b.exe then Include

输入规则后,按下 Add 按钮,这条规则就会被添加到下面的列表中。

设置完成,点击 OK 关闭设置窗口,然后运行 wsample01b.exe。

▲ 运行 wsample01b.exe 并输出日志

运行 wsample01b.exe,会弹出一个写着 Copied! 的消息框。与此同时,Process Monitor 也会输出文件和注册表的访问日志。

通过日志,我们可以看出 wsample01b.exe 访问了以下文件。

C:\Documents and Settings\XPMUser\「开始」菜单 \ 程序 \ 启动 \ wsample01b.exe

和 sample_mal.exe 很像吧?

▲ 对“启动”文件夹的访问

我们可以打开“启动”文件夹确认一下,里面果然有 wsample01b.exe 文件。

笔者的测试环境是 Windows XP SP3,请大家注意不同环境下“启动”文件夹的名称和位置可能会有所不同。在 Vista 及更高版本中,“启动”文件夹位于以下位置。

C:\Users\ 用户名 \AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup1.3.2 调试器是干什么用的

通过 Process Monitor 我们只能知道上面这些信息,如果要进一步跟踪程序逻辑,我们需要使用调试器。

调试器是一种帮助发现程序问题和 bug 的软件,一般来说至少应具备以下功能。● 断点● 单步跳入、跳出● 查看寄存器和内存数据

断点是能够让程序在任意位置中断、恢复运行的功能。我们可以在可能会发生 bug 的地方稍往前一点设置一个断点,以便找到导致问题的程序逻辑。一般来说,如果是机器语言,则以指令为单位来设置断点;而如果是高级语言,则以源代码的行为单位来设置断点。

断点能够在任意位置中断和恢复运行,而每执行一条指令都中断一次就叫作单步跳入或跳出。通过单步运行功能,我们可以以一条指令或者一行代码为单位逐个运行程序中的逻辑,仔细确认内存和变量的状态。跳入和跳出的区别如下所示。● 跳入:调用函数时进入函数内部● 跳出:调用函数时不进入函数内部,而是将函数调用作为一

条指令来执行

最后就是查看寄存器和内存数据了,这个功能可以在程序中断运行的状态下确认寄存器、内存和变量的状态。

本章中我们使用的调试器为 OllyDbg 1.10,安装方法请参见附录。● OllyDbghttp://www.ollydbg.de/1.3.3 用 OllyDbg 洞察程序的详细逻辑

现在我们将 wsample01b.exe 拖曳到 OllyDbg 的图标上。

▲ 用 OllyDbg 打开 wsample01b.exe

OllyDbg 的画面包括以下几个部分。● 左上:主要反汇编窗口● 左下:内存数据窗口● 右上:寄存器● 右下:当前栈

这些窗口各自的功能我们可以慢慢学,现在我们先按下面任意方式进行操作,然后在弹出的窗口中输入 00401000,按下 OK 按钮。● 在反汇编窗口中按 Ctrl+G● 在单击右键弹出的菜单中点击 Go To → Expression

▲ 跳转到地址 00401000

这时,反汇编窗口中会显示出地址 00401000 以后的程序逻辑。

这些程序逻辑对应的汇编代码如下。00401000 >/$ 55 PUSH EBP00401001 |. 8BEC MOV EBP,ESP00401003 |. B8 04200000 MOV EAX,200400401008 |. E8 D3080000 CALL wsample0._chkstk0040100D |. A1 00304000 MOV EAX,DWORD PTR DS:[__security_cookie]00401012 |. 33C5 XOR EAX,EBP00401014 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX00401017 |. 68 00100000 PUSH 10000040101C |. 8D85 FCDFFFFF LEA EAX,DWORD PTR SS:[EBP-2004]00401022 |. 50 PUSH EAX ; |PathBuffer00401023 |. 6A 00 PUSH 0 ; |hModule = NULL00401025 |. FF15 04204000 CALL DWORD PTRDS:[]0040102B |. 8D8D FCEFFFFF LEA ECX,DWORD PTR SS:[EBP-1004]00401031 |. 51 PUSH ECX00401032 |. 6A 00 PUSH 000401034 |. 6A 00 PUSH 000401036 |. 6A 07 PUSH 700401038 |. 6A 00 PUSH 00040103A |. FF15 B4204000 CALL DWORD PTRDS:[]00401040 |. 68 14214000 PUSH OFFSET "\wsample01b.exe"00401045 |. 8D95 FCEFFFFF LEA EDX,DWORD PTR SS:[EBP-1004]0040104B |. 52 PUSH EDX ; |ConcatString0040104C |. FF15 08204000 CALL DWORD PTR DS:[]00401052 |. 6A 00 PUSH 0 ; /FailIfExists = FALSE00401054 |. 8D85 FCEFFFFF LEA EAX,DWORD PTR SS:[EBP-1004]0040105A |. 50 PUSH EAX ; |NewFileName0040105B |. 8D8D FCDFFFFF LEA ECX,DWORD PTR SS:[EBP-2004]00401061 |. 51 PUSH ECX ; |ExistingFileName00401062 |. FF15 00204000 CALL DWORD PTR DS:[]00401068 |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]0040106B |. 33CD XOR ECX,EBP0040106D |. 33C0 XOR EAX,EAX0040106F |. E8 2F000000 CALL wsample0.__security_check_cookie00401074 |. 8BE5 MOV ESP,EBP00401076 |. 5D POP EBP00401077 \. C3 RETN

也许你会问:“我看不懂这些汇编代码,是不是没办法继续分析了呢?”其实看不懂汇编并没有大碍,软件分析的目标是搞清楚程序到底干了什么,和实际的编程是不同的。我们不需要完全理解所有的逻辑,只要能看出个大概就可以了。1.3.4 对反汇编代码进行分析

现在让我们来仔细看看 00401000 之后的程序逻辑。我们发现程序依次调用了 GetModuleFileNameW、SHGetFolderPathW、lstrcatW、CopyFileW 这几个函数。

回想一下,刚才我们用 Process Monitor 已经发现程序会向“启动”文件夹复制文件,我们可以推测“上面的 CopyFileW 函数就是用来执行这一操作的”。你看,即便看不懂汇编代码,只要能大概推测出程序的逻辑就行了。

那么,我们的推测是否正确呢?可以通过单步运行功能来确认一下。

首先选中地址 00401000 所在的行,然后按 F2 键,或者单击右键从菜单中选择 Breakpoint → Toggle。这时,地址 00401000 的背景会变成红色,这说明我们已经在 00401000 的位置设置了一个断点。

接下来按下 F9 键,或者在窗口上方菜单中点击 Debug → Run。这时,OllyDbg 会启动 wsample01b.exe,当到达断点所在的 00401000 位置时,程序会暂停运行。

▲ 程序在 00401000 的断点处暂停运行

接下来,我们可以通过单步运行,逐条运行程序中的指令。按 F7 表示单步跳入,按 F8 表示单步跳出。由于我们不需要进入 GetModuleFileNameW 和 SHGetFolderPathW 函数的内部,因此在这里我们按 F8。

随着每次按下 F8,程序都会执行一条指令,同时右上方的寄存器窗口和右下方的栈窗口的内容也会发生变化。

现在我们让程序一直运行到 00401062 的地方,也就是调用 CopyFileW 之前的位置。这时,通过寄存器窗口和栈窗口,我们可以看到要复制的文件源路径和目标路径。

由于现在 CopyFileW 还没有被调用,因此在“启动”文件夹中还没有文件。这时如果我们再次按下 F8 键,程序就会调用 CopyFileW 函数,现在再看一下“启动”文件夹,我们就会发现其中已经出现了 wsample01b.exe 文件。

通过使用调试器,我们可以逐一运行程序中的指令,从而搞清楚在哪个时间点执行了怎样的操作,这是动态分析的一个优点。专栏:什么是寄存器寄存器是位于 CPU 内部的存储空间,每个寄存器都有自己的名字,分别叫作 EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI、EIP。这些寄存器都有各自的用途。例如 ESP 和 EBP 用于管理栈,而 EIP 则指向当前执行的指令。OllyDbg 右上方的寄存器窗口中会显示当前所有寄存器的值。▲ OllyDbg 的寄存器窗口如果我们在 OllyDbg 中按下 F8 或者 F7,程序就会执行一条指令,这时我们可以看到 EIP 的值会根据所执行指令的长度不断增加。在 EIP 的下方还有 C、P、A、Z、S、T、D、O 这几个字母,它们代表标志。一般我们会在这些字母后面加上一个字母 F(Flag 的首字母),写作 CF、PF、AF、ZF,这些标志主要用于条件分支,比如下面这样。● 若 ZF为1 则跳转● 若 CF 为 1 则不跳转基本上只要理解了 EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI、EIP 以及各个标志寄存器的作用,我们就可以进行软件分析了。除此之外画面上还会显示其他一些寄存器的值,关于这些寄存器,等我们上手一些之后再去了解也不迟。1.3.5 将分析结果与源代码进行比较

最后,我们照例会列出 wsample01b.exe 的源代码,大家可以将自己分析的结果以及头脑中设想的程序逻辑与源代码进行比较。

▼ wsample01b.cpp#include #include #include int cpy(void){ // 获取自身文件路径 TCHAR szThis[2048]; GetModuleFileName(NULL, szThis, sizeof(szThis)); // 获取“启动”文件夹路径 TCHAR szStartup[2048]; SHGetFolderPath(NULL, CSIDL_STARTUP, NULL, SHGFP_TYPE_CURRENT, szStartup); lstrcat(szStartup, _T("\\wsample01b.exe")); // 将自身复制到“启动”文件夹 CopyFile(szThis, szStartup, FALSE); return 0;}int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){ cpy(); MessageBox(GetActiveWindow(), _T("Copied!"), _T("MESSAGE"), MB_OK); return 0;}

在软件分析中,我们需要按照目的和需要选择使用静态分析还是动态分析。

从分类的角度来看,静态分析和动态分析的区别在于“是否运行目标程序”,但从笔者个人感觉来看,静态分析比较偏向于“总览全局”,而动态分析则比较偏向于“细看局部”。

因此,在进行软件分析的时候,一般都是先用 Stirling 和 IDA 看一下整体的样子,然后再用 OllyDbg 单步运行来查看一些特别关注的点。

当然,上面只是我的个人感觉,也会有一些例外的情况。随着经验的积累,大家完全可以摸索出自己喜欢的方式。专栏:选择自己喜欢的调试器Windows 环境中有几款主流的调试器,每个人的喜好都有所不同。● OllyDbghttp://www.ollydbg.de/● Immunity Debugger

通过实际尝试静态分析和动态分析,相信大家已经对软件分析是怎么一码事有了一些了解。如果大家觉得比想象中要容易那是最好,不过可能很多读者还是会觉得有些难度。

那么到底难在哪里呢?恐怕还是在于汇编语言。

和一般编程语言的保留字相比,汇编语言的指令数量多得离谱,因为只有记住将近 1000 条指令才能编写出像样的程序,难怪想学汇编的人少得可怜。

不过,说实在的,在逆向工程中需要用到的汇编语言知识并没有那么多。正如 Windows 程序员没必要记住所有的 Windows API 函数一样,做逆向工程也没必要记住太多的汇编指令,遇到不会的指令查一下就行了,实际上我们需要掌握的指令也就是 20 ~ 50 条左右。

下面我们就来讲解一下逆向工程所需要掌握的汇编指令,并简单介绍一下 CPU 的工作原理。

首先我们来看看“以笔者的‘主观偏见’为标准选出的常用汇编指令”。这里的内容全部基于笔者的个人感觉,知道这些指令应该就能够基本上手了。

顺便一提,这里讲解的内容以简单易懂为首要目标,相应地牺牲了准确性。如果大家有兴趣继续深入学习汇编语言的话,请务必重新查阅一下这些指令的用法。

▼ 常用汇编指令指示例含义说明令MOMV EAX = OEAX将 ECX 的值存入 EAXECXV,ECXADDA EAEAX += D将 EAX 的值加上 ECX 的值X,EECXDCXSUBS EAEAX -= U将 EAX 的值减去 ECX 的值X,EECXBCXININC EAX++将 EAX 的值加 1CEAXDDECE EAEAX--将 EAX 的值减 1CXLEA EAXLEEAX = ,将 ECX+4 的值存入 EAXAECX+4[ECX+4]if(EAX CMP对两个值进行比较并根据结果设置C== ECX) EA标志M ZF=1X,E若 EAX 与 ECX 相同,则 ZF=1PelseCX若 EAX 与 ECX 不同,则 ZF=0 ZF=0TESif(EAX 将值与 0 进行比较并根据结果设置T == 0)TE标志EAX ZF=1ST若 EAX 为 0,则 ZF=1,EAelse若 EAX 不为 0,则 ZF=0X ZF=0if(ZF==1JEJE )(J0400若 ZF 为 1,则跳转到 04001000 GOTO Z)100004001000JNif(ZF==0JNE E()0400若 ZF 为 0,则跳转到 04001000JN GOTO 1000Z)04001000

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载