AFL fuzz_one 中的优先级处理(favored)

fuzz_one中有这么一段代码,涉及到优先级操作:

  if (pending_favored) {

    /* If we have any favored, non-fuzzed new arrivals in the queue,
       possibly skip to them at the expense of already-fuzzed or non-favored
       cases. */

    if ((queue_cur->was_fuzzed || !queue_cur->favored) &&
        UR(100) < SKIP_TO_NEW_PROB) return 1;

  } else if (!dumb_mode && !queue_cur->favored && queued_paths > 10) {

    /* Otherwise, still possibly skip non-favored cases, albeit less often.
       The odds of skipping stuff are higher for already-fuzzed inputs and
       lower for never-fuzzed entries. */

    if (queue_cycle > 1 && !queue_cur->was_fuzzed) {

      if (UR(100) < SKIP_NFAV_NEW_PROB) return 1;

    } else {

      if (UR(100) < SKIP_NFAV_OLD_PROB) return 1;

    }

  }

首先要搞清楚pending_favored,was_fuzzed,favored这几个参数的意义,以及在哪赋值的

  1. pending_favored, /* Pending favored paths */
  2. was_fuzzed, /* Had any fuzzing done yet? */
  3. favored, /* Currently favored? */

pending_favored

这个参数在cull_queue函数中被使用

static void cull_queue(void) {

  struct queue_entry* q;
  static u8 temp_v[MAP_SIZE >> 3];
  u32 i;
  
  score_changed = 0;
  
  // 将temp_v全部置1,这个数组的每一位,用于追踪trace_bits中的一个字节
  memset(temp_v, 255, MAP_SIZE >> 3);

  // 分别记录队列中有多少favored元素,和剩余多少favored元素
  queued_favored  = 0;
  pending_favored = 0;

  q = queue;

  // 遍历所有元素,将其favored置0
  while (q) {
    q->favored = 0;
    q = q->next;
  }

  /* Let's see if anything in the bitmap isn't captured in temp_v.
     If yes, and if it has a top_rated[] contender, let's use it. */

  for (i = 0; i < MAP_SIZE; i++)
    // temp_v[i >> 3]确定所属字节
    // temp_v[i >> 3] & (1 << (i & 7))确定所属位
    // 如果top_rated[i]存在,并且temp_v为1
    if (top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) {

      u32 j = MAP_SIZE >> 3;

      /* Remove all bits belonging to the current entry from temp_v. */
      // 这一步是为了从 temp_v 中清除top_rated[i]已经覆盖的位,这样,选出来的favored 的testcase可以覆盖所有的bit
      while (j--) 
        if (top_rated[i]->trace_mini[j])
          temp_v[j] &= ~top_rated[i]->trace_mini[j];

      top_rated[i]->favored = 1;
      queued_favored++;

      if (!top_rated[i]->was_fuzzed) pending_favored++;

    }

  // mark_as_redundant,这个函数暂时不想看,后续再看
  q = queue;

  while (q) {
    mark_as_redundant(q, !q->favored);
    q = q->next;
  }

}

这里不太清楚top_rated的含义,所以去看了下top_rated在哪些地方被使用
在这里插入图片描述
这个变量在update_bitmap_score被使用,而update_bitmap_score又是在calibrate_case被调用。

回顾一下之前学习到的perform_dry_run知识:https://blog.csdn.net/weixin_44033321/article/details/136430578
calibrate_case调用run_target执行目标testcase 3/8次,同时也调用了在这里插入图片描述
当时没有细看这段代码,现在开始详细看:

/* When we bump into a new path, we call this to see if the path appears
   more "favorable" than any of the existing ones. The purpose of the
   "favorables" is to have a minimal set of paths that trigger all the bits
   seen in the bitmap so far, and focus on fuzzing them at the expense of
   the rest.

   The first step of the process is to maintain a list of top_rated[] entries
   for every byte in the bitmap. We win that slot if there is no previous
   contender, or if the contender has a more favorable speed x size factor. */

/* 评估一条新路径,是否比现有路径更加“favorable”,目的是用更少的testcase,来覆盖更多的路径,并在
   接下来更多的fuzz这些路径。
   为bitmap中的每个byte维护一个top_rated[]表项 
   top_rated[]记录在当前bit,哪个testcase是最优的*/

