首页
社区
课程
招聘
[原创] Fuzz 工具 WinAFL 的使用感受 - 对 FreeImage 图片解析库进行模糊测试 ^_^
发表于: 2019-10-23 01:46 18053

[原创] Fuzz 工具 WinAFL 的使用感受 - 对 FreeImage 图片解析库进行模糊测试 ^_^

2019-10-23 01:46
18053

本次测试只是简单的 Fuzzing 了一下 ABC 看图软件的加载图片功能,但是效果并不是很理想。由于时间比较紧张,错误在所难免,请勿喷

  • AFL 介绍
众所周知模糊测试是发掘软件 Bug 最有用的方法之一,AFL 就是在这个背景下发展起来的。从原理上来说 AFL 通过变异软件输入的数据来进行软件 Bug 挖掘,与一些模糊测试器不同的是 AFL 变异数据的方法是通过覆盖率算法来实现的,而不是通过格式,虽然前者效率高但是也有缺点,详情可以看看 Black Hat 2019 超越覆盖率指导的模糊测试。


  • 对图片解析软件进行模糊测试
对图片解析库进行模糊测试的前提是找到一款可以读取图片格式的软件,百度搜索了一下觉得 ABC 这个软件不错,因为它能读取很多格式的图片,包括 TIFF 图片,但是测试时并不需要这么多,因为根本没那么多时间(说实话它的官网有点搞笑)。
  • 对图片解析软件进行模糊测试
对图片解析库进行模糊测试的前提是找到一款可以读取图片格式的软件,百度搜索了一下觉得 ABC 这个软件不错,因为它能读取很多格式的图片,包括 TIFF 图片,但是测试时并不需要这么多,因为根本没那么多时间(说实话它的官网有点搞笑)。


下载完成之后转到这个看图软件的根目录,由于尚未进行 RCE,所以只能从名称和日志信息上猜测各个模块的功能,等到以后再验证。比如 skinbox 模块可能是换肤功能,KTUpdateDownlaoder 模块可能是下载更新功能,PhotoManage 打开之后是一个路径下寻找图片的功能,PhotoViewer 不同说了肯定是查看图片格式的,Service 模块可能是获取服务器信息的,以及其他一些杂七杂八的。对于动态链接库来说 FreeImage 模块可能是读取图片格式的,Free 说明它是免费的,极有可能是一个公开的库,Imgdecoder-gdip 貌似是解码库或者图形库,ShellExt 应该与执行命令有关,有意思的是这个软件还用到了 sqlite3 的内置小型数据库,不知道它要储存什么。
下载完成之后转到这个看图软件的根目录,由于尚未进行 RCE,所以只能从名称和日志信息上猜测各个模块的功能,等到以后再验证。比如 skinbox 模块可能是换肤功能,KTUpdateDownlaoder 模块可能是下载更新功能,PhotoManage 打开之后是一个路径下寻找图片的功能,PhotoViewer 不同说了肯定是查看图片格式的,Service 模块可能是获取服务器信息的,以及其他一些杂七杂八的。对于动态链接库来说 FreeImage 模块可能是读取图片格式的,Free 说明它是免费的,极有可能是一个公开的库,Imgdecoder-gdip 貌似是解码库或者图形库,ShellExt 应该与执行命令有关,有意思的是这个软件还用到了 sqlite3 的内置小型数据库,不知道它要储存什么。


从 exe 后缀的模块来看,该软件的功能还是十分的多的,甚至包括了 Pdf 的阅读功能。


使用搜索引擎查了一番之后发现 FreeImage 库果然是一个公开的库,专门用来处理图片的,并且有五年的历史。下面主要的逆向工程工作就放在这个上面就行了。




既然你是一个公开的库并且版本不是最新的 3.18.0,那么肯定要查一下漏洞库有没有记录,假如一个漏洞都没有的话那么就没有对它进行模糊测试的必要了。搜索了一下发现全是洞,以堆栈溢出为主。估计下面进行模糊测试的时候会找出一些旧 Bug。


下面对 FreeImage 库进行逆向分析:首先拖入 IDA,发现这个库导出的函数巨多,但是并不是所有函数都会被 PhotoViewer 调用到,并且有些导出函数中会调用一堆导出函数(名称相似的情况下参数少的调用参数多的,当然这个只是经验判断,有时候并不一定是这样)。


