文章目录

  • 1、sync_fuzzers(char **argv)该函数是读取其他fuzz的queue中的case文件,然后保存到自己的queue里
  • 2、trim_case(char **argv, struct queue_entry *q, u8 *in_buf)对于测试用例进行修剪
  • 3、u32 calculate_score(struct queue_entry *q)根据queue entry的执行速度、覆盖到的path数和路径深度来评估出一个得分,这个得分perf_score在后面havoc的时候使用。
  • 4、u8 common_fuzz_stuff(char **argv, u8 *out_buf, u32 len)写出修改后的测试用例,运行程序,处理result与错误等。
  • 5、void write_to_testcase(void *mem, u32 len)将从mem中读取len个字节,写入到.cur_input中
  • 6、u8 save_if_interesting(char **argv, void *mem, u32 len, u8 fault)检查这个case的执行结果是否是interesting的

1、sync_fuzzers(char **argv)该函数是读取其他fuzz的queue中的case文件,然后保存到自己的queue里


/* Grab interesting test cases from other fuzzers. */static void sync_fuzzers(char** argv) {DIR* sd;struct dirent* sd_ent;u32 sync_cnt = 0;sd = opendir(sync_dir);打开sync_dir文件夹if (!sd) PFATAL("Unable to open '%s'", sync_dir);stage_max = stage_cur = 0;cur_depth = 0;/* Look at the entries created for every other fuzzer in the sync directory. */while ((sd_ent = readdir(sd))) {用while循环遍历sync_dir下面的所有文件static u8 stage_tmp[128];DIR* qd;struct dirent* qd_ent;u8 *qd_path, *qd_synced_path;u32 min_accept = 0, next_min_accept;s32 id_fd;/*跳过点文件和我们自己的输出目录*/if (sd_ent->d_name[0] == '.' || !strcmp(sync_id, sd_ent->d_name)) continue;跳过.开头的文件和sync_id即我们自己的输出文件夹/*跳过没有队列/子目录的任何内容*/qd_path = alloc_printf("%s/%s/queue", sync_dir, sd_ent->d_name);if (!(qd = opendir(qd_path))) {ck_free(qd_path);continue;}/*检索上次看到的测试用例的ID*/qd_synced_path = alloc_printf("%s/.synced/%s", out_dir, sd_ent->d_name);id_fd = open(qd_synced_path, O_RDWR | O_CREAT, 0600);打开out_dir/.synced/sd_ent->d_name,返回到id_fdif (id_fd < 0) PFATAL("Unable to create '%s'", qd_synced_path);if (read(id_fd, &min_accept, sizeof(u32)) > 0) 读取out_dir/.synced/sd_ent->d_name文件即id_fd里的前(sizeof(u32))4个字节到min_accept里lseek(id_fd, 0, SEEK_SET);然后lseek从新调整文件内指针到开头。next_min_accept = min_accept;设置next_min_accept为min_accept,这个值代表之前从这个文件夹里读取到的最后一个queue的id。/* 显示数据统计 */     sprintf(stage_tmp, "sync %u", ++sync_cnt);sync_cnt计数加一,由"sync %u"格式化到stage_tmp中。stage_name = stage_tmp;stage_cur  = 0;stage_max  = 0;/*接下来利用一个while循环对于此fuzzer排队的每个文件,解析ID并查看我们之前是否曾看过它;如果没有,执行此个测试用例。 */while ((qd_ent = readdir(qd))) {利用readdir(qd)进一步取出目录中的文件u8* path;s32 fd;struct stat st;if (qd_ent->d_name[0] == '.' ||sscanf(qd_ent->d_name, CASE_PREFIX "%06u", &syncing_case) != 1 || syncing_case < min_accept) continue;跳过.开头的文件和标识小于min_accept的文件,因为这些文件应该已经被sync过了。/*下面就是新的了*/if (syncing_case >= next_min_accept)next_min_accept = syncing_case + 1;path = alloc_printf("%s/%s", qd_path, qd_ent->d_name);/* 如果其他模糊器正在恢复,请允许此操作失败。。。 */fd = open(path, O_RDONLY);只读的方式打开qd_path/qd_ent->d_name返回为fdif (fd < 0) {ck_free(path);continue;}if (fstat(fd, &st)) PFATAL("fstat() failed");/* 忽略大小为零或过大的文件。*/开始同步这个if (st.st_size && st.st_size <= MAX_FILE) {u8  fault;u8* mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);将fd对应的文件映射到进程空间中,返回u8 *memif (mem == MAP_FAILED) PFATAL("Unable to mmap '%s'", path);/*看看会发生什么。我们依赖save_if_interest()来捕获主要错误并保存测试用例*/write_to_testcase(mem, st.st_size);调用write_to_testcase(mem, st.st_size)将其写到outfile中。fault = run_target(argv, exec_tmout);接着run_target运行对应文件,返回fault。if (stop_soon) return;syncing_party = sd_ent->d_name;queued_imported += save_if_interesting(argv, mem, st.st_size, fault);调用save_if_interesting(argv, mem, st.st_size, fault)将感兴趣的样本保存。syncing_party = 0;munmap(mem, st.st_size);调用 munmap(mem, st.st_size) 接触映射if (!(stage_cur++ % stats_update_freq)) show_stats();然后 stage_cur++ % stats_update_freq 如果是0即循环到一个周期,如果是1则输出对应的fuzz信息}ck_free(path);close(fd);}ck_write(id_fd, &next_min_accept, sizeof(u32), qd_synced_path);将&next_min_accept对应文件中的内容写到id_fd对应的文件中。关闭对应的文件/目录描述等。close(id_fd);closedir(qd);ck_free(qd_path);ck_free(qd_synced_path);}  closedir(sd);}

