-
-
[原创](开源)Windows下测试用例自动生成工具--pingrind
-
发表于:
2012-5-5 15:14
27641
-
[原创](开源)Windows下测试用例自动生成工具--pingrind
Windows下测试用例自动生成工具—Pingind
原理:
Windows下二进制程序的漏洞挖掘主要还是通过fuzz测试,通过构造随机的输入使程序崩溃,再进行人工分析程序崩溃是否由漏洞引起。但是传统的黑盒fuzz效率非常低,因其无法达到理想中的覆盖率,其中很大部分的时间里都是在重复以前同样的路径,并不能有效地探测到新的路径。因此,路径覆盖的问题亟待解决。
微软的Sage提出白盒fuzz的方法,可以通过二进制的一次具体执行中收集到路径约束,然后取反求解而得到新的输入,使用新的输入再次执行二进制程序,通常又可得到新的路径,如此往复,可以达到较好的二进制代码覆盖率。Sage一贯继承微软的作风,并未开源。类似的实现还有DART、CUTE、Catchconv、Fuzzgrind,这些都是运行在linux平台下。其中CUTE与DART同宗,都是使用了CIL中间语言与lpsovler求解器,由Koushik与Patrice两人共同完成。而Catchconv与Fuzzgrind原理相同,都是使用Valgrind插装工具与STP求解器。其中Catchconv与Fuzzgrind现在仍然是开源的。
基于上述的基础,我实现了一种运行在Windows平台上的路径探测工具—Pingrind。
实现思路:实现Pin中的pintool,使用可以追踪指令,可方便获取当前线程执行上下文,可得知每个跳转是否taken等信息,可得到文件输入的地址,从而引入污点(这里的污点可看成是输入,从污点位置开始收集路径约束)。然后集成以Valgrind中的中间语言VEX IR,使给出任意地址即可把该地址的机器指令翻译成VEX IR。再借鉴fuzzgrind中的一部分代码来完成收集约束及污点传播过程。使用STP来求解生成新的输入用例。最后完成自动化过程,使整个过程不需要人工。
Pin是Intel公司开发的、对二进制代码执行监控的工具。使用插装的方式,可以监控二进制代码在用户模式下的一切行为,包括线程、寄存器、内存等信息。Pin可运行在Window与Linux平台下,Linux下工具一般都开源,且还有其它的程序分析工具如Valgrind、Temu等与其竞争,而Windows下与其竞争的开源框架极少。
Pin为PinVMM和Pintool开发者提供一个常规的编程环境,使用C++语言,包括流和标准模板库,C运行时库和一些Windows API。但是PinVMM和Pintools是应用进程的DLL,调用相同的运行时库可能会引起不想看到的Pin和应用程序的交互。如当程序调用malloc时,我们想插装它的整个执行直到系统调用级。Pintool可能需要使用malloc但它的执行不能被插装。而且,Pintools调用malloc可能作为对程序调用malloc插装的一部分,表示pintool在应用程序调用malloc完成之前调用malloc。系统库设计来支持使用锁和线程局部存储来支持并发执行,但是这些方法并不有效因为应用程序和插装可能在同一个线程内。
Pin为用户提供了很好的接口,可以实现各种Pintool,可基于Pin的基础上对二进制分析。在Pin源码中的ManualExample文件中有很多例子可以参考。Pin接口API文档化较差,需看include文件夹下的*.PH文件,根据函数名猜测其功能。
Valgrind也是二进制插装平台,可运行在Linux、MacOS等平台下,唯独对Windows不兼容,导致其虽然功能完善,但无法分析Windows程序,虽说出现了Wine+Valgrind的组合,但其兼容性有待考证。Valgrind中实现了一套中间语言--VEX IR,它可以将二进制转换为此IR,再进行插装,然后再把插装后的IR编译成二进制执行。Fuzzgrind为Valgrind平台上实现的一个插件,可以在插装VEX IR并收集路径约束,再用STP求解来生成新的输入用例。从Fuzzgrind的实现来看,它更适用于对文件读写的程序,可看成是一种文件类型的智能fuzz工具。Valgrind包括两个组件外加一个程序分析的工具。第一个组件是VEX库,把机器代码块转化为一种中间表示。第二个组件是Valgrind核,处理程序载入,与操作系统交互并即时翻译程序到VEX中间表示,插装,编译到机器代码。Valgrind以标准的Linux进程运行并作为一个程序加载器。Valgrind核把guest进程的每个基本块加载到VEX库。VEX库转化每个基本到一种表示并将其输入到特定的Valgrind工具中。该工具为基本块插装并把结果输入到Valgrind核,Valgrind核使用VEX编译其到机器代码。Valgrind保留一个编译后的插装块的缓存并管理它们的执行流。Valgrind可作为一个即时的插装编译器。VEX库转化机器码到一种平台无关的中间表示。
Pingrind的工作就是把Valgrind中的VEX集成在Pin中,使用Pin作为二进制代码的插装工具,使用VEX作为中间代码,在Pin中监控二进制代码的执行,使其转化成VEX后,并在每个分支收集其依赖于输入的路径约束。再使用STP求解,可得到新的输入。
实现:
重用了Fuzzgrind中的部分python代码(在此严重感谢ESEC开发Fuzzgrind的作者)
移植了VEX库到windows下,为方便直接合成到一个源文件vex_main.c(对这近4W行的代码修改还真是累)。
SOURCE=grind.cpp, check.cpp
grind.cpp就是pin的插件源码,用来插装二进制代码的动态执行
check.cpp是先观察程序执行时要加载哪些模块,要create, read,map哪些文件的信息,有了这些信息才能给pingrind.py添加参数。
开发环境:
Pin主页上下载Pintools的源码,然后修改其中的NMakefile,把Source文件中的check.cpp 及grind.cpp添加进去编译即可。由于Pin的源码较大我就不一起上传了。
环境:
环境要求:Windows xp(32位) + Python2.7及以上版本
编译STP:
1)下载安装cgywin,并添加必要的开发组件(如gcc, g++, make等),还需添加bison, flex, svn;
2) svn co https://stp-fast-prover.svn.sourceforge.net/svnroot/stp-fast-prover/trunk/stp stp;
3)cd stp;
4)./scripts/configure –with-prefix=/path/to/stp/inst;
5)make & make install;
注意:编译过程中可能会出现getchar函数名问题,将其重命名即可
6)添加cygwin/bin与/path/to/stp/inst/bin到环境变量中
使用方法:
1)cmd中先运行“lm.py <程序名>”
这一步完成后会在当前目录下生成一个_check_info的文件,其中包括了程序运行过程中加载的模块及其地址等信息,还有访问的文件信息。
(由于Pin只是对用户态级别的监控,所以内核层的任何动作它都无法得知)
2)有了模块及文件信息后,在cmd下执行以下命令:
“pingrind.py --ts=0x<模块开始地址> --te=0x<模块结束地址> --tf=<访问的文件名> --prog=<程序名>”
简单的例子:
现在在文件中包括了testC.exe和testRead.exe这两个最简单的例子可以测,它们中包括相同的代码:
char buffer[5] = { 0 };
int count = 0;
FILE *fp = fopen("d:\\123.txt", "r");
if(fp != NULL)
{
fread(buffer, 1, 4, fp);
}
if (buffer[0] == 'b') count++;
if (buffer[1] == 'a') count++;
if (buffer[2] == 'd') count++;
if (buffer[3] == '!') count++;
if (count == 4) {
printf("\nbad!\n");
}
else{
printf("\ngood\n");
}
fclose(fp);
先在d:下建一个文件123.txt,在这个文件中写入”good”,然后使用命令:”pingrind.py --ts=0x400000 --te=0x4FFFFF --tf=d:\\123.txt --prog=testC.exe”就可以开始测试。
作者声明:
Pingrind现在充其量算是一个原型,目前只能测一些非常小的例子,稍微大一点的程序完全没法测试(效率问题),如果要投入使用,需要以后不断的优化,完善。我开源的目的也就是为了有兴趣的朋友可以加入一起研究。
作者邮箱:majinxin2003@126.com
作者blog: http://hi.baidu.com/majinxin2003/blog(欢迎互粉)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课