从 Get 函数上来看,许多都与获取图片信息有关,比如 GetColorType 获取图片颜色类型,GetFileType 获取图片格式,GetInfo 获取图片格式信息等等。


继续在导出函数中查找,发现了一些重要的信息:FreeImage_Convert* 应该是负责数据位数转换的,FreeImage_Allocate* 表示进行了内存操作,FreeImage_Load* 载入数据,FreeImage_*Tag* 负责标签操作。





傻瓜式的静态分析到此结束,接着使用动态分析,在此之前我已经在网络上收集了各式各样的图片,包括 BMP、JPG、TIFF。使用 DynamoRIO 的 drcov 覆盖率查询工具扫一下,看看调用了 FreeImage 的哪些函数。命令如下:
 DynamoRIO-7.0.0\bin32> drrun.exe -t drcov -- [需要测试的程序/模块名] [程序/模块传入的参数]



傻瓜式的静态分析到此结束,接着使用动态分析,在此之前我已经在网络上收集了各式各样的图片,包括 BMP、JPG、TIFF。使用 DynamoRIO 的 drcov 覆盖率查询工具扫一下,看看调用了 FreeImage 的哪些函数。命令如下:
 DynamoRIO-7.0.0\bin32> drrun.exe -t drcov -- [需要测试的程序/模块名] [程序/模块传入的参数]



 DynamoRIO-7.0.0\bin32> drrun.exe -t drcov -- [需要测试的程序/模块名] [程序/模块传入的参数]



从被执行的函数中可以看出调用了内存操作函数、数据格式转换函数、拷贝函数、初始化函数、标签操作函数以及加载函数等。





从覆盖率上看 ABC 看图软件调用了约 4.26% 的 FreeImage 库函数代码,说明 FreeImage 可以解析的图片格式还是非常的多。


用 windbg 看一下调用函数的顺序,以便编写测试文件用来进行模糊测试。读取的图片为 jpg 格式,命令如下:
 .logopen E:\log.txt
 lmm FreeImage
 x FreeImage*
 bm FreeImge!FreeImage* ".echo; kb 1; g"

通过 python 脚本筛选出如下结果,总体可以概括为使用 Initialise 函数初始化库,使用一系列的 Get 函数获取图片格式信息,使用 Load 函数加载图片,对图片进行拷贝和获取详细图片信息操作,卸载图片并进行标签操作。至于参数分析就不写了,这个过程比较繁琐,具体可以概括为大部分函数的参数都传入了加载图片函数的返回值(^ _ ^)。

用 windbg 看一下调用函数的顺序,以便编写测试文件用来进行模糊测试。读取的图片为 jpg 格式,命令如下:
 .logopen E:\log.txt
 lmm FreeImage
 x FreeImage*
 bm FreeImge!FreeImage* ".echo; kb 1; g"
 .logopen E:\log.txt
 lmm FreeImage
 x FreeImage*
 bm FreeImge!FreeImage* ".echo; kb 1; g"

通过 python 脚本筛选出如下结果,总体可以概括为使用 Initialise 函数初始化库,使用一系列的 Get 函数获取图片格式信息,使用 Load 函数加载图片,对图片进行拷贝和获取详细图片信息操作,卸载图片并进行标签操作。至于参数分析就不写了,这个过程比较繁琐,具体可以概括为大部分函数的参数都传入了加载图片函数的返回值(^ _ ^)。


经过动态和静态的简单分析后,决定对 FreeImage 库的载入函数、格式转换函数、获取图片信息函数、图片格式判断函数进行模糊测试。至于为什么不包括标签和内存操作函数,因为这个过程属于设置而不是获取,并且是在 PhotoViewer 模块中实现的,而非 FreeImage 模块。那么首先编写的是加载图片和获取图片信息的功能,测试代码如下:
/*
	test.exe
*/
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h> 
#include <tchar.h>
#include <iostream>
using namespace std;

extern "C" __declspec(dllexport) int main(int argc, char** argv);
void FreeImage_test(HINSTANCE hinstLib, wchar_t* pathfile);
wchar_t* charToWChar(const char* text);

