winafl fuzz 工具的使用

0. 下载 Visual Studio Community 2022

下载地址:https://aka.ms/vs/17/release/vs_community.exe

从微软网站下载并安装 Visual Studio Community 的时候速度只有2 K,一下午没能下载成功。咨询同事小钻风,指出可能是 DNS 问题,将 DNS 切换成阿里的 DNS 223.5.5.5 后下载速度达到 4 M。中国开发者网络总是个问题,大家都挺不容易的。

1. 编译 winafl

  1. 下载 DynamoRIO,https://github.com/DynamoRIO/dynamorio/releases/download/cronbuild-9.0.19209/DynamoRIO-Windows-9.0.19209.zip 解压到 D:\DynamoRIO
  2. 下载 cmake,https://github.com/Kitware/CMake/releases/download/v3.24.0/cmake-3.24.0-windows-x86_64.zip 解压到 D:\cmake
  3. 从 Github 下载 winafl 源码 https://github.com/googleprojectzero/winafl.git , 编译 intel PT 需要同步 third_party 的源码
1
2
3
git clone https://github.com/googleprojectzero/winafl.git
cd winafl
git submodule update --init --recursive
  1. 从菜单中选择 X64 native tool command prompt for VS 2022,执行编译命令
1
2
3
4
mkdir build64
cd build64
D:\cmake\bin\cmake.exe -G"Visual Studio 17 2022" -A x64 .. -DDynamoRIO_DIR=D:\DynamoRIO\cmake -DINTELPT=1
D:\cmake\cmake.exe --build . --config Release

-DINTelPT=1 参数将编译 Intel PT 模式的支持,编译完成后,可以正常运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
.\build64\bin\Release>.\afl-fuzz.exe

WinAFL 1.16b by <ifratric@google.com>
Based on AFL 2.43b by <lcamtuf@google.com>

.\afl-fuzz.exe [ afl options ] -- [instrumentation options] -- \path\to\fuzzed_app [ ... ]

Required parameters:

-i dir - input directory with test cases
-o dir - output directory for fuzzer findings
-t msec - timeout for each run

Instrumentation type:

-D dir - directory with DynamoRIO binaries (drrun, drconfig)
-w winafl - Path to winafl.dll
-P - use Intel PT tracing mode
-Y - enable the static instrumentation mode

Execution control settings:

-f file - location read by the fuzzed program (stdin)
-m limit - memory limit for the target process
-p - persist DynamoRIO cache across target process restarts
-c cpu - the CPU to run the fuzzed program

Fuzzing behavior settings:

-d - quick & dirty mode (skips deterministic steps)
-n - fuzz without instrumentation (dumb mode)
-x dir - optional fuzzer dictionary (see README)

Other stuff:

-I msec - timeout for process initialization and first run
-T text - text banner to show on the screen
-M \ -S id - distributed mode (see parallel_fuzzing.txt)
-C - crash exploration mode (the peruvian rabbit thing)
-e - expert mode to run WinAFL as a DynamoRIO tool
-l path - a path to user-defined DLL for custom test cases processing
-V - show version number and exit

Attach:

-A module - attach to the process that loaded the provided module

For additional tips, please consult afl_docs\README.


C:\Users\zhouzhen\Downloads\winafl\build64\bin\Release>

2. 检查 DynamoRIO 模式是否正常工作

使用 IDA Pro 对 test_gdiplus.exe 进行反汇编,target_offset 为 0x10E0

1
2
3
.text:00000001400010E0 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000001400010E0 main proc near ; CODE XREF: __scrt_common_main_seh(void)+107↓p
.text:00000001400010E0 ; DATA XREF: .rdata:0000000140002B6C↓o ...

先用 drrun.exe 测试 winafl 是否正常工作,其实就是循环执行 10 次目标程序。

1
2
3
D:\DynamoRIO\bin64\drrun.exe -c winafl.dll -debug ^
-target_module test_gdiplus.exe -target_offset 0x10E0 -fuzz_iterations 10 ^
-nargs 2 -- test_gdiplus.exe input.bmp

执行命令后,在当前目录下会生成一个 log 文件,文件名为 afl.test_gdiplus.exe.14172.0000.proc.log,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Module loaded, dynamorio.dll
Module loaded, winafl.dll
Module loaded, drx.dll
Module loaded, drreg.dll
Module loaded, drmgr.dll
Module loaded, drwrap.dll
Module loaded, test_gdiplus.exe
Module loaded, gdiplus.dll
Module loaded, VCRUNTIME140.dll
Module loaded, msvcp_win.dll
Module loaded, win32u.dll
Module loaded, ucrtbase.dll
Module loaded, KERNELBASE.dll
Module loaded, gdi32full.dll
Module loaded, KERNEL32.dll
Module loaded, msvcrt.dll
Module loaded, IMM32.dll
Module loaded, RPCRT4.dll
Module loaded, GDI32.dll
Module loaded, combase.dll
Module loaded, USER32.dll
Module loaded, ntdll.dll
In pre_fuzz_handler
Module loaded, UxTheme.dll
Module loaded, OLEAUT32.dll
Module loaded, bcrypt.dll
Module loaded, SECHOST.dll
Module loaded, ADVAPI32.dll
Module loaded, WindowsCodecs.dll
Module loaded, MSCTF.dll
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
In pre_fuzz_handler
In post_fuzz_handler
Everything appears to be running normally.
Coverage map follows:

