AFL(American Fuzzy Lop)源码详细解读(4)

感谢大佬们的文章:
https://eternalsakura13.com/2020/08/23/afl/#more
https://bbs.pediy.com/thread-265936.htm
https://bbs.pediy.com/thread-269534.htm
http://rk700.github.io/2017/12/28/afl-internals/
接下来是关于AFL插桩部分的内容,这篇记录 afl-gcc.c 的代码解读,先记录一小部分吧,有些小细节理解可能还差点意思。

afl-gcc.c

1. find_as() 寻找as路径

说明:as是Linux下常用的汇编器。编译完成AFL后,在其目录下也会存在一个as文件,并作为符号链接指向afl-as

  • 获取环境变量“AFL_PATH” 赋值到 afl_path ,如果没有设置环境变量AFL_PATH的话,会为null。

    • 这里手动export设置一下环境变量AFL_PATH 为AFL存放位置,算是一个小尝试(当然必须在一个终端内设置并运行,我就犯了小迷糊,因为export设置的变量只在当前终端有效)

    • export AFL_PATH="/home/xu/fuzz/AFL"
      
    • 在gcc.c中加入一行代码,打印出来看看

    • u8 *afl_path = getenv("AFL_PATH");
      printf("afl_path: %s \n", afl_path);
      
    • 加入代码后需要重新 make && make install, 然后重新输入下列命令

    • afl-gcc test.c -o test
      
    • 可以看到会输出 afl_path=/home/xu/fuzz/AFL

  • 如果环境变量获取成功

    • 动态分配一段空间存储对应的路径
    • 如果有可执行权限
      • as_path 即设置为该路径
      • free并return
    • 如果没有可执行权限
      • 直接free
  • 如果环境变量获取失败或者没有可执行权限,slash 置为 argv0 中最后一个 ‘/’ 的位置

  • 如果argv0 中有 ‘/’

    • 取’/’ 前面的字符串为dir
    • 检查dir/afl-as这个文件是否具有可执行权限,如果有
      • 赋值,free,return
    • 如果没有,直接free
  • 如果以上两种情况都失败了,直接去默认文件夹(AFL_PATH = /usr/local/lib/afl)下找 as

    • 找到了且可访问,则赋值并return
    • 否则抛出异常
2. edit_params() 设置CC的参数
  • cc_params 分配大小为 (argc + 128) * 8 的空间

  • 检查 argv[0] 中是否存在 ‘/’ (如afl-gcc test.c -o test ,则argv[0] = afl-gcc)

    • 如果不存在则 name = argv[0]
    • 如果存在则一直找到最后一个/,并将其后面的字符串赋值给 name
  • 如果name 以 “afl-clang” 开头

    • clang_mode = 1;
    • 设置环境变量CLANG_ENV_VAR为1
    • 如果 name 为 “afl-clang++”
      • 则获取环境变量AFL_CXX的值赋值给alt_cxx
      • alt_cxx不为null,则cc_params[0] 即第一个参数置成alt_cxx,否则置成 ”clang++“
    • 如果 name 不为 “afl-clang++”,那 name就是 “afl-clang”
      • 则获取环境变量AFL_CC的值赋值给alt_cc
      • alt_cc不为null,则cc_params[0] 即第一个参数置成alt_cc,否则置成 ”clang“
  • 如果name 不是以 “afl-clang” 开头

    • 如果 name 为 “afl-g++”

      • 则获取环境变量AFL_CXX的值赋值给alt_cxx
      • alt_cxx不为null,则cc_params[0] 即第一个参数置成alt_cxx,否则置成 ”g++“
    • 如果 name 为 “afl-gcj” (gcj 是针对JAVA的)

      • 则获取环境变量AFL_GCJ的值赋值给alt_cc
      • alt_cc不为null,则cc_params[0] 即第一个参数置成alt_cc,否则置成 ”gcj“
    • 如果 name 为 “afl-gcc”

      • 则获取环境变量AFL_CC的值赋值给alt_cc
      • alt_cc不为null,则cc_params[0] 即第一个参数置成alt_cc,否则置成 ”gcc“
  • 进入 while 循环,遍历从argv[1]开始的argv参数

    • 如果传入的第二个参数为 -B
      • 如果 be_quiet 为0,则警告-B已经设置
      • 如果这个参数后面还有参数,直接去扫描下一个参数(好像不是这样)
    • 如果扫描到 -integrated-as,跳过
    • 如果扫描到 -pipe,跳过
    • 如果扫描到 -fsanitize=address 或 -fsanitize=memory ,设置 asan_set = 1
    • 如果扫描到 FORTIFY_SOURCE ,设置 fortify_set = 1 (FORTIFY_SOURCE 主要进行缓冲区溢出问题的检查,检查的常见函数有memcpy, mempcpy, memmove, memset 等)
    • 将参数保存到cc_params数组内
  • -B 保存到cc_params数组内

  • as_path 保存到cc_params数组内 (这两步指定汇编器)

  • 如果为 clang模式 ,则设置-no-integrated-as

  • 如果存在环境变量 AFL_HARDEN,

    • 则设置-fstack-protector-all
    • 如果没有设置 fortify_set ,追加 -D_FORTIFY_SOURCE=2
  • 如果 asan_set 在前面被设置为1,则设置环境变量 AFL_USE_ASAN 为1

  • 如果 asan_set 不为1且存在 AFL_USE_ASAN 环境变量

    • 如果存在 AFL_USE_ASAN 环境变量,又存在 AFL_USE_MSAN 环境变量,抛出异常不能同时存在
    • 如果存在 AFL_USE_ASAN 环境变量,又存在 AFL_HARDEN环境变量,抛出异常不能同时存在
    • -U_FORTIFY_SOURCE 保存到cc_params数组内
    • -fsanitize=address 保存到cc_params数组内
  • 如果存在 AFL_USE_MSAN 环境变量

    • 如果存在 AFL_USE_ASAN 环境变量, 抛出异常不能同时存在
    • 如果存在 AFL_HARDEN 环境变量, 抛出异常不能同时存在
    • -U_FORTIFY_SOURCE 保存到cc_params数组内
    • -fsanitize=memory 保存到cc_params数组内
  • 如果不存在 AFL_DONT_OPTIMIZE 环境变量

    • -g 保存到cc_params数组内
    • -O3 保存到cc_params数组内
    • -funroll-loops 保存到cc_params数组内
    • -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1 保存到cc_params数组内
    • D__AFL_COMPILER=1 保存到cc_params数组内
  • 如果存在 AFL_NO_BUILTIN 环境变量

  • 最后加入结束标志

3. main 函数
  • 如果没有环境变量 AFL_QUIET,打印信息

  • 否则 be_quiet = 1

  • 如果参数数量小于2,提示退出

  • 调用 find_as 查找汇编器

  • 调用edit_params处理传入的参数,将确定好的参数放入 cc_params[] 数组

  • 看一下处理后的参数数组

    // 输入
    afl-gcc test.c -o h.out
    // 结果(不知道后面为啥没有 -funroll-loops、-D__AFL_COMPILER=1、-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1)
    arg0: gcc
    arg1: test.c
    arg2: -o
    arg3: h.out
    arg4: -B
    arg5: /usr/local/lib/afl
    arg6: -g
    arg7: -O3
    
  • 调用execvp 执行命令,该函数如果执行成功则不返回

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值