// 加载卸载函数 
typedef DWORD(__stdcall *FreeImage_GetFileTypeU)(const wchar_t* lpszPathName, int flag);
typedef DWORD(__stdcall *FreeImage_Initialise)(BOOL load_local_plugins_only);
typedef DWORD(__stdcall *FreeImage_DeInitialise)();
typedef DWORD(__stdcall *FreeImage_LoadU)(DWORD format, const wchar_t* lpszPathName, int flag);
typedef DWORD(__stdcall *FreeImage_UnLoad)(DWORD dib);

// 获取信息函数
typedef DWORD(__stdcall *FreeImage_GetFIFFromFilenameU)(const wchar_t* lpszPathName); FreeImage_GetFIFFromFilenameU GetFIFFromFilenameU;
typedef DWORD(__stdcall *FreeImage_GetDotsPerMeterX)(DWORD dib); FreeImage_GetDotsPerMeterX GetDotsPerMeterX;
typedef DWORD(__stdcall *FreeImage_GetDotsPerMeterY)(DWORD dib); FreeImage_GetDotsPerMeterY GetDotsPerMeterY;
typedef DWORD(__stdcall *FreeImage_GetTransparencyCount)(DWORD dib); FreeImage_GetTransparencyCount GetTransparencyCount;
typedef DWORD(__stdcall *FreeImage_GetTransparencyTable)(DWORD dib); FreeImage_GetTransparencyTable GetTransparencyTable;
typedef DWORD(__stdcall *FreeImage_GetBlueMask)(DWORD dib); FreeImage_GetBlueMask GetBlueMask;
typedef DWORD(__stdcall *FreeImage_GetRedMask)(DWORD dib); FreeImage_GetRedMask GetRedMask;
typedef DWORD(__stdcall *FreeImage_GetThumbnail)(DWORD dib); FreeImage_GetThumbnail GetThumbnail;
typedef DWORD(__stdcall *FreeImage_GetPalette)(DWORD dib); FreeImage_GetPalette GetPalette;
typedef DWORD(__stdcall *FreeImage_GetGreenMask)(DWORD dib); FreeImage_GetGreenMask GetGreenMask;
typedef DWORD(__stdcall *FreeImage_GetImageType)(DWORD dib); FreeImage_GetImageType GetImageType;
typedef DWORD(__stdcall *FreeImage_GetICCProfile)(DWORD dib); FreeImage_GetICCProfile GetICCProfile;
typedef DWORD(__stdcall *FreeImage_GetBackgroundColor)(DWORD dib); FreeImage_GetBackgroundColor GetBackgroundColor;
typedef DWORD(__stdcall *FreeImage_GetInfo)(DWORD dib);	FreeImage_GetInfo GetInfo;	 	// 不确定的
typedef DWORD(__stdcall *FreeImage_GetFormatFromFIF)(DWORD dib); FreeImage_GetFormatFromFIF GetFormatFromFIF;
typedef DWORD(__stdcall *FreeImage_GetFIFExtensionList)(DWORD dib); FreeImage_GetFIFExtensionList GetFIFExtensionList;
typedef DWORD(__stdcall *FreeImage_GetMetadataCount)(DWORD format, DWORD dib); FreeImage_GetMetadataCount GetMetadataCount;

FreeImage_Initialise Initialise;
FreeImage_GetFileTypeU LoadFileType;
FreeImage_LoadU LoadU; DWORD load;
FreeImage_UnLoad UnLoad;
FreeImage_DeInitialise DeInitialise;

