AFL源码分析之afl-fuzz(学习笔记)(一)

一、源码

1.信号处理函数

/* Handle stop signal (Ctrl-C, etc). */
/*手动停止信号*/
static void handle_stop_sig(int sig) {

  stop_soon = 1; //设置stop_soon为1

  if (child_pid > 0) kill(child_pid, SIGKILL);//如果child_pid存在,向其发送SIGKILL终止信号,从而被系统杀死
  if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL);//如果forksrv_pid存在,向其发送SIGKILL终止信号

}


/* Handle skip request (SIGUSR1). */
//处理跳过请求
static void handle_skipreq(int sig) {

  skip_requested = 1;//设置skip_requested=1

}

/* Handle timeout (SIGALRM). */
//处理超时的情况
static void handle_timeout(int sig) {

  if (child_pid > 0) {//如果child_pid>0,则设置child_timed_out为1,并kill掉child_pid

    child_timed_out = 1; 
    kill(child_pid, SIGKILL);

  } else if (child_pid == -1 && forksrv_pid > 0) {//如果child_pid==-1,且forksrv_pid>0,则设置child_timed_out为1,并kill掉forksrv_pid

    child_timed_out = 1; 
    kill(forksrv_pid, SIGKILL);

  }

}
/* Handle screen resize (SIGWINCH). */
//处理窗口大小的变化信号
static void handle_resize(int sig) {
  clear_screen = 1;//设置clear_screen=1
}

* Set up signal handlers. More complicated that needs to be, because libc on
   Solaris doesn't resume interrupted reads(), sets SA_RESETHAND when you call
   siginterrupt(), and does other unnecessary things. */
/*设置信号处理程序。这需要更加复杂,因为libcSolaris不会恢复中断读取(),在调用时设置SA_RESETHAND
siginterrupt(),并执行其他不必要的操作*/
EXP_ST void setup_signal_handlers(void) {//注册必要的信号处理函数

  struct sigaction sa;

  sa.sa_handler   = NULL;//处理函数指针,相当于signal函数的func参数。
  sa.sa_flags     = SA_RESTART; //信号处理修改器
  sa.sa_sigaction = NULL;//设置sigaction为NULL

  sigemptyset(&sa.sa_mask);//sa_mask 的值通常是通过使用信号集函数来设置的  初始为空

  /* Various ways of saying "stop". */

  sa.sa_handler = handle_stop_sig;
  sigaction(SIGHUP, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);
  sigaction(SIGTERM, &sa, NULL);

  /* Exec timeout notifications. */

  sa.sa_handler = handle_timeout;
  sigaction(SIGALRM, &sa, NULL);

  /* Window resize */

  sa.sa_handler = handle_resize;
  sigaction(SIGWINCH, &sa, NULL);

  /* SIGUSR1: skip entry */

  sa.sa_handler = handle_skipreq;
  sigaction(SIGUSR1, &sa, NULL);

  /* Things we don't care about. */

  sa.sa_handler = SIG_IGN;
  sigaction(SIGTSTP, &sa, NULL);
  sigaction(SIGPIPE, &sa, NULL);

}

2.check_asan_opts(检查内存错误)

/* Check ASAN options. */

static void check_asan_opts(void) {
  u8* x = getenv("ASAN_OPTIONS");//读取环境变量ASAN_OPTIONS

  if (x) {

    if (!strstr(x, "abort_on_error=1")) //检查是否设置了abort_on_error=1,如果没有抛异常
      FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");//不带中止abort_on_error=1-请修复!

    if (!strstr(x, "symbolize=0"))//检查是否设置了symbolize=0,如果没有抛异常
      FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");

  }

  x = getenv("MSAN_OPTIONS");//读取环境变量MSAN_OPTIONS

  if (x) {

    if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR)))
      FATAL("Custom MSAN_OPTIONS set without exit_code="
            STRINGIFY(MSAN_ERROR) " - please fix!");

    if (!strstr(x, "symbolize=0"))
      FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");

  }

} 

3.fix_up_sync(检查ID、sync_id是否过长,检查互斥)

