afl-fuzz.c精注释版

我感觉我一行一行写注释这种行为本身就很傻。。
关键的地方作者都写过注释了,我就觉得我这一行行写很不合适,下次读源码还是用眼看吧,想记得地方再写文档上吧,这次接上次还是参考的https://bbs.pediy.com/thread-265936.htm,这份博客,发现可能是版本差异,有些源码不同,不过不碍事,其实注释算是硬写上去的,就把作者的英文注释翻译了一下,我真觉得我这一行行写注释行为太不可取了,真的
我就只贴个main吧,全贴发不出来
我发到github上了,向要的可以自己拿,在这里
也可以在我博客上看,这才8000多行csdn就发不上来了

afl-fuzz.c

main

int main(int argc, char** argv) {
//妈的main真长。。。。
  s32 opt;
  u64 prev_queued = 0;
  u32 sync_interval_cnt = 0, seek_to;
  u8  *extras_dir = 0;
  u8  mem_limit_given = 0;
  u8  exit_1 = !!getenv("AFL_BENCH_JUST_ONE");
  char** use_argv;

  struct timeval tv;
  struct timezone tz;

  SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by <lcamtuf@google.com>\n");

  doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
  //首先调用gettimeofday
  gettimeofday(&tv, &tz);
  //根据时间与当前进程pid做异或来设定种子,保证了随机性
  srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
  //一个很大很大的循环,通过getopt扫描argv里面的参数,类似如下
  //  /Users/apple/Desktop/AFL/AFL/cmake-build-debug/afl-fuzz -i input -o output -- ./test
  while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:Q")) > 0)
    //扫描到的字符,对应的操作
    switch (opt) {
      //如果是-i
      case 'i': /* input dir */

        if (in_dir) FATAL("Multiple -i options not supported");
        //将-i之后的input赋值给in_dir,optarg没找到在哪声明的
        in_dir = optarg;
        //如果此时的 in_dir = "-",那么设置 - in_place_resume = 1
        if (!strcmp(in_dir, "-")) in_place_resume = 1;

        break;
      //扫到-o 
      case 'o': /* output dir */

        if (out_dir) FATAL("Multiple -o options not supported");
        //将-o的参数output赋值给out_dir
        out_dir = optarg;
        break;

//剩下的以下这些case以后再分析
      
      case 'M': { /* master sync ID */

          u8* c;

          if (sync_id) FATAL("Multiple -S or -M options not supported");
          sync_id = ck_strdup(optarg);

          if ((c = strchr(sync_id, ':'))) {

            *c = 0;

            if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 ||
                !master_id || !master_max || master_id > master_max ||
                master_max > 1000000) FATAL("Bogus master ID passed to -M");

          }

          force_deterministic = 1;

        }

        break;

      case 'S': 

        if (sync_id) FATAL("Multiple -S or -M options not supported");
        sync_id = ck_strdup(optarg);
        break;

      case 'f': /* target file */

        if (out_file) FATAL("Multiple -f options not supported");
        out_file = optarg;
        break;

      case 'x': /* dictionary */

        if (extras_dir) FATAL("Multiple -x options not supported");
        extras_dir = optarg;
        break;

      case 't': { /* timeout */

          u8 suffix = 0;

          if (timeout_given) FATAL("Multiple -t options not supported");

          if (sscanf(optarg, "%u%c", &exec_tmout, &suffix) < 1 ||
              optarg[0] == '-') FATAL("Bad syntax used for -t");

          if (exec_tmout < 5) FATAL("Dangerously low value of -t");

          if (suffix == '+') timeout_given = 2; else timeout_given = 1;

          break;

      }

      case 'm': { /* mem limit */

          u8 suffix = 'M';

          if (mem_limit_given) FATAL("Multiple -m options not supported");
          mem_limit_given = 1;

          if (!strcmp(optarg, "none")) {

            mem_limit = 0;
            break;

          }

          if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
              optarg[0] == '-') FATAL("Bad syntax used for -m");

          switch (suffix) {

            case 'T': mem_limit *= 1024 * 1024; break;
            case 'G': mem_limit *= 1024; break;
            case 'k': mem_limit /= 1024; break;
            case 'M': break;

            default:  FATAL("Unsupported suffix or bad syntax for -m");

          }

          if (mem_limit < 5) FATAL("Dangerously low value of -m");

          if (sizeof(rlim_t) == 4 && mem_limit > 2000)
            FATAL("Value of -m out of range on 32-bit systems");

        }

        break;

      case 'd': /* skip deterministic */

        if (skip_deterministic) FATAL("Multiple -d options not supported");
        skip_deterministic = 1;
        use_splicing = 1;
        break;

      case 'B': /* load bitmap */

        /* This is a secret undocumented option! It is useful if you find
           an interesting test case during a normal fuzzing process, and want
           to mutate it without rediscovering any of the test cases already
           found during an earlier run.

           To use this mode, you need to point -B to the fuzz_bitmap produced
           by an earlier run for the exact same binary... and that's it.

           I only used this once or twice to get variants of a particular
           file, so I'm not making this an official setting. */

        if (in_bitmap) FATAL("Multiple -B options not supported");

        in_bitmap = optarg;
        read_bitmap(in_bitmap);
        break;

      case 'C': /* crash mode */

        if (crash_mode) FATAL("Multiple -C options not supported");
        crash_mode = FAULT_CRASH;
        break;

      case 'n': /* dumb mode */

        if (dumb_mode) FATAL("Multiple -n options not supported");
        if (getenv("AFL_DUMB_FORKSRV")) dumb_mode = 2; else dumb_mode = 1;

        break;

      case 'T': /* banner */

        if (use_banner) FATAL("Multiple -T options not supported");
        use_banner = optarg;
        break;

      case 'Q': /* QEMU mode */

        if (qemu_mode) FATAL("Multiple -Q options not supported");
        qemu_mode = 1;

        if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;

        break;

      default:

        usage(argv[0]);

    }

  if (optind == argc || !in_dir || !out_dir) usage(argv[0]);