static void update_bitmap_score(struct queue_entry* q) {

  u32 i;
  // 当前队列条目的执行时间与长度的乘积,用于评估路径的优劣
  u64 fav_factor = q->exec_us * q->len;

  /* For every byte set in trace_bits[], see if there is a previous winner,
     and how it compares to us. */

  for (i = 0; i < MAP_SIZE; i++)

    if (trace_bits[i]) {

       // 刚开始top_rated为0,不进到这个if,直接给top_rated[i]赋值为当前的q
       // 如果top_rated不为0,那么就要进行一些比较
       if (top_rated[i]) {

         /* Faster-executing or smaller test cases are favored. */
         // 是否执行更快+更小?
         if (fav_factor > top_rated[i]->exec_us * top_rated[i]->len) continue;

         /* Looks like we're going to win. Decrease ref count for the
            previous winner, discard its trace_bits[] if necessary. */
         // 是否tc_ref全为0,如果全为0,清除trace_mini 
         if (!--top_rated[i]->tc_ref) {
           ck_free(top_rated[i]->trace_mini);
           top_rated[i]->trace_mini = 0;
         }

       }

       /* Insert ourselves as the new winner. */
       // 更新top_rated[i]为testcase q
       top_rated[i] = q;  
       /* 问了下bing,这个参数的意义是:这是一个计数器,代表“test case reference count”,
       即测试用例的引用计数。每当一个测试用例(队列条目)被标记为某个字节的top_rated赢家时,
       它的tc_ref就会增加。如果一个测试用例不再是任何字节的top_rated赢家,它的tc_ref就会减少。
       当tc_ref降到0时,表示没有任何字节将这个测试用例作为最优选项,相关资源可以被释放。 */
       q->tc_ref++;

       // 如果 q->trace_mini 为空,那么为其分配内存trace_mini相当于一个缩减版的trace_bits
       // 将trace_bits转换为trace_mini,如果trace_bits的某字节非0,那么trace_mini相应的位就为1
       if (!q->trace_mini) {
         q->trace_mini = ck_alloc(MAP_SIZE >> 3);
         minimize_bits(q->trace_mini, trace_bits);
       }

       score_changed = 1;

     }

}

ok,现在明白top_rated的含义了,top_rated存储的就是,对每个插桩来说,最优testcase。

继续看cull_queue函数。主要内容在代码上进行了注释。现在总结一下:
这个函数的主要功能是筛选当前的testcase,获得一个最小的testcase集合,并且这个testcase集合能够覆盖全集合能够覆盖的所有bitmap。
temp_v:一个关键参数,这个参数记录了 这些已经选出的testcase 不能覆盖到的 bitmap(刚开始为全1)。
queued_favored:favored的testcase的数量
pending_favored:if (!top_rated[i]->was_fuzzed) pending_favored++;,没被fuzzed的testcase的数量。
执行过程:首先,函数通过一个for循环,来遍历bitmap的所有65535字节,如果当前字节存在一个top_rated[i],并且这个字节没有被其他的testcase覆盖((temp_v[i >> 3] & (1 << (i & 7))),那么就把这个字节定义为favored,并在temp_v中删除这个testcase覆盖到的字节。

现在也了解了pending_favored参数的含义,这是一个计数器,任何被标记为favored,但是没被标记为was_fuzzed的testcase,就会被统计在pending_favored。

was_fuzzed,目前仍不知道这个参数是在那里赋值的,但是大概了解了其意思,就是在某一轮fuzz中被处理过的testcase。

favored,通过cull_queue函数筛选出来的testcase。

现在回到最开始那段代码:

  // 如果存在favored,但是没被处理的testcase
  if (pending_favored) {

    /* If we have any favored, non-fuzzed new arrivals in the queue,
       possibly skip to them at the expense of already-fuzzed or non-favored
       cases. */
    // 如果queue_cur->was_fuzzed || !queue_cur->favored,那么就以99%的概率直接返回1
    if ((queue_cur->was_fuzzed || !queue_cur->favored) &&
        UR(100) < SKIP_TO_NEW_PROB) return 1;

  } else if (!dumb_mode && !queue_cur->favored && queued_paths > 10) {

    /* Otherwise, still possibly skip non-favored cases, albeit less often.
       The odds of skipping stuff are higher for already-fuzzed inputs and
       lower for never-fuzzed entries. */
    // 仍然以一定概率跳过不被 favored 的testcase
    if (queue_cycle > 1 && !queue_cur->was_fuzzed) {

      if (UR(100) < SKIP_NFAV_NEW_PROB) return 1;

    } else {

      if (UR(100) < SKIP_NFAV_OLD_PROB) return 1;

    }

  }

总结一下,这个函数就是,以一定概率,跳过某些“不够好”的testcase。在这里插入代码片

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值