/* Validate and fix up out_dir and sync_dir when using -S. */
//使用-S时验证并修复out_dir和sync_dir。
static void fix_up_sync(void) {

  u8* x = sync_id;

  if (dumb_mode)
    FATAL("-S / -M and -n are mutually exclusive");//-S/-M和-n是互斥的

  if (skip_deterministic) {

    if (force_deterministic)
      FATAL("use -S instead of -M -d");
    else
      FATAL("-S already implies -d");

  }

  while (*x) {

    if (!isalnum(*x) && *x != '_' && *x != '-')
      FATAL("Non-alphanumeric fuzzer ID specified via -S or -M");//通过-S或-M指定的非字母数字fuzzer ID

    x++;

  }

  if (strlen(sync_id) > 32)//如果sync_id超过32位报错
   FATAL("Fuzzer ID too long");

  x = alloc_printf("%s/%s", out_dir, sync_id);

  sync_dir = out_dir;//设置sync_dir的值为out_dir
  out_dir  = x;//设置out_dir的值为out_dir/sync_id

  if (!force_deterministic) {//如果没有设置force_deterministic
    skip_deterministic = 1;//设置skip_deterministic为1
    use_splicing = 1;//设置use_splicing为1
  }

}

4.save_cmdline(将当前输入参数拷贝进buf空间中)

/* Make a copy of the current command line. *//*复制当前命令行*/

static void save_cmdline(u32 argc, char** argv) {

  u32 len = 1, i;
  u8* buf;

  for (i = 0; i < argc; i++)
    len += strlen(argv[i]) + 1;//计算参数长度
  
  buf = orig_cmdline = ck_alloc(len);//给参数分配内存空间

  for (i = 0; i < argc; i++) {

    u32 l = strlen(argv[i]);//计算长度

    memcpy(buf, argv[i], l); //将argv[i]中的内容存放至buf空间
    buf += l;

    if (i != argc - 1) *(buf++) = ' ';

  }

  *buf = 0;

}

5.fix_up_banner(修剪并且创建一个运行横幅)

/* Trim and possibly create a banner for the run. */

static void fix_up_banner(u8* name) {

  if (!use_banner) {//如果没有设置use_banner

    if (sync_id) {//如果没有设置use_banner

      use_banner = sync_id;//将sync_id赋值给use_banner

    } else {

      u8* trim = strrchr(name, '/'); //获取最后一个参数中最后一个“/”后的内容
      if (!trim)//如果没有获取到
       use_banner = name;//将目标文件路径赋值给use_banner
      else 
        use_banner = trim + 1;

    }

  }

  if (strlen(use_banner) > 40) {//如果use_banner长度超过40,

    u8* tmp = ck_alloc(44);//分配44的空间给tmp
    sprintf(tmp, "%.40s...", use_banner);//取use_banner的前40个字节并在其后面加省略号
    use_banner = tmp;//将tmp赋值给use_banner

  }

}

6.check_if_tty(检查是否在tty终端上面运行)

/* Check if we're on TTY. */

static void check_if_tty(void) {

  struct winsize ws;

  if (getenv("AFL_NO_UI")) {//如果设置了AFL_NO_UI环境变量

    OKF("Disabling the UI because AFL_NO_UI is set.");//禁用UI
    not_on_tty = 1; //设置not_on_tty的值设为1
    return;
  }

  if (ioctl(1, TIOCGWINSZ, &ws)) {//获取窗口大小

    if (errno == ENOTTY) {//如果报错为ENOTTY
      OKF("Looks like we're not running on a tty, so I'll be a bit less verbose.");//看起来我们没有在tty上运行,所以我会少一点冗长。
      not_on_tty = 1;
    }

    return;
  }

}

7.get_core_count(计算逻辑CPU核的数量)

/* Count the number of logical CPU cores. */

