返回
顶部

references:

  • https://bushido-sec.com/index.php/2023/06/25/the-art-of-fuzzing-windows-binaries/

windows下的闭源二进制文件灰盒测试,所谓闭源,就是说我们没有待测试二进制文件的源代码,闭源测试很麻烦,所以搞这个的人比较少,然后能他人之所不能,即是我们自身价值的体现,进行这种类型的模糊测试,我们需要克服以下挑战:

  • 插桩
  • 定位值得被fuzz的函数
  • 修改二进制文件使得其能够被fuzz

我们将会使用WinAFL作为我们的fuzz工具,WinAFL提供了三种插桩方式:

  • DynamoRIO,在二进制运行过程中对代码进行修改
  • Syzygy,静态插桩,在二进制编译阶段修改代码
  • Intel PTrace,硬件追踪,这个是CPU的一个特性,可以以异步的方式跟踪程序执行流

这三种方式各有优劣,我们将主要使用DynamoRIO,DynamoRIO和WinAFL的配合流程如下图所示:

img

编译WinAFL

    1. 下载DynamoRIO,最新版本二进制文件下载地址
    1. 如果你需要Intel PTrace支持,你需要在WinAFL源代码目录下执行如下命令:git submodule update --init --recursive
    1. 打开VS Command Prompt(VS 2022)
    1. 进入WinAFL源码目录
    1. 输入如下命令进行构建:

    mkdir build64 cd build64 cmake -G "Visual Studio 17 2022" -A x64 .. -DDynamoRIO_DIR=C:\Users\x\Downloads\DynamoRIO-Windows-11.90.20133\cmake -DINTELPT=1 -DUSE_COLOR=1 cmake --build . --config Release

寻找要Fuzz的目标

一个比较有效的方法是在ZDI网站上寻找目标,特别是那种以前出过洞且仍然处于活跃状态的项目

修改程序,使得程序可以被fuzz

有些程序会有一些烦人的弹窗,这个时候我们就需要把这些弹窗给patch掉,省得他影响我们的fuzz工具

这里有一个示例程序,解压密码是bushido

image-20250302141430698

这个双击运行之后有一个弹窗,我们需要patch掉这个弹窗,在ida里面打开这个程序,搜索字符串Click Yes or No

image-20250302141758137

我们就直接把这个函数的第一个字节修改成c3,让他直接返回就行了,反正他的caller也不检查返回值

选中要修改的地址,直接patch,然后点击Apply patches to input file应用修改即可

image-20250302141945784

我好像不能直接这样改,我这样改好像把他的栈给损坏了,但是我又不知道我是怎么损坏了他的栈的,这x86的程序好操蛋啊,我都不知道他的calling convention是啥

写了个测试程序,x86的calling convention是这个样子的

image-20250302143802888

说白了,就是倒序push

观察这个地方

image-20250302144034328

可以看到,在call完test函数之后,会使用add esp, 0x18来修复栈,因为我们前面push了6个dword进去,一个DWORD是4bytes,6个正好就是0x18 bytes,我们之前直接把函数修改为ret导致没有人修复栈,所以在最后main函数中返回的时候就崩溃了

不对啊,我修改的是里面按理说对外面的代码是没有影响的呀卧槽

我刚才又仔细调试了一下示例代码,发现我们patch的程序修复了栈,所以我们直接把这个程序修改为ret,会导致最终的main函数在返回时崩溃,所以我们需要换一种patch方式

我们可以将这个函数中的call指令全部修改为nop指令,我靠,这么改也不行,还是会崩溃

仔细观察该函数,发现他最后的返回指令是

image-20250302145950503

就是这条指令修复了栈,我们直接从函数开始的地方复改为者3个字节即可

这下可以了,不崩溃了,栈平衡了,我们再来看一下原作者是怎么patch的

原作者是直接把call 401000替换成nop了,他这样肯定会在返回的时候崩溃,因为这个函数负责平衡栈,没有了这个函数栈就不可能是平衡的

我试了一下,确实是会崩溃