//参数处理完毕后,调用setup_siginal_handlers设置信号处理句柄
  setup_signal_handlers();
//调用check_asan_opts见哈asan设置是否正确
  check_asan_opts();
//上面这俩函数的实现都比较短
  //如果设置了sync_id,那么在fix_up_sync中检测是否有互斥的参数
  if (sync_id) fix_up_sync();
  //检查是否一样
  if (!strcmp(in_dir, out_dir))
    FATAL("Input and output directories can't be the same");
  //如果设置了dumb_mode,那么不能设置crash_mode或qemu_mode,因为互斥
  if (dumb_mode) {

    if (crash_mode) FATAL("-C and -n are mutually exclusive");
    if (qemu_mode)  FATAL("-Q and -n are mutually exclusive");

  }
  //获取几个环境变量,如果有就设置对应值
  if (getenv("AFL_NO_FORKSRV"))    no_forkserver    = 1;
  if (getenv("AFL_NO_CPU_RED"))    no_cpu_meter_red = 1;
  if (getenv("AFL_NO_ARITH"))      no_arith         = 1;
  if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue    = 1;
  if (getenv("AFL_FAST_CAL"))      fast_cal         = 1;
  //通过AFL_HANG_TMOUT设置对应的hang_out时间
  if (getenv("AFL_HANG_TMOUT")) {
    //ascii转int
    hang_tmout = atoi(getenv("AFL_HANG_TMOUT"));
    if (!hang_tmout) FATAL("Invalid value of AFL_HANG_TMOUT");
  }
//dumb_mode == 2 与 no_forkserver互斥
  if (dumb_mode == 2 && no_forkserver)
    FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive");
//设置LD_PRELOAD和DYLD_INSERT_LIBRARIES为AFL_PRELOAD
  if (getenv("AFL_PRELOAD")) {
    setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
    setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
  }

  if (getenv("AFL_LD_PRELOAD"))
    FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD");
  //save_cmdline 保存argv到局部变量buf中,代码很短自己看一下
  save_cmdline(argc, argv);
  //又是检查,比较短,不想看了
  fix_up_banner(argv[optind]);
  //检查!!检查是否是终端环境
  check_if_tty();
  //获取cpu数量,还分平台
  get_core_count();
//然后根据亲缘性设置绑定CPU
//这玩意我不懂。。,回头再分析吧
#ifdef HAVE_AFFINITY
  bind_to_free_cpu();
#endif /* HAVE_AFFINITY */
  //检查core dump设置是否正确
  check_crash_handling();
  //字面意思
  check_cpu_governor();
  //加载进来一个动态链接库,获取里面的后处理程序
  setup_post();
  //设置共享内存和virgin_bits
  setup_shm();
  //初始化count_class_lookup16数组,为分支路径的规整做准备
  init_count_class16();
  //创建一些相关文件夹,写入一些信息
  //准备输出到的文件以及fds
  setup_dirs_fds();
  //读取测试用例并入队,在启动时调用
  read_testcases();
  //加载automatically generated extras
  load_auto();
  //在输出目录中为输入测试用例创建硬链接,选择好名字,并据此进行调整
  pivot_inputs();
  //如果设置了extras_dir
  //就调用函数加载extras_dir下的文件放入extras数组并排序
  if (extras_dir) load_extras(extras_dir);
  //如果没设置timeout_given那么调用find_timeout设置超时时间
  if (!timeout_given) find_timeout();
  //检测sargs中的'@@'并替换
  detect_file_args(argv + optind + 1);
  //如果没设置out_file,调用函数
  //在output/.cur_input新建一个文件作为输出
  if (!out_file) setup_stdio_file();
  //检查目标文件的有效性,是否是可执行文件,是否式Mach-O还是ELF还是一个生成的shell文件
  check_binary(argv[optind]);
  //获取当前时间
  start_time = get_cur_time();
  //如果是qemu_mode
  if (qemu_mode)
  //为qemu重写参数
    use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
  else
  //否则简单粗暴
    use_argv = argv + optind;
  //对所有测试用例执行试运行,以确认该应用程序按照预期正常运行。
  //仅对初始输入执行此操作,并且仅执行一次
  //好些我都是抄的注释(狗头
  perform_dry_run(use_argv);
  //精简队列
  cull_queue();
  //向用户展示初始化状态信息
  show_init_stats();
  //进去
  seek_to = find_start_position();
  //更新统计信息文件以进行无人值守的监视
  write_stats_file(0, 0, 0);
  //前面调用过一次
  save_auto();
  //如果设置了stop_soon,就跳转到stop_fuzzing
  if (stop_soon) goto stop_fuzzing;

  /* Woop woop woop */
  //如果是tty启动(终端),那么先sleep 4 秒,start_time += 4000
  if (!not_on_tty) {
    sleep(4);
    start_time += 4000;
    //再检测如果设置了stop_soon,跳转到stop_fuzzing
    if (stop_soon) goto stop_fuzzing;
  }
