# Autoit辅助winafl对GUI程序fuzz ## 前言 对图形界面程序的模糊测试无外乎以下这三种方法(以下为仅使用afl/winafl的): 1.针对有源码的可以进行patch使其跳过界面显示阶段直接结束。(可参考:[Fuzzing Linux GUI/GTK Programs With American Fuzzy Lop](https://blog.hyperiongray.com/fuzzing-gtk-programs-with-american-fuzzy-lop-afl/) ) 2.针对无源码的可以写harness。(可参考:[50 CVEs in 50 Days: Fuzzing Adobe Reader](https://research.checkpoint.com/50-adobe-cves-in-50-days/)) 3.通过监控被fuzz的GUI程序在一定时间内将其kill掉。 本文属于第三种方法,但通过Autoit进行辅助可以拓展出更加丰富的功能而不局限于仅仅将被fuzz程序关闭。 ## Autoit简介 AutoIt是一个用于Windows的自动化语言。它兼容于Windows 95,98,ME,NT4,2000,XP,2003,Vista以及Windows 7。AutoIt自动化脚本可以编译成压缩、单一的可执行文件,这样的文件可以运行在没有安装AutoIt解释器的计算机上。 部分功能:**调用Win32 DLL中的函数、模拟鼠标移动、操作窗口和进程、自动发送用户输入和键击到应用程序以及程序中的单个控件、**运行控制台应用程序和访问标准流、包含文件在编译文件中以便在运行时提取、GUI接口,创建消息和输入框、支持COM。 ## 最初的思路 一开始的思路是使用Autoit的**Run**或者**ShellExecute**函数执行被fuzz函数通过发送快捷键或者结束进程的方式将其关闭,将脚本打包成exe,这样用winafl去fuzz被打包过的exe。但实际测试过程中发现winafl只会记录打包的exe的代码覆盖率。被fuzz程序实际上是以子进程的形式去运行。翻看winafl的issue发现作者的[这样一段话](https://github.com/googleprojectzero/winafl/issues/74#issuecomment-354142563): ``` DynamoRIO does indeed instrument child processes by default, but this is disabled in WinAFL here: https://github.com/ivanfratric/winafl/blob/master/afl-fuzz.c#L2089 (note the -no_follow_children flag). The main reason is communication of target process and afl-fuzz: Target process needs to connect to a pipe and shared memory exposed by afl-fuzz. IIRC this led to problems in the past when multiple processes attempted to connect to the same pipe/shared memory and I put -no_follow_children to fix that. A possible alternative could be to only connect to pipe/shm once the target function is reached (and hope it's only going to get reached in 1 process). Not sure if this would result in some other problems, difficult to say off the top of my head. ``` 由于winafl使用管道与目标进程进行通信,多个进程同时连接同一管道会出现问题。 ## 最后实现的方法 使用Autoit的 [WinWait](https://www.autoitscript.com/autoit3/docs/functions/WinWait.htm) 函数监控被fuzz程序的主窗口类,捕获主窗口类后可以对其发送快捷键或鼠标点击事件,之后再对其关闭。实现脚本如下: ```autoit #include While True Local $hWnd = WinWait("[CLASS:Notepad]") If WinActive($hWnd) Then Sleep(1000) Send("{ESC}") WinClose($hWnd) EndIf WEnd ``` 但这个脚本存在一个问题,若其他程序主窗口类名和其相同也会被捕获从而造成干扰,在查阅autoit文档后改进如下: ```autoit #cs ---------------------------------------------------------------------------- AutoIt Version: 3.3.14.5 Author: 1vanChen Name: fuzzHelper Script Function: Get target program window class Open target program and close it automatically Usage: Find target program window class (make sure the program is running): fuzzHelper.exe programName.exe Open target program and close it automatically: fuzzHelper.exe ProgramName.exe WindowClsName #ce ---------------------------------------------------------------------------- #include #include #include #include #pragma compile(Console, True) If $CmdLine[0]==2 Then While True Local $hWnd = _WinGetHandleByPnmAndCls($CmdLine[1],$CmdLine[2]) If WinActive($hWnd) Then Sleep(500) ;此处只是发送"关闭"这个快捷键, ;还可以根据需要添加其他要发送的快捷键 Send("{ESC}") WinClose($hWnd) EndIf WEnd ElseIf $CmdLine[0]==1 Then Local $pid = ProcessExists($CmdLine[1]) If $pid Then _WinGetWindowClsByPid($pid) Else MsgBox($MB_SYSTEMMODAL, "", "程序未找到") EndIf EndIf ; 根据pid打印该程序所有窗口类 Func _WinGetWindowClsByPid ($pid ) Local $winArr = _WinAPI_EnumWindowsTop() For $i=1 To $winArr[0][0] If $pid=WinGetProcess($winArr[$i][0])Then ConsoleWrite($winArr[$i][1] & @CRLF) EndIf Next EndFunc ; 根据pname和class获取窗口句柄,找不到则返回0 Func _WinGetHandleByPnmAndCls($pname, $class) Local $pid = ProcessExists($pname) If $pid Then return _WinGetHandleByPidAndCls($pid, $class) Else Return 0 EndIf EndFunc ; 根据pid和class获取窗口句柄,找不到则返回0 Func _WinGetHandleByPidAndCls($pid, $class) Local $winArr = _WinAPI_EnumWindowsTop() For $i=1 To $winArr[0][0] If $pid=WinGetProcess($winArr[$i][0]) And $winArr[$i][1]=$class Then return $winArr[$i][0] EndIf Next Return 0 EndFunc ``` 该脚本可以直接运行也可以打包成exe,有两个功能: 1.在打开被fuzz程序的形况下运行:`fuzzHelper.exe programName.exe`列出被fuzz程序窗口类。 2.在启动winafl前运行: `fuzzHelper.exe ProgramName.exe WindowClsName`捕获被fuzz程序窗口类并执行相应操作。 ## 总结 这种方式最大的优势在于不需要对程序进行任何前期逆向工作,无脑fuzz。缺点在于由于需要加载图形界面或者执行相应操作,fuzz过程会变得异常缓慢,我在测试的时候一个test case大约需要2秒。目前可以想到的提升速度的方法有:多核fuzz、虚拟机cpu加速、移植论文中改进的变异算法...但终究和写harness这种在速度上不是一个数量级的。 在fuzz中减少人工投入还是有很长的路要走... ## 参考链接 https://www.autoitscript.com/autoit3/docs/ https://autoit8.com/Doc/ https://blog.csdn.net/moonshine_1988/article/details/48006043