Everything appears to be running normally. 表明 winafl 自己认为没有出错。 log 文件中还包含了其他有用信息,比如说目标程序加载的模块。这些加载的模块可以用来设置 -coverage_module来统计你所关注的 coverage。

使用 drrun.exe 验证成功后,可以执行下面命令测试 winafl 是否正常工作。

1
2
3
cmd > afl-fuzz.exe -i in -o out -D D:\DynamoRIO\bin64 -t 20000 ^
-- -coverage_module gdiplus.dll -coverage_module WindowsCodecs.dll -fuzz_iterations 5000 ^
-target_module test_gdiplus.exe -target_offset 0x10E0 -nargs 2 -- test_gdiplus.exe @@

执行后上面的命令后,如果发现 total paths 的数字在不断变化, winafl 就已经可以正常工作了,恭喜 😄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
+- process timing -------------------------------------+- overall results ----+
| run time : 0 days, 0 hrs, 0 min, 1 sec | cycles done : 0 |
| last new path : 0 days, 0 hrs, 0 min, 1 sec | total paths : 2 |
| last uniq crash : none seen yet | uniq crashes : 0 |
| last uniq hang : none seen yet | uniq hangs : 0 |
+- cycle progress --------------------+- map coverage -+----------------------+
| now processing : 0 (0.00%) | map density : 1.65% / 1.65% |
| paths timed out : 0 (0.00%) | count coverage : 1.00 bits/tuple |
+- stage progress --------------------+ findings in depth --------------------+
| now trying : arith 8\8 | favored paths : 1 (50.00%) |
| stage execs : 388/389 (99.74%) | new edges on : 2 (100.00%) |
| total execs : 619 | total crashes : 0 (0 unique) |
| exec speed : 353.3/sec | total tmouts : 0 (0 unique) |
+- fuzzing strategy yields -----------+---------------+- path geometry -------+
| bit flips : 0/56, 1/55, 0/53 | levels : 2 |
| byte flips : 0/7, 0/6, 0/4 | pending : 2 |
| arithmetics : 0/0, 0/0, 0/0 | pend fav : 1 |
| known ints : 0/0, 0/0, 0/0 | own finds : 1 |
| dictionary : 0/0, 0/0, 0/0 | imported : n/a |
| havoc : 0/0, 0/0 | stability : 99.63% |
| trim : 0.00%/1, 0.00% +-----------------------+
^C----------------------------------------------------+ [cpu000001: 14%]

3. DynamoRIO 模式 winafl.dll 各个参数的具体含义

winafl.dll 是 DynamoRIO client (instrumentation) code,参数挺多 Winafl 的 README 中介绍了下面这些参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-covtype         - the type of coverage being recorded. Supported options are
bb (basic block, default) or edge.

-coverage_module - module for which to record coverage. Multiple module flags
are supported.

-target_module - module which contains the target function to be fuzzed.
Either -target_method or -target_offset need to be
specified together with this option.

-target_method - name of the method to fuzz in persistent mode. For this to
work either the method needs to be exported or the symbols
for target_module need to be available. Otherwise use
-target_offset instead.

-target_offset - offset of the method to fuzz from the start of the module.

-fuzz_iterations - Maximum number of iterations for the target function to run
before restarting the target process.

-nargs - Number of arguments the fuzzed method takes. This is used
to save/restore the arguments between runs.

-call_convention - The default calling convention is cdecl on 32-bit x86
platforms and Microsoft x64 for Visual Studio 64-bit
applications. Possible values:
* fastcall: fastcall
* ms64: Microsoft x64 (Visual Studio)
* stdcall: cdecl or stdcall
* thiscall: thiscall

-debug - Debug mode. Does not try to connect to the server. Outputs
a log file containing loaded modules, opened files and
coverage information.

-logdir - specifies in which directory the log file will be written
(only to be used with -debug).

-thread_coverage - If set, WinAFL will only collect coverage from a thread
that executed the target function
  • -nargs target method 或者 target offset 的参数个数
  • -fuzz_iterations 重启进程前,循环执行 target method 或者 target offset 的次数
  • -target_moudle fuzz 的目标模块,需要和 target method 或者 target offset 一起使用
  • -target_method persistent mode 下 fuzz 的函数名(方法名),需要有符号 (symbols)
  • -target_offset fuzz 的函数(方法)相对于模块起始地址的偏移
  • -coverage_module 统计覆盖率的模块,可以统计多个模块的 coverage,即指定多个 -coverage_module 参数
  • -covtype bb 或者 edge,bb (basic block 为默认值)
  • -thread_coverage 用于多线程程序,只统计一个线程执行 target function 的覆盖率变化

4. WinAFL intel PT 模式使用