int main(int argc, char** argv)
{
	if (argc < 2) {
		printf("Usage: %s <xml file>\n", argv[0]);
		return 0;
	}
	
	wchar_t* PathName = charToWChar(argv[1]);

	HINSTANCE hinstLib; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; DWORD Error = NULL;
	hinstLib = LoadLibrary(TEXT("E:\\FreeImage.dll"));

	if (hinstLib != NULL)
	{
		fRunTimeLinkSuccess = TRUE;
		
		Initialise = (FreeImage_Initialise)GetProcAddress(hinstLib, (LPCSTR)163); // 初始化 FreeImage 库
		LoadFileType = (FreeImage_GetFileTypeU)GetProcAddress(hinstLib, (LPCSTR)126);// 获取位图文件类型
		LoadU = (FreeImage_LoadU)GetProcAddress(hinstLib, (LPCSTR)181);	// 加载位图
		UnLoad = (FreeImage_UnLoad)GetProcAddress(hinstLib, (LPCSTR)242);// 卸载位图
		DeInitialise = (FreeImage_DeInitialise)GetProcAddress(hinstLib, (LPCSTR)83);//卸载 FreeImage 库
		
		// 获取信息函数
		LoadFileType = (FreeImage_GetFileTypeU)GetProcAddress(hinstLib, (LPCSTR)126);
		GetFIFFromFilenameU = (FreeImage_GetFIFFromFilenameU)GetProcAddress(hinstLib, (LPCSTR)118);
		GetDotsPerMeterX = (FreeImage_GetDotsPerMeterX)GetProcAddress(hinstLib, (LPCSTR)112);
		GetDotsPerMeterY = (FreeImage_GetDotsPerMeterY)GetProcAddress(hinstLib, (LPCSTR)113);
		GetTransparencyCount = (FreeImage_GetTransparencyCount)GetProcAddress(hinstLib, (LPCSTR)155);
		GetTransparencyTable = (FreeImage_GetTransparencyTable)GetProcAddress(hinstLib, (LPCSTR)156);
		GetBlueMask = (FreeImage_GetBlueMask)GetProcAddress(hinstLib, (LPCSTR)105);
		GetRedMask = (FreeImage_GetRedMask)GetProcAddress(hinstLib, (LPCSTR)145);
		GetGreenMask = (FreeImage_GetGreenMask)GetProcAddress(hinstLib, (LPCSTR)128);
		GetThumbnail = (FreeImage_GetThumbnail)GetProcAddress(hinstLib, (LPCSTR)154);
		GetPalette = (FreeImage_GetPalette)GetProcAddress(hinstLib, (LPCSTR)141);
		GetImageType = (FreeImage_GetImageType)GetProcAddress(hinstLib, (LPCSTR)132);
		GetICCProfile = (FreeImage_GetICCProfile)GetProcAddress(hinstLib, (LPCSTR)131);
		GetBackgroundColor = (FreeImage_GetBackgroundColor)GetProcAddress(hinstLib, (LPCSTR)103);
		GetInfo = (FreeImage_GetInfo)GetProcAddress(hinstLib, (LPCSTR)133);
		GetFormatFromFIF = (FreeImage_GetFormatFromFIF)GetProcAddress(hinstLib, (LPCSTR)127);
		GetFIFExtensionList = (FreeImage_GetFIFExtensionList)GetProcAddress(hinstLib, (LPCSTR)116);
		GetMetadataCount = (FreeImage_GetMetadataCount)GetProcAddress(hinstLib, (LPCSTR)139);
		
		(Initialise)(FALSE);
		
		FreeImage_test(hinstLib, PathName);
		
		(DeInitialise)();
		fFreeResult = FreeLibrary(hinstLib);
	}

	if (!fRunTimeLinkSuccess)
		cout << "加载函数失败, Error: " << Error << endl;
	return 0;
}

void FreeImage_test(HINSTANCE hinstLib, wchar_t* pathfile)
{
	// 加载函数
	DWORD FileType = (LoadFileType)(pathfile, 0);
	load = (LoadU)(FileType, pathfile, 0);

	// 获取信息函数
	GetFIFFromFilenameU(pathfile);
	GetDotsPerMeterX(load);
	GetDotsPerMeterY(load);
	GetTransparencyCount(load);
	GetTransparencyTable(load);
	GetBlueMask(load);
	GetRedMask(load);
	GetGreenMask(load);
	GetThumbnail(load);
	GetPalette(load);
	GetImageType(load);
	GetICCProfile(load);
	GetInfo(load);
	GetFormatFromFIF(load);
	GetFIFExtensionList(load);
	
	// 卸载函数
	(UnLoad)(load);
}

wchar_t* charToWChar(const char* text)
{
	size_t size = strlen(text) + 1;
	wchar_t* wa = new wchar_t[size];
	mbstowcs(wa, text, size);
	return wa;
}