static void get_core_count(void) {

  u32 cur_runnable = 0;

8.check_crash_handling(确保核心转储不会进入程序)

/* Make sure that core dumps don't go to a program. */

static void check_crash_handling(void) {

#ifdef __APPLE__

  /* Yuck! There appears to be no simple C API to query for the state of 
     loaded daemons on MacOS X, and I'm a bit hesitant to do something
     more sophisticated, such as disabling crash reporting via Mach ports,
     until I get a box to test the code. So, for now, we check for crash
     reporting the awful way. */
  
  if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash$'")) return;

  SAYF("\n" cLRD "[-] " cRST
       "Whoops, your system is configured to forward crash notifications to an\n"
       "    external crash reporting utility. This will cause issues due to the\n"
       "    extended delay between the fuzzed binary malfunctioning and this fact\n"
       "    being relayed to the fuzzer via the standard waitpid() API.\n\n"
       "    To avoid having crashes misinterpreted as timeouts, please run the\n" 
       "    following commands:\n\n"

       "    SL=/System/Library; PL=com.apple.ReportCrash\n"
       "    launchctl unload -w ${SL}/LaunchAgents/${PL}.plist\n"
       "    sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist\n");

  if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"))//如果没有获取环境变量AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES
    FATAL("Crash reporter detected");

#else

  /* This is Linux specific, but I don't think there's anything equivalent on
     *BSD, so we can just let it slide for now. */

  s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY);
  u8  fchar;

  if (fd < 0) return;

  ACTF("Checking core_pattern...");

  if (read(fd, &fchar, 1) == 1 && fchar == '|') {

    SAYF("\n" cLRD "[-] " cRST
         "Hmm, your system is configured to send core dump notifications to an\n"
         "    external utility. This will cause issues: there will be an extended delay\n"
         "    between stumbling upon a crash and having this information relayed to the\n"
         "    fuzzer via the standard waitpid() API.\n\n"

         "    To avoid having crashes misinterpreted as timeouts, please log in as root\n" 
         "    and temporarily modify /proc/sys/kernel/core_pattern, like so:\n\n"

         "    echo core >/proc/sys/kernel/core_pattern\n");

    if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"))//如果没有获取环境变量AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES
      FATAL("Pipe at the beginning of 'core_pattern'");//报错

  }
 
  close(fd);

#endif /* ^__APPLE__ */

}


9.check_cpu_governor(检查CPU管理者)


/* Check CPU governor. */

static void check_cpu_governor(void) {

  FILE* f;
  u8 tmp[128];
  u64 min = 0, max = 0;

  if (getenv("AFL_SKIP_CPUFREQ")) //获取环境变量AFL_SKIP_CPUFREQ
  return;

  f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r");//打开文件只读
  if (!f) 
  return;

  ACTF("Checking CPU scaling governor...");//“正在检查CPU比例调节器…”

  if (!fgets(tmp, 128, f)) PFATAL("fgets() failed");

  fclose(f);

  if (!strncmp(tmp, "perf", 4)) return;

  f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", "r");

  if (f) {
    if (fscanf(f, "%llu", &min) != 1) min = 0;
    fclose(f);
  }

  f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", "r");

  if (f) {
    if (fscanf(f, "%llu", &max) != 1) max = 0;
    fclose(f);
  }

  if (min == max) return;

  SAYF("\n" cLRD "[-] " cRST
       "Whoops, your system uses on-demand CPU frequency scaling, adjusted\n"
       "    between %llu and %llu MHz. Unfortunately, the scaling algorithm in the\n"
       "    kernel is imperfect and can miss the short-lived processes spawned by\n"
       "    afl-fuzz. To keep things moving, run these commands as root:\n\n"

       "    cd /sys/devices/system/cpu\n"
       "    echo performance | tee cpu*/cpufreq/scaling_governor\n\n"

       "    You can later go back to the original state by replacing 'performance' with\n"
       "    'ondemand'. If you don't want to change the settings, set AFL_SKIP_CPUFREQ\n"
       "    to make afl-fuzz skip this check - but expect some performance drop.\n",
       min / 1024, max / 1024);

  FATAL("Suboptimal CPU scaling governor");

}

10.setup_post(加载后处理器(如果可用))

/* Load postprocessor, if available. */

static void setup_post(void) {

  void* dh;
  u8* fn = getenv("AFL_POST_LIBRARY");//获取环境变量AFL_POST_LIBRARY
  u32 tlen = 6;

  if (!fn)//如果没有设置AFL_POST_LIBRARY环境变量,直接返回
   return;

  ACTF("Loading postprocessor from '%s'...", fn);//输出环境变量AFL_POST_LIBRARY

  dh = dlopen(fn, RTLD_NOW);//以RTLD_NOW模式打开AFL_POST_LIBRARY环境变量指向的动态链接库,在返回前解析出所有未定义的符号
  if (!dh) FATAL("%s", dlerror());

  post_handler = dlsym(dh, "afl_postprocess"); //post_handler赋值为动态链接库中afl_postprocess()函数地址
  if (!post_handler)//如果没有获取到afl_postprocess()函数地址,报错
   FATAL("Symbol 'afl_postprocess' not found.");

  /* Do a quick test. It's better to segfault now than later =) *//*做一个快速测试。现在做比以后做更好*/

  post_handler("hello", &tlen);

  OKF("Postprocessor installed successfully.");

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值