2、trim_case(char **argv, struct queue_entry *q, u8 *in_buf)对于测试用例进行修剪

/*在进行确定性检查时,修剪所有新的测试用例以节省周期。修剪器使用文件大小的1/16和1/1024之间的两个增量的幂,以保持该阶段短而甜美*/
static u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) {static u8 tmp[64];static u8 clean_trace[MAP_SIZE];u8  needs_write = 0, fault = 0;u32 trim_exec = 0;u32 remove_len;u32 len_p2;/*虽然微调器在检测到变量行为时用处不大,但它在一定程度上仍然有效,因此我们不检查这一点*/if (q->len < 5) return 0;如果这个case的大小len小于5字节,就直接返回stage_name = tmp;令stage_name指向tmp数组首位bytes_trim_in += q->len;bytes_trim_in计数加上当前的q->len。bytes_trim_in代表被trim过的字节数len_p2 = next_p2(q->len);接着找出使得2^x > q->len的最小的x,作为len_p2remove_len = MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES);设置remove_len为MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES)即len_p2/16,与4中最大的那个,作为步长。/*继续,直到步数太高或跨步太小*/while (remove_len >= MAX(len_p2 / TRIM_END_STEPS, TRIM_MIN_BYTES)) {进入while循环,终止条件是remove_len小于终止步长len_p2的1/1024,每轮循环步长会除2u32 remove_pos = remove_len;设置remove_pos的值为remove_lensprintf(tmp, "trim %s/%s", DI(remove_len), DI(remove_len));读入"trim %s/%s", DI(remove_len), DI(remove_len)到tmp中, 即stage_name = “trim 512/512”stage_cur = 0;stage_max = q->len / remove_len;while (remove_pos < q->len) {进入while循环,remove_pos < q->len,即每次前进remove_len个步长,直到整个文件都被遍历完为止u32 trim_avail = MIN(remove_len, q->len - remove_pos);u32 cksum;write_with_gap(in_buf, q->len, remove_pos, trim_avail);fault = run_target(argv, exec_tmout);trim_execs++;计数器加一if (stop_soon || fault == FAULT_ERROR) goto abort_trimming;如果设置了stop_soon或者fault == FAULT_ERROR,直接跳转到abort_trimming/*请注意,我们在这里不跟踪崩溃或挂起;也许是TODO*/cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);计算当前trace_bits的hash32为cksum。if (cksum == q->exec_cksum) {如果相等u32 move_tail = q->len - remove_pos - trim_avail;从q->len中减去remove_len个字节,并由此重新计算出一个len_p2,这里注意一下while (remove_len >= MAX(len_p2 / TRIM_END_STEPS, TRIM_MIN_BYTES)q->len -= trim_avail;len_p2  = next_p2(q->len);memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, move_tail);从in_buf + remove_pos + trim_avail复制move_tail个字节到in_buf + remove_pos/*让我们保存一个干净的跟踪,它将由完成修剪后update_bitmap_score*/if (!needs_write) {needs_write = 1;memcpy(clean_trace, trace_bits, MAP_SIZE);拷贝trace_bits到clean_trace}} else remove_pos += remove_len;如果不等,remove_pos前移remove_len个字节。/*由于这可能会很慢,请不时更新屏幕*/if (!(trim_exec++ % stats_update_freq)) show_stats();stage_cur++;}remove_len >>= 1;}/*如果我们对in_buf进行了更改,我们还需要更新测试用例的磁盘版本*/if (needs_write) {如果needs_write为1s32 fd;删除原来的q->fname,创建一个新的q->fname,将in_buf里的内容写入,然后用clean_trace恢复trace_bits的值。unlink(q->fname); /* ignore errors */fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600);if (fd < 0) PFATAL("Unable to create '%s'", q->fname);ck_write(fd, in_buf, q->len, q->fname);close(fd);memcpy(trace_bits, clean_trace, MAP_SIZE);update_bitmap_score(q);进行一次update_bitmap_score}abort_trimming:bytes_trim_out += q->len;return fault;}