测试代码编写完之后使用 WinAFL 的案例最小化功能筛选案例,这一步主要是提高代码运行时的覆盖率。命令如下:
/*
	test.exe
*/
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h> 
#include <tchar.h>
#include <iostream>
using namespace std;

extern "C" __declspec(dllexport) int main(int argc, char** argv);
void FreeImage_test(HINSTANCE hinstLib, wchar_t* pathfile);
wchar_t* charToWChar(const char* text);

// 加载卸载函数 
typedef DWORD(__stdcall *FreeImage_GetFileTypeU)(const wchar_t* lpszPathName, int flag);
typedef DWORD(__stdcall *FreeImage_Initialise)(BOOL load_local_plugins_only);
typedef DWORD(__stdcall *FreeImage_DeInitialise)();
typedef DWORD(__stdcall *FreeImage_LoadU)(DWORD format, const wchar_t* lpszPathName, int flag);
typedef DWORD(__stdcall *FreeImage_UnLoad)(DWORD dib);

// 获取信息函数
typedef DWORD(__stdcall *FreeImage_GetFIFFromFilenameU)(const wchar_t* lpszPathName); FreeImage_GetFIFFromFilenameU GetFIFFromFilenameU;
typedef DWORD(__stdcall *FreeImage_GetDotsPerMeterX)(DWORD dib); FreeImage_GetDotsPerMeterX GetDotsPerMeterX;
typedef DWORD(__stdcall *FreeImage_GetDotsPerMeterY)(DWORD dib); FreeImage_GetDotsPerMeterY GetDotsPerMeterY;
typedef DWORD(__stdcall *FreeImage_GetTransparencyCount)(DWORD dib); FreeImage_GetTransparencyCount GetTransparencyCount;
typedef DWORD(__stdcall *FreeImage_GetTransparencyTable)(DWORD dib); FreeImage_GetTransparencyTable GetTransparencyTable;
typedef DWORD(__stdcall *FreeImage_GetBlueMask)(DWORD dib); FreeImage_GetBlueMask GetBlueMask;
typedef DWORD(__stdcall *FreeImage_GetRedMask)(DWORD dib); FreeImage_GetRedMask GetRedMask;
typedef DWORD(__stdcall *FreeImage_GetThumbnail)(DWORD dib); FreeImage_GetThumbnail GetThumbnail;
typedef DWORD(__stdcall *FreeImage_GetPalette)(DWORD dib); FreeImage_GetPalette GetPalette;
typedef DWORD(__stdcall *FreeImage_GetGreenMask)(DWORD dib); FreeImage_GetGreenMask GetGreenMask;
typedef DWORD(__stdcall *FreeImage_GetImageType)(DWORD dib); FreeImage_GetImageType GetImageType;
typedef DWORD(__stdcall *FreeImage_GetICCProfile)(DWORD dib); FreeImage_GetICCProfile GetICCProfile;
typedef DWORD(__stdcall *FreeImage_GetBackgroundColor)(DWORD dib); FreeImage_GetBackgroundColor GetBackgroundColor;
typedef DWORD(__stdcall *FreeImage_GetInfo)(DWORD dib);	FreeImage_GetInfo GetInfo;	 	// 不确定的
typedef DWORD(__stdcall *FreeImage_GetFormatFromFIF)(DWORD dib); FreeImage_GetFormatFromFIF GetFormatFromFIF;
typedef DWORD(__stdcall *FreeImage_GetFIFExtensionList)(DWORD dib); FreeImage_GetFIFExtensionList GetFIFExtensionList;
typedef DWORD(__stdcall *FreeImage_GetMetadataCount)(DWORD format, DWORD dib); FreeImage_GetMetadataCount GetMetadataCount;

FreeImage_Initialise Initialise;
FreeImage_GetFileTypeU LoadFileType;
FreeImage_LoadU LoadU; DWORD load;
FreeImage_UnLoad UnLoad;
FreeImage_DeInitialise DeInitialise;

