上一篇 已经将前三部分写完了,但是留有一些疑问点,所以下篇将分三部分:对上篇遗留问题的解决 、关键函数实现原理介绍 、main函数注释 (逐行贴出代码块,因为main是整个alf的核心流程,所以需要一行行的详解),这一篇可能对代码的分析偏多一点,因为以后我的论文应该也是要在afl的基础上进行改进,所以就需要对代码多进行分析。其实像mopt-afl对代码的改进就主要是在fuzz_one函数上也就是mutation阶段。 最后是附录,写有我看过的一些实用的相关文章、博客、帖子之类的,多是实用总结型的。
先来说说上一篇未解决的问题,这几个问题主要是在代码细节的理解上,有错误之处还望斧正):
关于effector map
,在看源码数据变异这一部分的时候,一定会注意的是在 bitflip 8/8 的时候遇到一个叫eff_map
的数组,这个数组的大小是EFF_ALEN(len)
,这个数是多大?
当时没想出来这么写是个什么意思,后来转过弯来,其实那不是变量也不是普通的函数,EFF_ALEN
是一个宏定义的函数:
如果把这一块的宏定义拆开,变成函数的形式就是这样:
宏函数本质知道了,但是分别代表的什么意思呢?(代码中给出的注释如下)
EFF_APOS - position of a particular file offset in the map. 在map中的特定文件偏移位置。 EFF_ALEN - length of a map with a particular number of bytes. 根据特定数量的字节数,计算得到的文件长度。 EFF_SPAN_ALEN - map span for a sequence of bytes. 跳过一块bytes
现在重新看eff_map = ck_alloc(EFF_ALEN(len));
,len来自于队列当前结点queue_cur的成员len,是input length(输入长度),所以这里分配给eff_map的大小是 (文件大小/8) 向下取整,这里的 8 = 2^EFF_MAP_SCALE2
。比如文件17bytes,那么这里的EFF_ALEN(_l)就是3。
如果加减某数之后效果与之前某bitflip效果相同,认为此次变异在上一阶段已经执行过,此次不再执行?
这里当时标记出来是因为没有理解透彻,没怎么搞懂作者是怎么实现的,后来经过仔细分析几个变量的关系,才缕清楚,这里以 ARITHMETIC
的8/8变异这一段为例(16和32的变异大同小异),把重要部分做解释:
为什么不是当前的尾拼接随机文件的头
这个其实想想当时挺蠢的,一堆文件,拿出一个一分为二,把当前文件的头和其他文件的尾拼接,这是原来的策略,这样多次之后,自然会有之前的那个拿了尾的文件,用这个的头跟其他的尾拼接了。所以没必要此次拼接的时候,非得生成两个文件,因为这样的话后面还会出现,就有点重复了。
一次变异到底是变一个比特还是从一比特到32比特都结束了才算事
这个看理解,我跟同学总结的说法是:一次变异是指一个比特的改变也算变异,根据编译策略,经过很多次变异之后,fuzz_one结束叫做一轮变异。
这部分详提一下三个重要函数 fuzz_one、init_forkserver、show_stats
这个函数的主要功能就是变异,每一阶段变异的原理,在上一篇已经分析过,这里着重说一下作者加的 eff_map
这个变量,看代码的话,在变异fuzz_one阶段,这是个贯穿始终的数组,刚开始第一遍看代码其实不是理解的很深刻,现在理解的比较多了,也能理解作者为什么要加这个数组了:fuzz_one函数将近两千行,每一个变异阶段都有自己的功能,怎么把上一阶段的信息用于下一阶段,需要一个在函数内通用的局部变量 ,可以看到fuzz_one一开始的局部变量有很多,有很多类型:
eff_map的类型是u8(上篇解释过这种看不懂的,可以去types.h里找,这是一个uint8_t = unsigned char 形,8比特(0~255) ),并且u8类型只有这一个是map命名形式的,在后面的注释中如果出现Effector map,说的就是这个变量。主要的作用就是标记,在初始化数组的地方有这么一段注释Initialize effector map for the next step (see comments below). Always flag first and last byte as doing something. 把第一个和最后一个字节单独标记出来用作其他用途,这里其实就说明了,这个map是标记作用,那是标记什么呢,标记当前byte对应的map块是否需要进行阶段变异。如果是0意味着不需要变异,非0(比如1)就需要变异,比如一开始分析的 arithmetic 8/8
阶段就用过这个eff_map,此时已经它在bitflip阶段经过了改变了。
用于fork server进行的初始化,这部分跟插桩息息相关,只有插桩模式才会运行这部分,可以配合afl-as.h文件一起看。 这里的整体流程是这样的:
这个函数技术上没什么好说的,就是用来展示那个fuzz界面的,每次有数据更新的时候就会调用这个函数刷新页面,如果说在AFL运行的界面,看到哪个不懂的变量,或者想单独看那个参数是怎么来的,就从这个函数入手就对了,对应着界面的字符串定位到函数的位置,然后从变量再定位到相应位置,就可以很轻松的理解参数的含义和求法。
main函数逐块分析,这部分可能会有点长,大家随意看看就好,算是我自己看代码的碎碎念吧,因为不少在前面已经解释过了,这里算是总结了,有很多总结文章对源代码的解读比我更好,形式也比我的好看 ,我这算是献丑了233333)main函数代码太长,我放在这里:afl-fuzz.c文件里的main函数代码注释版 了,可以点进去看。
持续更新的AFL相关小细节
这个是我从去年年底一开始接触AFL一直到现在记录的平时遇到的一些小细节,一般情况下就很机录在这个博客里,王婆卖瓜自卖自夸 哈哈哈哈哈
利用AFL对upx从头开始模糊测试
这是一篇比较简单的实践类,非常适合刚开始的新手对AFL进行初探。但是我最早的时候跟着这个帖子进行测试,发现并没有达到作者的效果,所以大家就跟着练练手就好啦,只要跑出来的界面就行。
从头开始的fuzzing流程
很详细的教程,配合2.可以加快对afl工作原理的理解,我是这么觉得的。如果对英文吃力,可以看这篇翻译
afl-fuzz.c源码讲解
这位前辈写的源码分析,对我而言收获颇多,希望能帮到大家。
AFL整体结构
版主写的一篇对AFL从整体结构上进行剖析的文章,写的也很好,很有收获。
256多线程运行AFL
一个对AFL进行多线程操作的文章,算是从工程上进行性能改进的类型,有机会可以实现一下。
Awesome AFL
一个搜集的项目,作者收集了很多 不同的AFL变种,或者AFL启发的超级魔改,这个项目的好处是从没停更,一直整的挺好的。
AFL生态圈
这位师傅写的翻译,对很多AFL类,以及其他fuzzer工具的介绍,比较仔细全面
AFL插桩讲解
可以看到上下篇只对afl-fuzz.c进行讲解,插桩部分并没有讲解,因为我也还没仔细研究。有这方面需要的可以看一下这篇文章,对插桩进行了详细解释
Fuzzer tools
一些fuzzer工具集合,内容是前几年比较经典的一些fuzzer,不包括最近顶会的那些fuzzer
fuzz总结性优秀文章分类
这是看雪上的一篇质量挺高的总结性的文章
顶会fuzz论文收集与总结
作者收集的一些文章是比较经典的顶会文章,而且做了思维导图,可以说是很用心了,~~ 但是貌似停更很久了,不知道还会不会继续更新。 ~~ 跟作者聊过,现在是不更新了,不过还有一个项目在维护
顶会fuzzing论文分类
这是 3. 的作者写的另一个一直在维护的论文分类project,后面我跟同学也会参与其中一起维护,后面对论文的理解相关的东西也会同步更新到这里。我跟郭老板的想法是把近十年的论文abstract都过一遍然后进行分类,希望能从中找到启发。
大手子rk700
写的关于fuzz的文章都挺好的,最早的几篇对afl的理解也很有帮助。他的这篇分析写的很好
下篇本来是跟着上篇写的,但是中间被安排了一些杂七杂八的事情,就一直拖到现在,还好现在已经进入正轨了,期间看雪上也有发私信一起讨论的,如果大家也想一起讨论,或者对文章内容有异议欢迎留言,或者发邮件 wayne-tao(at)Outlook.com,我也是上学期末对时候下定决心搞这方面的,再加上本科不是搞安全的,所以进步很慢,大家共同进步。 文章和注释源码我放在git上了地址: https://github.com/WayneDevMaze/Chinese_noted_AFL 欢迎大家star ,除了上下两篇对 afl.c 文件对分析,还有两篇对cmin和tmin的分析,这两个因为没多少技术含量就不放看雪了,感兴趣可以看一下我对博客(对两个工具对分析 和修改tmin 、cmin ),目前一方面搞fuzz,一方面也在搞web安全(毕竟新入门的水平比较菜,这个好入门),后面也会深入一下二进制,因为经常是发现一些崩溃情况,但是不知道怎么入手分析就很烦,感觉入门还早,继续努力把吧。最后,谢谢大家看我的文章,希望大家都能有所收获,早发文章。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-6-8 00:00
被张公子T40编辑
,原因: 添加附录精简