//至此,整个启动前的初始化完成,准备进入fuzz主循环
  while (1) {

    u8 skipped_fuzz;
    //简化队列
    cull_queue();
    //queue_cur指向目前队列中的元素
    //初始化是空的,不为空说明扫过一次了
    if (!queue_cur) {
      //循环计数器加1
      queue_cycle++;
      //归零
      current_entry     = 0;
      //归零
      cur_skipped_paths = 0;
      //重新指向队头,afl就是这么可怕
      queue_cur         = queue;
      //如果seek_to不为0,没注释的局部变量
      while (seek_to) {
        current_entry++;
        //直达seek_to==0才会停,似乎是用seek_to记录上次队列位置,这次从那开始
        seek_to--;
        //queue_cur后移
        queue_cur = queue_cur->next;
      }
      //展示状态
      show_stats();
      //如果不是终端模式即:not_on_tty==1
      if (not_on_tty) {
        //输出当前是第几个循环
        ACTF("Entering queue cycle %llu.", queue_cycle);
        //清输出缓存
        fflush(stdout);
      }

      /* If we had a full queue cycle with no new finds, try
         recombination strategies next. */
      //如果我们经历了一个完整的扫描周期后都没有新的路径发现,那么尝试调整策略
      //如果queue_path==prev_queued
      if (queued_paths == prev_queued) {
        //当设置了use_splicing,cycles_wo_finds计数加1,否则use_splicing为1
        if (use_splicing) cycles_wo_finds++; else use_splicing = 1;
      //否则设置cycles_wo_finds为0
      } else cycles_wo_finds = 0;
      //令prev_queued等于queued_paths
      prev_queued = queued_paths;
      //如果设置了syn_id并且queue_cycle==1并且环境变量中有这个
      if (sync_id && queue_cycle == 1 && getenv("AFL_IMPORT_FIRST"))
        //调用syn_fuzzers,同步其他fuzzer
        sync_fuzzers(use_argv);

    }
    //调用fuzz_one(use_argv)对于我们的样本进行变换后fuzz,返回skipped_fuzz
    skipped_fuzz = fuzz_one(use_argv);
    //如果skipped_fuzz为且这样这样
    if (!stop_soon && sync_id && !skipped_fuzz) {
      //如果sync_interval_cnt没有到一个周期
      if (!(sync_interval_cnt++ % SYNC_INTERVAL))
      //调用同步其他fuzzer
        sync_fuzzers(use_argv);

    }
    //如果没有设置stop_soon,且 exit_1不为0
    //那么设置stop_soon=2后break处fuzz主循环
    if (!stop_soon && exit_1) stop_soon = 2;

    if (stop_soon) break;
    //否则准备下一个样本
    queue_cur = queue_cur->next;
    current_entry++;

  }
  //主循环结束了,输出/更新一些状态
  if (queue_cur) show_stats();

  write_bitmap();
  write_stats_file(0, 0, 0);
  save_auto();

stop_fuzzing:

  SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST,
       stop_soon == 2 ? "programmatically" : "by user");

  /* Running for more than 30 minutes but still doing first cycle? */

  if (queue_cycle == 1 && get_cur_time() - start_time > 30 * 60 * 1000) {

    SAYF("\n" cYEL "[!] " cRST
           "Stopped during the first cycle, results may be incomplete.\n"
           "    (For info on resuming, see %s/README.)\n", doc_path);

  }
  //主循环结束后,销毁内存空间
  //关闭描述符,至此整个afl的fuzz过程就结束了
  fclose(plot_file);
  destroy_queue();
  destroy_extras();
  ck_free(target_path);
  ck_free(sync_id);

  alloc_report();

  OKF("We're done here. Have a nice day!\n");

  exit(0);

}

#endif /* !AFL_LIB */
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值