int main(int argc, char** argv)
{
	if (argc < 2) {
		printf("Usage: %s <xml file>\n", argv[0]);
		return 0;
	}
	
	wchar_t* PathName = charToWChar(argv[1]);

	HINSTANCE hinstLib; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; DWORD Error = NULL;
	hinstLib = LoadLibrary(TEXT("E:\\FreeImage.dll"));

	if (hinstLib != NULL)
	{
		fRunTimeLinkSuccess = TRUE;
		
		Initialise = (FreeImage_Initialise)GetProcAddress(hinstLib, (LPCSTR)163); // 初始化 FreeImage 库
		LoadFileType = (FreeImage_GetFileTypeU)GetProcAddress(hinstLib, (LPCSTR)126);// 获取位图文件类型
		LoadU = (FreeImage_LoadU)GetProcAddress(hinstLib, (LPCSTR)181);	// 加载位图
		UnLoad = (FreeImage_UnLoad)GetProcAddress(hinstLib, (LPCSTR)242);// 卸载位图
		DeInitialise = (FreeImage_DeInitialise)GetProcAddress(hinstLib, (LPCSTR)83);//卸载 FreeImage 库
		
		// 获取信息函数
		LoadFileType = (FreeImage_GetFileTypeU)GetProcAddress(hinstLib, (LPCSTR)126);
		GetFIFFromFilenameU = (FreeImage_GetFIFFromFilenameU)GetProcAddress(hinstLib, (LPCSTR)118);
		GetDotsPerMeterX = (FreeImage_GetDotsPerMeterX)GetProcAddress(hinstLib, (LPCSTR)112);
		GetDotsPerMeterY = (FreeImage_GetDotsPerMeterY)GetProcAddress(hinstLib, (LPCSTR)113);
		GetTransparencyCount = (FreeImage_GetTransparencyCount)GetProcAddress(hinstLib, (LPCSTR)155);
		GetTransparencyTable = (FreeImage_GetTransparencyTable)GetProcAddress(hinstLib, (LPCSTR)156);
		GetBlueMask = (FreeImage_GetBlueMask)GetProcAddress(hinstLib, (LPCSTR)105);
		GetRedMask = (FreeImage_GetRedMask)GetProcAddress(hinstLib, (LPCSTR)145);
		GetGreenMask = (FreeImage_GetGreenMask)GetProcAddress(hinstLib, (LPCSTR)128);
		GetThumbnail = (FreeImage_GetThumbnail)GetProcAddress(hinstLib, (LPCSTR)154);
		GetPalette = (FreeImage_GetPalette)GetProcAddress(hinstLib, (LPCSTR)141);
		GetImageType = (FreeImage_GetImageType)GetProcAddress(hinstLib, (LPCSTR)132);
		GetICCProfile = (FreeImage_GetICCProfile)GetProcAddress(hinstLib, (LPCSTR)131);
		GetBackgroundColor = (FreeImage_GetBackgroundColor)GetProcAddress(hinstLib, (LPCSTR)103);
		GetInfo = (FreeImage_GetInfo)GetProcAddress(hinstLib, (LPCSTR)133);
		GetFormatFromFIF = (FreeImage_GetFormatFromFIF)GetProcAddress(hinstLib, (LPCSTR)127);
		GetFIFExtensionList = (FreeImage_GetFIFExtensionList)GetProcAddress(hinstLib, (LPCSTR)116);
		GetMetadataCount = (FreeImage_GetMetadataCount)GetProcAddress(hinstLib, (LPCSTR)139);
		
		(Initialise)(FALSE);
		
		FreeImage_test(hinstLib, PathName);
		
		(DeInitialise)();
		fFreeResult = FreeLibrary(hinstLib);
	}

	if (!fRunTimeLinkSuccess)
		cout << "加载函数失败, Error: " << Error << endl;
	return 0;
}

void FreeImage_test(HINSTANCE hinstLib, wchar_t* pathfile)
{
	// 加载函数
	DWORD FileType = (LoadFileType)(pathfile, 0);
	load = (LoadU)(FileType, pathfile, 0);

	// 获取信息函数
	GetFIFFromFilenameU(pathfile);
	GetDotsPerMeterX(load);
	GetDotsPerMeterY(load);
	GetTransparencyCount(load);
	GetTransparencyTable(load);
	GetBlueMask(load);
	GetRedMask(load);
	GetGreenMask(load);
	GetThumbnail(load);
	GetPalette(load);
	GetImageType(load);
	GetICCProfile(load);
	GetInfo(load);
	GetFormatFromFIF(load);
	GetFIFExtensionList(load);
	
	// 卸载函数
	(UnLoad)(load);
}

