AFL trace_bits和virgin_bits

记录一下所遇到的和AFL覆盖率相关的参数

trace_bits

65536字节
在二进制文件中的插桩会直接修改trace_bits。
如何修改? 参考这篇博客https://blog.csdn.net/weixin_45100742/article/details/135426994
写的很清楚,trace_bits记录的是分支覆盖率,并且分支每被执行一次,就会+1

virgin_bits

这个参数在calibrate_case函数中被使用。
首先,这个参数是什么意思? fuzzing目前没有涉及到的区域
在这里插入图片描述
问bing:具体来说,virgin_bits数组的每个元素对应于trace_bits数组的一个字节,它表示该字节是否被置位过,即是否覆盖了一个新的执行路径。如果是,那么virgin_bits数组的相应元素就会被清零,否则就保持为255。
看了下这篇博客:https://blog.csdn.net/weixin_50972562/article/details/124327119,virgin_bits 记录总的路径信息
大概意思是,virgin_bits记录了所有已经被发现的路径?
那么,是记录当前testcase覆盖的路径,还是所有的?

先去看看calibrate_case中的这个函数 hnb = has_new_bits(virgin_bits);看看能否获得答案(删减部分内容)

/* Check if the current execution path brings anything new to the table.
   Update virgin bits to reflect the finds. Returns 1 if the only change is
   the hit-count for a particular tuple; 2 if there are new tuples seen. 
   Updates the map, so subsequent calls will always return 0. */

static inline u8 has_new_bits(u8* virgin_map) {

  // 跟run_target里面处理trace_bits类似,都是以8字节为单位进行处理的。i=8192
  u64* current = (u64*)trace_bits;
  u64* virgin  = (u64*)virgin_map;
  
  u32  i = (MAP_SIZE >> 3);

  u8   ret = 0;

  while (i--) {

    /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap
       that have not been already cleared from the virgin map - since this will
       almost always be the case. */
    
    // trace_bits中包含该位(被覆盖),
    if (unlikely(*current) && unlikely(*current & *virgin)) {

      if (likely(ret < 2)) {

        u8* cur = (u8*)current;
        u8* vir = (u8*)virgin;

        /* Looks like we have not found any new bytes yet; see if any non-zero
           bytes in current[] are pristine in virgin[]. */

        if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
            (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) ||
            (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) ||
            (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff)) ret = 2;
        else ret = 1;

      }
      
      // 把覆盖到的位置0
      *virgin &= ~*current;

    }

    current++;
    virgin++;

  }
  
  if (ret && virgin_map == virgin_bits) bitmap_changed = 1;

  return ret;

}

这个函数的作用是检查当前执行路径是否发现了新的覆盖点,即是否触发了新的分支或边。它会更新virgin_map参数,这是一个数组,用于保存后续模糊测试中覆盖的路径。函数的返回值有三种可能:

0:表示当前执行路径没有发现任何新的覆盖点,即与之前的测试用例没有区别。
1:表示当前执行路径只发现了新的hit-count,即某个分支或边的执行次数发生了变化,但没有发现新的分支或边。
2:表示当前执行路径发现了新的分支或边,即增加了覆盖率。

在网上搜索了下这个函数,仅有的几个中文博客写的都比较模糊,再大概解释下:
最前面那段注释,说的是ret(返回值),如果返回2,说明覆盖了新路径;如果返回1,说明路径的执行次数发生了变化;如果返回0,说明覆盖率没有发生变化。
*virgin &= ~*current;这句代码用来更新virgin_bits。

现在也理解为什么virgin_bits的注释是Regions yet untouched by fuzzing,virgin_bits的初始值全是1,如果某些路径被覆盖到了,就置0。(置1=Regions yet untouched=未被覆盖到)
而virgin翻译为:处女,童男;无经验的人,新手,这就合理了。

现在可以回答问题了,virgin_bits记录所有的testcase覆盖的路径。

到目前为止,把calibrate_case函数看了个差不多,明天继续往下看。


在分析fuzz_one havoc_stage的处理时,有这么一段代码:

        simplify_trace((u64*)trace_bits);
        // 如果没有触发新的覆盖,那么就返回函数
        if (!has_new_bits(virgin_tmout)) return keeping;

simplify_trace把trace按字节进行了处理,被覆盖到的转换为0x80,没被覆盖到的转换为0x01,现在想要搞明白一个事情,simplify_trace的处理结果,会不会对has_new_bits的结果产生影响。

个人感觉这里逻辑有点难懂,simplify_trace处理后,trace_bits的每一位,要么是0x01,要么是0x80。

第一次调用has_new_bits(virgin_tmout),*current一定为真,*current & *virgin也一定为真,virgin_tmout的第1位,或者第8位会被置0。

如果第1位置0,下次输入为0x01,current & *virgin为0,不处理。
如果第1位置0,下次输入为0x80,current & *virgin为1,处理,返回1,第1,8位全置0,之后永远不处理。
如果第8位置0,下次输入为0x01,current & *virgin为1,处理,返回1,第1,8位全置0,之后永远不处理。
如果第8位置0,下次输入为0x80,current & *virgin为1,不处理。

第1位置0,下次输入为0x80,意味着本来没被覆盖,现在被覆盖了,返回1是合理的。
第8位置0,下次输入为0x01,意味着本来被覆盖,现在没被覆盖,返回1不合理。因为并没有带来新的覆盖率。

这个地方还是搞不太清楚,留着以后解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值