3、u32 calculate_score(struct queue_entry *q)根据queue entry的执行速度、覆盖到的path数和路径深度来评估出一个得分,这个得分perf_score在后面havoc的时候使用。


/*计算案例可取性得分,以调整浩劫模糊的长度。fuzz_one()的帮助函数。也许这些常量中的一些应该进入config.h*/static u32 calculate_score(struct queue_entry* q) {u32 avg_exec_us = total_cal_us / total_cal_cycles;首先计算平均时间u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries;计算平均bitmap大小u32 perf_score = 100;定义初始的perf_score = 100/*根据此路径的执行速度与全局平均值进行比较,调整分数。乘数范围从0.1x到3x。快速输入比模糊输入便宜,所以我们给它们更多的播放时间*/接下来通过给q->exec_us乘一个系数,判断他和avg_exec_us的大小来调整perf_score。if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10;else if (q->exec_us * 0.25 > avg_exec_us) perf_score = 25;else if (q->exec_us * 0.5 > avg_exec_us) perf_score = 50;else if (q->exec_us * 0.75 > avg_exec_us) perf_score = 75;else if (q->exec_us * 4 < avg_exec_us) perf_score = 300;else if (q->exec_us * 3 < avg_exec_us) perf_score = 200;else if (q->exec_us * 2 < avg_exec_us) perf_score = 150;/* Adjust score based on bitmap size. The working theory is that bettercoverage translates to better targets. Multiplier from 0.25x to 3x. */然后通过给q->bitmap_size 乘一个系数,判断与avg_bitmap_size的大小关系来调整perf_score。if (q->bitmap_size * 0.3 > avg_bitmap_size) perf_score *= 3;else if (q->bitmap_size * 0.5 > avg_bitmap_size) perf_score *= 2;else if (q->bitmap_size * 0.75 > avg_bitmap_size) perf_score *= 1.5;else if (q->bitmap_size * 3 < avg_bitmap_size) perf_score *= 0.25;else if (q->bitmap_size * 2 < avg_bitmap_size) perf_score *= 0.5;else if (q->bitmap_size * 1.5 < avg_bitmap_size) perf_score *= 0.75;/* Adjust score based on handicap. Handicap is proportional to how latein the game we learned about this path. Latecomers are allowed to runfor a bit longer until they catch up with the rest. */if (q->handicap >= 4) {如果q->handicap大于等于4perf_score *= 4;perf_score乘4.q->handicap -= 4;} else if (q->handicap) {perf_score *= 2;q->handicap--;}
/*基于输入深度的最终调整,假设模糊更深的测试用例更有可能揭示传统模糊器无法发现的东西*/switch (q->depth) {case 0 ... 3:   break;case 4 ... 7:   perf_score *= 2; break;case 8 ... 13:  perf_score *= 3; break;case 14 ... 25: perf_score *= 4; break;default:        perf_score *= 5;}最后保证我们调整后的不会超出最大界限。if (perf_score > HAVOC_MAX_MULT * 100) perf_score = HAVOC_MAX_MULT * 100;return perf_score;}

4、u8 common_fuzz_stuff(char **argv, u8 *out_buf, u32 len)写出修改后的测试用例,运行程序,处理result与错误等。

5、void write_to_testcase(void *mem, u32 len)将从mem中读取len个字节,写入到.cur_input中

6、u8 save_if_interesting(char **argv, void *mem, u32 len, u8 fault)检查这个case的执行结果是否是interesting的