wchar_t* charToWChar(const char* text)
{
	size_t size = strlen(text) + 1;
	wchar_t* wa = new wchar_t[size];
	mbstowcs(wa, text, size);
	return wa;
}

测试代码编写完之后使用 WinAFL 的案例最小化功能筛选案例,这一步主要是提高代码运行时的覆盖率。命令如下:
 winafl\python winafl-cmin.py --working-dir E:\winafl\bin32 
 							  -D E:\DynamoRIO-7.0.0\bin32 
 							  -t 100000 
 							  -i [案例路径] 
 							  -o [输出案例路径] 
 							  -coverage_module FreeImage.dll 
 							  -target_module test.exe 
 							  -target_method main 
 							  -nargs 2 -- E:\test.exe @@ // 表示引用

筛选过的图片储存在 MIX_* 文件夹中,并且保留了不大于 4KB 的图片,因为大于 4KB 的图片 WinAFL 读起来会非常的慢,而这次测试的时间计划为 6h 左右:
 winafl\python winafl-cmin.py --working-dir E:\winafl\bin32 
 							  -D E:\DynamoRIO-7.0.0\bin32 
 							  -t 100000 
 							  -i [案例路径] 
 							  -o [输出案例路径] 
 							  -coverage_module FreeImage.dll 
 							  -target_module test.exe 
 							  -target_method main 
 							  -nargs 2 -- E:\test.exe @@ // 表示引用

筛选过的图片储存在 MIX_* 文件夹中,并且保留了不大于 4KB 的图片,因为大于 4KB 的图片 WinAFL 读起来会非常的慢,而这次测试的时间计划为 6h 左右:


筛选完图片之后就可以开始模糊测试了,这里规定每个图片格式测试时间为 1h,命令如下:
 winafl\bin32\afl-fuzz.exe -i [输入案例路径]
 						   -o [结果输出路径]
 						   -D E:\DynamoRIO-7.0.0\bi3n2
 						   -t 20000 
 						   -- -coverage_module FreeImage.dll
 						   -fuzz_iterations 5000
 						   -target_module test.exe
 						   -target_offset [函数偏移] // 这里进行模糊测试的函数为 FreeImage_test()
 						   -nargs 2 -- E:\test.exe @@

如下图所示 WinAFL 已经开始正常工作了,但是否运行的良好呢,首先来看一下运行速度 stage progress->exec speed,在 WinAFL 中速度分为三挡:极慢(zzzz....)、慢(slow)、正常,此时的速度为 2352 次每秒属于正常速度;其次看一下 Fuzzing strategy yields,这个板块表示样本变异的程度,数字越大样本越模糊,测试效率越高;之后看一下 stage progress -> now trying && stage execs,now trying 表示目前执行的任务,如图所示目前正在执行算数变异(arith),而 stage execs 表示任务执行的进度,用百分率表示。如果按上面的标准来看,下图算是一个良好的测试开始。
 winafl\bin32\afl-fuzz.exe -i [输入案例路径]
 						   -o [结果输出路径]
 						   -D E:\DynamoRIO-7.0.0\bi3n2
 						   -t 20000 
 						   -- -coverage_module FreeImage.dll
 						   -fuzz_iterations 5000
 						   -target_module test.exe
 						   -target_offset [函数偏移] // 这里进行模糊测试的函数为 FreeImage_test()
 						   -nargs 2 -- E:\test.exe @@

