手把手教你 | 漏洞挖掘系列之WinAFL从安装到使用

阅读量    9296 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

作者:维阵漏洞研究员——ztop

1. 实验环境


我下面的所有操作都是在VMware里完成的,所以在 windows 7 pro 中安装vs2013的步骤可以在网上查的到。

2. git 安装


直接双击 Git-2.27.0-64-bit.exe 进行安装,然后一直next即可。

3. cmake 安装


也直接双击 cmake-3.18.0-rc3-win64-x64.msi 进行安装,然后一直next即可。

4. DynamoRIO 编译


在 C: 盘下新建 my_winafl_fuzz 文件夹,并把下载好的DynamoRIO 源码(dynamorio-release_7.1.0.zip)解压并放入到my_winafl_fuzz目录下。

找到 vcvarsall.bat ,并使用vcvarsall.bat来设置命令行的编译环境。下面是我的vcvarsall.bat所在目录:

1. 编译 DynamoRIO 的 x32 版本

在C:Program Files (x86)Microsoft Visual Studio 12.0VC目录下,右键cmd出来,然后执行下列命令:

Studio 12.0\VC>vcvarsall x86
Studio 12.0\VC>cd C:\my_winafl_fuzz\dynamorio-release_7.1.0
dynamorio-release_7.1.0>mkdir build32 && cd build32
dynamorio-release_7.1.0\build32>cmake -G"Visual Studio 12 2013" -A Win32 ..
*******************
cmake -G"Visual Studio 12 2013" -A Win32 ..   //这里的两个.点表示上层目录
也可以用下列命令,这两条命令是等价的
cmake -G"Visual Studio 12 2013" ..         // x32  
如果要编译x64的话,就加
cmake -G"Visual Studio 12 2013 Win64" ..   // x64
*******************
cmake --build . --config RelWithDebInfo //RelWithDebInfo 表示包含调试信息的release版本

 

解决 “Could NOT find Perl (missing: PERL_EXECUTABLE)” 的办法是,安装一个perl,并把perl的安装路径添加到PAHT环境变量里。由于我们安装了”Git-2.27.0-64-bit.exe”, 而”C:\Program Files\Git\usr\bin”目录下刚好有perl.exe, 所以我们把 “C:\Program Files\Git\usr\bin” 添加到 PAHT环境变量即可。

然后重新启动cmd,重复上述命令即可。

经过上面的步骤,我们就完成了DynameRIO x32 的编译,在 build32\bin32 目录下可以看到 drrun.exe 程序。

2. 编译 DynamoRIO 的 x64 版本

编译x64版本的步骤基本和上面一样:

Studio 12.0\VC>vcvarsall amd64_x86                           // 切换64位编译环境
Studio 12.0\VC>cd C:\my_winafl_fuzz\dynamorio-release_7.1.0  // 进入dynamorio源码目录
dynamorio-release_7.1.0>mkdir build64 && cd build64     // 创建文件并进入
dynamorio-release_7.1.0\build32>cmake -G"Visual Studio 12 2013" -A x64 ..
#cmake -G"Visual Studio 12 2013 Win64" ..      
dynamorio-release_7.1.0\build32>cmake --build . --config RelWithDebInfo

这里我通过另一种方式编译DynamoRIO —- > 即:”Visual Studio命令提示工具”; 该工具在【开始->所有程序->Visual Stdio 2013 -> Visual Studio Tools】目录下可以找到。

双击上面的”Visual Studio Tools”目录后,会看到下列内容:

这里对于新手来说,这里有个坑。但是我们先操作正确的步骤,然后演示遇到的坑。 由于我们的系统是windos_x64的,所以必须选 “VS2013 x64 兼容工具命令提示”,双击”VS2013 x64 兼容工具命令提示”会弹出一个cmd。


经过上面步骤x64就编译完成了。可以看到”build64\bin64”目录下已经有了”drrun.exe”等文件。

通过上面步骤我们就完成了DynamoRIO 的x32和x64的编译了。

现在我们来说说,新手可能会遇到的坑。我们先把”dynamorio-release_7.1.0”目录下的”build64”文件全部删除掉。双击”VS2013 x64 本机工具命令提示”,然后运行下面命令:

最后会报下列错误:

还有一种就是用最原始的来切换编译环境:

它也会出现下列错误:

为了避免这个错误,必须遵守”vcvarsall.bat” 用于生成命令行编译环境的规则,规则在开头我已经说的很清楚了,”Visual Studio命令提示工具”其实和”vcvarsall.bat”是一样的。所以不要因马虎而犯错了。

5. winafl 编译


进入C:my_winafl_fuzz目录,通过下列命令下载winafl代码:

git clone —recursive https://github.com/googleprojectzero/winafl