/*检查例程模糊化过程中execve()的结果是否有趣,
如果是,保存或排队输入测试用例以供进一步分析。
如果条目已保存,则返回1,否则返回0*/static u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {u8  *fn = "";u8  hnb;s32 fd;u8  keeping = 0, res;if (fault == crash_mode) {如果fault等于crash_mode。/* Keep only if there are new bits in the map, add to queue forfuture fuzzing, etc. */查看此时是否出现了newbits。如果没有的话若设置了crash_mode,则total_crashes计数加一。return 0if (!(hnb = has_new_bits(virgin_bits))) {if (crash_mode) total_crashes++;return 0;}    #ifndef SIMPLE_FILES
若出现了newbits则调用 fn = alloc_printf("%s/queue/id:%06u,%s", out_dir, queued_paths,describe_op(hnb));拼接出路径fnfn = alloc_printf("%s/queue/id:%06u,%s", out_dir, queued_paths,describe_op(hnb));#elsefn = alloc_printf("%s/queue/id_%06u", out_dir, queued_paths);#endif /* ^!SIMPLE_FILES */add_to_queue(fn, len, 0);通过调用add_to_queue(fn, len, 0)将其插入队列。if (hnb == 2) {如果hnb==2成立。(有新路径发现)queue_top->has_new_cov = 1;设置queue_top->has_new_cov为1queued_with_cov++;计数器加一}queue_top->exec_cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);利用hash32从新计算trace_bits的哈希值,将其设置为queue_top->exec_cksum/*尝试在线校准;成功时,还调用update_bitmap_score()*/res = calibrate_case(argv, queue_top, mem, queue_cycle - 1, 0);调用calibrate_case进行用例校准,评估当前队列。if (res == FAULT_ERROR)FATAL("Unable to execute target application");fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);if (fd < 0) PFATAL("Unable to create '%s'", fn);ck_write(fd, mem, len, fn);打开fn,将mem的内容写入文件fn。close(fd);keeping = 1;}switch (fault) {case FAULT_TMOUT:/*超时不是很有趣,但我们仍有义务保留少量样本。我们使用挂起特定位图中新位的存在作为唯一性的信号。在“dume”模式下,我们只保留一切*/total_tmouts++;计数器加一if (unique_hangs >= KEEP_UNIQUE_HANG) return keeping;if (!dumb_mode) {如果不是dume_mode#ifdef WORD_SIZE_64simplify_trace((u64*)trace_bits);调用simplify_trace对trace_bits进行调整
#elsesimplify_trace((u32*)trace_bits);
#endif /* ^WORD_SIZE_64 */if (!has_new_bits(virgin_tmout)) return keeping;若没有新的超时路径,直接return keeping。}unique_tmouts++;计数器加一if (exec_tmout < hang_tmout) {u8 new_fault;write_to_testcase(mem, len);将mem的内容写到outfilenew_fault = run_target(argv, hang_tmout);然后再次调用run_target运行一次,返回new_fault。if (!stop_soon && new_fault == FAULT_CRASH) goto keep_as_crash;如果未设置stop_soon,并且new_fault为FAULT_CRASH,那么跳转到keep_as_crashif (stop_soon || new_fault != FAULT_TMOUT) return keeping;}#ifndef SIMPLE_FILESfn = alloc_printf("%s/hangs/id:%06llu,%s", out_dir,unique_hangs, describe_op(0));#elsefn = alloc_printf("%s/hangs/id_%06llu", out_dir,unique_hangs);#endif /* ^!SIMPLE_FILES */unique_hangs++;last_hang_time = get_cur_time();break;case FAULT_CRASH:keep_as_crash:/* This is handled in a manner roughly similar to timeouts,except for slightly different limits and no need to re-run testcases. */total_crashes++;if (unique_crashes >= KEEP_UNIQUE_CRASH) return keeping;if (!dumb_mode) {#ifdef WORD_SIZE_64simplify_trace((u64*)trace_bits);
#elsesimplify_trace((u32*)trace_bits);
#endif /* ^WORD_SIZE_64 */if (!has_new_bits(virgin_crash)) return keeping;}if (!unique_crashes) write_crash_readme();#ifndef SIMPLE_FILESfn = alloc_printf("%s/crashes/id:%06llu,sig:%02u,%s", out_dir,unique_crashes, kill_signal, describe_op(0));#elsefn = alloc_printf("%s/crashes/id_%06llu_%02u", out_dir, unique_crashes,kill_signal);#endif /* ^!SIMPLE_FILES */unique_crashes++;last_crash_time = get_cur_time();last_crash_execs = total_execs;break;case FAULT_ERROR: FATAL("Unable to execute target application");default: return keeping;}/* If we're here, we apparently want to save the crash or hangtest case, too. */fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600);if (fd < 0) PFATAL("Unable to create '%s'", fn);ck_write(fd, mem, len, fn);close(fd);ck_free(fn);return keeping;}

fuzz对测试用例作用的一些函数相关推荐

  1. 函数指针的作用:*visit函数

    定义 函数指针是指向函数的指针变量. 因此"函数指针"本身首先应是指针变量,只不过该指针变量指向函数.这正如用指针变量可指向整型变量.字符型.数组一样,这里是指向函数.如前所述,C ...

  2. static作用(修饰函数、局部变量、全局变量)

    C语言:static作用(修饰函数.局部变量.全局变量) 一. static全局变量与普通的全局变量有什么区别 ? 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量.   全局 ...

  3. C语言:static作用(修饰函数、局部变量、全局变量)

    C语言:static作用(修饰函数.局部变量.全局变量) 一. static全局变量与普通的全局变量有什么区别 ? 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量.  全局变 ...

  4. python函数的作用是_Python函数一

    函数 一.函数的作用 函数就是一段具有独立功能的代码块整合到一个整体并命名,在需要的位置调用这个名称即可完成对应的需求 函数在开发过程中,可以更高效的实现代码重用 二,函数的使用步骤 2.1 定义函数 ...

  5. python测试用例图_pytest以函数形式的测试用例

    from __future__ import print_function #pytest以函数形式形成测试用例 def setup_module(module): print('\nsetup_mo ...

  6. python函数参数的作用是_python函数参数理解

    1.位置参数 函数调用时,参数赋值按照位置顺序依次赋值. e.g. 1 deffunction(x):2 3return x *x4 5print function(2) 输出结果: 4 1 deff ...

  7. python中get函数作用_python get函数有什么作用?示例解析

    这篇文章之中我们来了解一下关于python字典之中的pythonget函数的相关知识,get函数是什么意思,他有什么作用都将会在接下来的文章之中得到解答. 描述 Python 字典(Dictionar ...

  8. python map函数的作用_Python map()函数介绍及用法

    Python函数式编程之map() Python中map().filter().reduce()这三个都是应用于序列的内置函数. 格式: 1 map(func, seq1[, seq2,-]) 第一个 ...

  9. python info函数的作用是_Python函数__new__及__init__作用及区别解析

    [同] 二者均是Python面向对象语言中的函数,__new__比较少用,__init__则用的比较多. [异] __new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是 ...

最新文章

  1. 轮播图html_【技术篇前端】用html+css实现小米首页部分内容(含源码,不含轮播图)...
  2. 黑客发飙!智能汽车不太安全你还敢开?
  3. EOS 源代码解读 (4)交易数据结构
  4. java多线程总结五:线程池的原理及实现
  5. 使用VLC和live555MediaServer搭建RTSP服务器
  6. NIFI从mysql导入Hbase
  7. python技术是什么意思_python中“//”表示什么意思_后端开发
  8. CF1090F - How to Learn You Score(构造)
  9. 最长上升子序列——动态规划
  10. 缓存MEMCACHE 使用原子性操作add,实现并发锁
  11. 深度学习实践指南(一)—— 卷积和池化
  12. 十二、Oracle学习笔记:分页查询
  13. unix下matlab安装
  14. ISO50001认证咨询,新版标准更加强调持续改进能源绩效主要体现在以下方面
  15. 云计算对21世纪IT人才的挑战
  16. 1296. 划分数组为连续数字的集合
  17. 《心流》| 精神熵和负熵
  18. 基于Springboot的Java项目--新冠疫情统计系统
  19. 联想g510升级换什么cpu好_老775平台还有升级CPU的必要吗?实测来告诉你
  20. 使用canvas画美队盾牌

热门文章

  1. Pillow - putpixel操作 实现随机色的图片
  2. Citrix ADC 13.0 下载 百度网盘 按您的方式进行应用交付
  3. 设计模式 模板模式和策略模式
  4. CGAL例程:地理信息系统----点云数据生成DSM、DTM、等高线和数据分类
  5. 开源财务会计软件(搬运)
  6. 程序员过高工资导致加班?应该降低程序员工资?网友:放过其他苦逼的程序员吧
  7. 开机自检,BIOS运行原理
  8. 是对计算机系统或其他网络设备进行,计算机信息系统是由计算机及其相关的和配套的设备、设施(含网络)构成的,按照一定的应用目标和规则对信息进行()等处理的人机系统。...
  9. 你对区块链的理解还停留在炒币上吗
  10. idea keymap之前选择成 Eclipse 后,idea默认的快捷键Default找不到了的解决办法