本文最后更新于 2022年12月14日 凌晨
下载地址: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
下载 DynamoRIO 解压到 D:\DynamoRIO
下载 cmake 解压到 D:\cmake
从 Github 下载 winafl 编译 intel PT 需要同步 third_party 的源码
1 2 3 git clone https://github.com/googleprojectzero/winafl.gitcd winafl git submodule update --init --recursive
从菜单中选择 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\bin\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.16 b by <ifratric@google.com> Based on AFL 2.43 b by <lcamtuf@google.com> .\afl-fuzz.exe [ afl options ] 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 0 x10E0 -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 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_ref
和 full
(full 为默认值)
-nopersistent_trace
由于性能的缘故,WinAFL 每次循环执行 target 是不重启程序,这个选项可以强制 WinAFL 每次执行 target 都重启,一般是为了调试才会启用这个选项
-trace_cache_size
trace 信息的 cache 字节数,和 full
解码器一起使用
5. 检查 Intel PT 模式是否正常工作 1 2 winaflpt-debug.exe -debug -coverage_module gdipluss.dll -coverage_module WindowsCodecs.dll ^ -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 2 3 afl-fuzz.exe -i in -o out -P -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 @@
用上面的命令调用 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, 15 sec | cycles done : 0 | | last new path : 0 days, 0 hrs, 0 min, 1 sec | total paths : 9 | | 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.50% / 3.67% | | paths timed out : 0 (0.00%) | count coverage : 1.40 bits/tuple | +- stage progress --------------------+ findings in depth --------------------+ | now trying : havoc | favored paths : 1 (11.11%) | | stage execs : 2332/8192 (28.47%) | new edges on : 5 (55.56%) | | total execs : 3350 | total crashes : 0 (0 unique) | | exec speed : 221.4/sec | total tmouts : 0 (0 unique) | +- fuzzing strategy yields -----------+---------------+- path geometry -------+ | bit flips : 0/48, 0/47, 1/45 | levels : 2 | | byte flips : 0/6, 0/5, 0/3 | pending : 9 | | arithmetics : 1/335, 0/75, 0/0 | pend fav : 1 | | known ints : 0/28, 1/168, 1/120 | own finds : 8 | | dictionary : 0/0, 0/0, 0/0 | imported : n/a | | havoc : 0/0, 0/0 | stability : 65.28% | | trim : 0.00%/1, 0.00% +-----------------------+ +-----------------------------------------------------+ [cpu000001: 23%]
7. Winafl 的多核使用情况 执行 Winafl 的 PT 模式,使用任务管理器 -> 打开资源监视器 -> CPU 可以观察到只有一个 CPU core 跑满 100%
参考资料 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