1. 编译 winafl 的 x32版本

// 1. 切换 x86 编译环境
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC>vcvarsall.bat x86

// 2. 进行winafl源码的下载目录
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC>cd C:\my_winafl_fuzz\winafl

// 3. 创建目录,用于保存winafl编译好的二进制等文件
C:\my_winafl_fuzz\winafl>md b32 && cd b32

// 4. 进行配置,DDynamoRIO_DIR 填写我们编译好的build32\cmake的绝对路径
C:\my_winafl_fuzz\winafl\b32>cmake -G"Visual Studio 12 2013" -A Win32 .. -DDynamoRIO_DIR=C:\my_winafl_fuzz\dynamorio-release_7.1.0\build32\cmake

// 5. 编译生成
C:\my_winafl_fuzz\winafl\b32>cmake --build . --config Release

配置winafl时,cmake 的参数说明:

cmake 参数说明:

-G"Visual Studio 12 2013"   // 使用什么版本的 Visual Studio 进行编译源码
-A Win32                    // 编译什么架构的版本,也可以用下列标准的形式
************************************************************************
C:\my_winafl_fuzz\winafl\b64>cmake -G"Visual Studio 2013"
CMake Error: Could not create named generator Visual Studio 2013

Generators
  Visual Studio 16 2019        = Generates Visual Studio 2019 project files.
                                 Use -A option to specify architecture.
  Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files.
                                 Optional [arch] can be "Win64" or "ARM".
* Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 10 2010 [arch] = Generates Visual Studio 2010 project files.
                                 Optional [arch] can be "Win64" or "IA64".
  Visual Studio 9 2008 [arch]  = Generates Visual Studio 2008 project files.
                                 Optional [arch] can be "Win64" or "IA64".
****************************************************************************

-DDynamoRIO_DIR=..\path\to\DynamoRIO\cmake   // 生成 DynamoRIO 客户端: winafl.dll

-DINTELPT=1     // 启用 Intel PT 模式.
参考: https://github.com/googleprojectzero/winafl/blob/master/readme_pt.md

-DUSE_COLOR=1   // 颜色支持, 只对 Windows 10周年纪念版或更高版本有效

-DUSE_DRSYSMS=1 // 开启 Drsyms 模式,但在 Windows 10 v1809 下加该参数会出错.
参考:https://github.com/googleprojectzero/winafl/issues/145

进入winafl\b32\bin\Release下面就是我们编译好的winafl_x32:

下面演示可能出现的问题,有一些人在下载winafl代码的时候,可能习惯性的会直接这样操作:

git clone https://github.com/googleprojectzero/winafl

编译时候就会出现这样的错误,这是由于winalf源代码没有下载完整,缺少依赖文件,在winafl\third_party\processor-trace目录下是空的。

解决的办法: https://github.com/googleprojectzero/winafl/issues/184

方法一:
git clone https://github.com/googleprojectzero/winafl
cd winafl
git submodule update --init --recursive //即可将子模块内容下载下来后工程才不会缺少相应的文件

方法二:
//加上 --recursive 参数。它会自动初始化并下载每一个子模块,包括第三方的库文件
git clone --recursive https://github.com/googleprojectzero/winafl

2. winafl 的 x64 版本

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC>vcvarsall.bat amd64_x86

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC>cd C:\my_winafl_fuzz\winafl

C:\my_winafl_fuzz\winafl>md b64 && cd b64

C:\my_winafl_fuzz\winafl\b64>cmake -G"Visual Studio 12 2013" -A x64 .. -DDynamoRIO_DIR=C:\my_winafl_fuzz\dynamorio-release_7.1.0\build64\cmake
// cmake -G"Visual Studio 12 2013 Win64" .. -DDynamoRIO_DIR=C:\my_winafl_fuzz\dynamorio-release_7.1.0\build64\cmake

C:\my_winafl_fuzz\winafl\b64>cmake --build . --config Release

编译完成后:

6. 测试 DynamoRIO 和 winafl


官方的使用文档,主要是DynamoRIO插桩参数和winafl运行参数的说明
https://github.com/googleprojectzero/winafl/blob/master/readme_dr.md

1. DynamoRIO 是否编译后可用

winafl 动态插桩是调用DynamoRIO 下的 “drrun.exe” 进行的。我们可以简单使用”drrun.exe”来获取目标程序执行过程中所加载的模块,从而推断DynamoRIO编译是成功并可用的,这也是官方教程里的做法。

任意找一个bmp格式的图片放到上面我们编译后的winafl\b32\bin\Release目录下。然后运行下面命令:

C:\my_winafl_fuzz\dynamorio-release_7.1.0\build32\bin32\drrun.exe -c winafl.dll -debug -target_module test_gdiplus.exe -target_method main -fuzz_iterations 10 -nargs 2 -- test_gdiplus.exe input.bmp