如下图所示 WinAFL 已经开始正常工作了,但是否运行的良好呢,首先来看一下运行速度 stage progress->exec speed,在 WinAFL 中速度分为三挡:极慢(zzzz....)、慢(slow)、正常,此时的速度为 2352 次每秒属于正常速度;其次看一下 Fuzzing strategy yields,这个板块表示样本变异的程度,数字越大样本越模糊,测试效率越高;之后看一下 stage progress -> now trying && stage execs,now trying 表示目前执行的任务,如图所示目前正在执行算数变异(arith),而 stage execs 表示任务执行的进度,用百分率表示。如果按上面的标准来看,下图算是一个良好的测试开始。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-10-26 14:00 被护花使者cxy_编辑 ,原因: 修改一些错误,完善文章
收藏
免费 10
支持
分享
最新回复 (21)
雪    币: 760
活跃值: (69)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
优秀
2019-10-23 08:29
0
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
3
mark,楼主辛苦了
2019-10-23 08:57
0
雪    币: 26245
活跃值: (63297)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
4
感谢分享!点赞、评论、赞赏来一套!
2019-10-23 09:27
0
雪    币: 2325
活跃值: (4898)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
DynamoRIO-7.0.0\bin32> drrun,exe -t drcov -- [程序/模块名] [参数]   上面你生成的数据 完整的命令能给下吗
2019-10-23 10:49
0
雪    币: 1216
活跃值: (230)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
点赞,流程详细、清晰。btw~同求 该命令 DynamoRIO-7.0.0\bin32> drrun,exe -t drcov -- [程序/模块名] [参数] 的完整命令
2019-10-23 11:41
0
雪    币: 8447
活跃值: (5041)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
7
写的非常明白,赞了
2019-10-23 13:06
0
雪    币: 3407
活跃值: (1242)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
8
学习了
2019-10-23 17:30
0
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
感谢发表的文章
2019-10-23 19:30
0
雪    币: 346
活跃值: (62)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
weishi 点赞,流程详细、清晰。btw~同求 该命令 DynamoRIO-7.0.0\bin32> drrun,exe -t drcov -- [程序/模块名] [参数] 的完整命令
DynamoRIO-7.0.0\bin32> drrun.exe -t drcov -- PhotoViewer.exe 1.jpg
2019-10-24 00:18
0
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
11
楼主能不能把开头说的blackhat的链接发一下
2019-11-1 08:58
0
雪    币: 346
活跃值: (62)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
pureGavin 楼主能不能把开头说的blackhat的链接发一下
2019-11-1 22:54
0
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
13
护花使者cxy_ [em_39]
咋了??找不到了么??
2019-11-2 20:06
0
雪    币: 185
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
非常感谢楼主分享心得。
2019-11-3 03:43
0
雪    币: 47
活跃值: (418)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
15
pureGavin 咋了??找不到了么??
https://www.blackhat.com/us-19/briefings/schedule/#going-beyond-coverage-guided-fuzzing-with-structured-fuzzing-16110
2019-11-6 15:16
0
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
16
GeneBlue https://www.blackhat.com/us-19/briefings/schedule/#going-beyond-coverage-guided-fuzzing-with-structu ...
多谢
2019-11-6 20:35
0
雪    币: 109
活跃值: (314)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
2019-11-7 00:50
0
雪    币: 1
活跃值: (213)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
我也觉得用 winafl 每次都要重新封装目标函数,非常麻烦(尤其是目标函数的输入参数比较复杂时),有没有其他的自动化程度更高的工具?
2019-11-12 11:04
0
雪    币: 1
活跃值: (213)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
顺便再问个问题:drcov 能不能统计到dll 的覆盖率,我用的时候好像只能统计到主程序的覆盖率
2019-11-12 17:38
0
雪    币: 346
活跃值: (62)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
Flyour 顺便再问个问题:drcov 能不能统计到dll 的覆盖率,我用的时候好像只能统计到主程序的覆盖率
可以统计子模块的覆盖率
2019-11-14 15:56
0
雪    币: 49
活跃值: (22)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
你好,我参考你这个案例进行实践的时候发生一个问题 使用参数"-fuzz_interations 5000" 弹出一个错误
ASSERT FAILURE: c:\work\winafl\source\winafl.c:947:(0) (invalid options)
你有遇到过吗?
写错了好像。
最后于 2019-12-1 17:49 被wxtaaaa编辑 ,原因:
2019-12-1 17:38
0
雪    币: 188
活跃值: (621)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
22
您好,我在fuzzer运行到perform_dry_run()中的calibrate_case()的时候,在循环run_target时,第一次成功,第二次就失败了。第二次失败的原因是WriteCommandToPipe('F')后,目标程序崩溃了,ReadCommandFromPipe收到0,然后程序返回Test case 'id_000000' results in a crash。

请问你指导原因嘛?或者调试方法。

https://bbs.pediy.com/thread-260785.htm

2020-7-20 21:44
0
游客
登录 | 注册 方可回帖
返回
//