Intel PT (Processor Tracing) 是 Intel CPU 的一个特性,从 Intel 第5代处理器开始支持,5th generation 的微架构为 Broadwell。相关说明可以参考:https://www.intel.com/content/www/us/en/support/articles/000056730/processors.html

Windows 10 从 v1809 开始提供了 Intel PT 的驱动,但目前没有公开的文档描述此驱动,也没有提供官方的 API。 Alex Ionescu 提供了 winipt library 和 Intel PT 驱动交互,WinAFL 利用 winipt 来获得 Intel PT 的 Processo Tracing 信息。

WinAFL 使用 Intel PT 模式,和 DynamoRIO 不同需要指定 -P , WinAFL Intel PT 模式除了和DynamoRIO 相同的参数外额外添加了下面几个参数:

  • -trace_size 每次执行 traget 手机的 trace 信息的字节数,必须是2 的次方并且大于 4096
  • -decode 处理 trace 信息的解码器,有三个可选值:tip, tip_reffull (full 为默认值)
  • -nopersistent_trace 由于性能的缘故,WinAFL 每次循环执行 target 是不重启程序,这个选项可以强制 WinAFL 每次执行 target 都重启,一般是为了调试才会启用这个选项
  • -trace_cache_size trace 信息的 cache 字节数,和 full 解码器一起使用

5 检查 Intel PT 模式是否正常工作

1
2
winaflpt-debug.exe -debug -coverage_module test_gdiplus.exe -fuzz_iterations 10 ^
-target_module test_gdiplus.exe -target_offset 0x10E0 -nargs 2 -- test_gdiplus.exe @@

上面命令其实和检查 DynamoRIO 模式是否正常工作的命令基本一直,执行命令后输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Module loaded: test_gdiplus.exe
Module loaded: ntdll.dll
Module loaded: KERNEL32.DLjL
Module loaded: KERNELBASE.dll
Module loaded: ucrtbase.dll
Module loaded: gdiplus.dll
Module loaded: msvcrt.dll
Module loaded: combase.dll
Module loaded: VCRUNTIME140.dll
Module loaded: RPCRT4.dll
Module loaded: USER32.dll
Module loaded: win32u.dll
Module loaded: GDI32.dll
Module loaded: gdi32full.dll
Module loaded: msvcp_win.dll
Module loaded: IMM32.DLL
iteration 0
Module loaded: uxtheme.dll
Module loaded: msctf.dll
Module loaded: oleaut32.dll
Module loaded: sechost.dll
Iteration finished normally
iteration 1
Iteration finished normally
iteration 2
Iteration finished normally
iteration 3
Iteration finished normally
iteration 4
Iteration finished normally
iteration 5
Iteration finished normally
iteration 6
Iteration finished normally
iteration 7
Iteration finished normally
iteration 8
Iteration finished normally
iteration 9
Iteration finished normally
Coverage map (hex):
00000000000000000000000000000000
00000000000000000000000000000000

6. 用 Intel PT 模式 fuzz

1
afl-fuzz.exe -i in -o out -P -t 20000 -- -coverage_module test_gdiplus.exe -fuzz_iterations 10 -target_module test_gdiplus.exe -target_offset 0x10E0 -nargs 2 -- test_gdiplus.exe @@

用上面的命令调用 afl-fuzz,发现可以正常工作,界面如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

WinAFL 1.16b based on AFL 2.43b (test_gdiplus.exe)

+- process timing -------------------------------------+- overall results ----+
| run time : 0 days, 0 hrs, 0 min, 13 sec | cycles done : 10 |
| last new path : none yet (odd, check syntax!) | total paths : 1 |
| last uniq crash : none seen yet | uniq crashes : 0 |
| last uniq hang : none seen yet | uniq hangs : 0 |
+- cycle progress --------------------+- map coverage -+----------------------+
| now processing : 0 (0.00%) | map density : 0.04% / 0.04% |
| paths timed out : 0 (0.00%) | count coverage : 1.07 bits/tuple |
+- stage progress --------------------+ findings in depth --------------------+
| now trying : havoc | favored paths : 1 (100.00%) |
| stage execs : 48/128 (37.50%) | new edges on : 1 (100.00%) |
| total execs : 2207 | total crashes : 0 (0 unique) |
| exec speed : 160.8/sec | total tmouts : 0 (0 unique) |
+- fuzzing strategy yields -----------+---------------+- path geometry -------+
| bit flips : 0/32, 0/31, 0/29 | levels : 1 |
| byte flips : 0/4, 0/3, 0/1 | pending : 0 |
| arithmetics : 0/222, 0/2, 0/0 | pend fav : 0 |
| known ints : 0/19, 0/102, 0/40 | own finds : 0 |
| dictionary : 0/0, 0/0, 0/0 | imported : n/a |
| havoc : 0/1664, 0/0 | stability : 100.00% |
| trim : 42.86%/1, 0.00% +-----------------------+
^C----------------------------------------------------+ [cpu000001: 18%]

参考资料

https://github.com/googleprojectzero/winafl/blob/master/README.md
https://github.com/googleprojectzero/winafl/blob/master/readme_dr.md
https://github.com/googleprojectzero/winafl/blob/master/readme_pt.md