显示报错了,官方的说法是这样的,-target_method main 这里没有找到,是由于没有目标程序的调试符号文件。所以解决的办法,就是用 target_offset 替换掉 target_method,或者编译的使用生成调试符号:

https://github.com/googleprojectzero/winafl/issues/199

// target_offset 替换掉 target_method 后的命令
C:\my_winafl_fuzz\dynamorio-release_7.1.0\build32\bin32\drrun.exe -c winafl.dll -debug -target_module test_gdiplus.exe -target_offset 0x10D0 -fuzz_iterations 10 -nargs 2 -- test_gdiplus.exe input.bmp

对 “drrun.exe” 参数说明。

// 1. 后面跟 <客户端> <客户端 参数> —(分割线) <目标程序 和 目标程序参数>
-c <client> [client options] — <app and args to run>
// 2.1 winafl.dll 参数说明。这也是插桩参数的使用[instrumentation options]
-debug # debug模式, 它会生成一个log文件
-target_module # 目标程序(只能有一个), 也是target_offset所在的模块
-target_offset # 目标程序偏移,相对于target_module的偏移,在method无法导出的时候使用
-fuzz_iterations # 目标程序重新启动一次内运行目标函数(即target_method)的最大迭代数
-nargs # 目标程序执行所需要的参数个数(包括目标程序本身)
-target_module # 目标函数,需要export或者调试符号(pdb)
-coverage_module # 计算覆盖率的模块,也就是目标程序会调用的模块(dll); (可以有多个)

可以看到我写的是-target_offset 0x10D0 ,而官网写的是-target_offset 0x16e0,这里是因为我的系统是win7_x64环境,所以编译出来的程序的地址就会有所不同;不管怎么说,还是以IDA给出的偏移而定。

如果偏移不对,winafl运行时,有时就会出现下列情况:

通过上面的测试,说明我们自己编译的DynamoRIO是没问题的。

2. winafl 是否编译后可用

winafl\b32\bin\Release目录下,分别新建 in、out 文件夹;然后把bmp格式图片放到 in 文件夹下。然后运行下面命令。

afl-fuzz.exe -i in -o out -D C:\my_winafl_fuzz\dynamorio-release_7.1.0\build32\bin32 -t 20000 -- -coverage_module gdiplus.dll -coverage_module WindowsCodecs.dll -fuzz_iterations 5000 -target_module test_gdiplus.exe -target_offset 0x10D0 -nargs 2 -- test_gdiplus.exe @@

这里说明下winafl的参数:

-i        # 存放样本的目录
-o        # 保存输出数据,包括 crash文件、测试用例等
-D        # DynamoRIO的路径 (drrun, drconfig)
-t msec   # 每一次样本执行的超时时间
--        # 分割符
****************************
第一个"--"分割符: 后面跟的是插桩的参数
第二个"--"分割符: 后面跟的是目标程序的参数
****************************

winafl 正常运行:

x64 测试:

// 1. drrun.exe 测试
C:\my_winafl_fuzz\dynamorio-release_7.1.0\build64\bin64\drrun.exe -c winafl.dll -debug -target_module test_gdiplus.exe -target_offset 0x1110 -fuzz_iterations 10 -nargs 2 -- test_gdiplus.exe input.bmp

// 2. winafl 测试
afl-fuzz.exe -i in -o out -D C:\my_winafl_fuzz\dynamorio-release_7.1.0\build64\bin64 -t 20000 -- -coverage_module gdiplus.dll -coverage_module WindowsCodecs.dll -fuzz_iterations 5000 -target_module test_gdiplus.exe -target_offset 0x1110 -nargs 2 -- test_gdiplus.exe @@

7. 总结


按上文的步骤操作,我们就完成了winafl的整个编译。当然了,也可以直接使用官网编译好的,如果大家是在win10下编译的,就需要注意cmake、DynamoRIO的版本问题了,会出现编译不过、兼容性等问题,这些github上都有解决的办法。

再来说说我对winafl的看法,winafl给我的感觉整体上是有好有坏的,它设计的思维肯定是新颖的,但有一点局限性,体现在如果fuzzing的目标程序,没有函数导出表(dll)、不接受命令行参数、源代码也没有、环境变量也不调用的话,就很难fuzzing。解决的办法就只有hook和逆向,只是相对来说比较麻烦一点而已,但是在半自动化fuzz测试工具则已经很优秀了。由于篇幅有限,遗传算法、bitmap算法、插桩机制、管道通信fuzzing模型在这里都没有涉及,这也是afl-fuzz在设计时,最新颖的四大模型。后续我将进行更多的详细解说,大家敬请期待吧~~

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多