AFL(american fuzzy lop)学习二

@sizaif

@2022-04-10

设计思想

覆盖率计算

改进边缘覆盖:

向目标程序注入以下工具来捕获分支(边缘)覆盖率和分支命中计数

  • 一条边表示为当前基本块(分配了一个随机常数)与前一个基本块(即元组 (prev_location, cur_location))之间的 XOR
  • 覆盖信息存储在一个紧凑共享的64KB的哈希表中,称为跟踪位图(bitmap)
  • 当访问一条边时,通过增加与该特定边的哈希相对应的位图中的值来记录命中
cur_location = <COMPILE_TIME_RANDOM>; # cur_location 值是随机生成的,以简化链接复杂项目的过程并保持 XOR 输出均匀分布。
shared_mem[cur_location ^ prev_location]++; # 由调用者传递给检测的二进制文件。
prev_location = cur_location >> 1; # 保持元组的方向性 以区分 A^B 和 B^A ,并保持紧密循环的标识,区分A^A,B^B

**简单块计算存在的问题:**对已执行的基本块进行技术会导致信息丢失

例如: 已执行 BB1->BB2->BB3->BB4, 新的路径: BB1->BB2->BB4, BB1->BB2->BB3 未被计入,路径丢失

相比简单的块覆盖计算:可以区分一下路径

  BB1 -> BB2 -> BB3 -> BBB4  (tuples: BB1BB2, BB2BB3, BB3BB4)BB1 -> BB2 ->BBB4  (tuples: BB1BB2, BB2BB4)BB1 -> BB2 ->BBB3  (tuples: BB1BB2, BB2BB3)

检测新行为

采用以下方法:

  1. fuzzer 维护先前执行中元组的全局映射;当一个变异的输入产生一个包含新元组的执行跟踪时,相应输入文件被保留等后续处理。
  2. 不触发执行跟踪中新的局部规模状态转换(即不产生新元组)的输入将被丢弃,即使它们的整体控制流序列是唯一的。

优势:

  1. 避免路径爆炸
  2. 达到较高的细粒度探索
  3. 不必对复杂的执行轨迹进行任何计算密集型和脆弱的全局比较

example: #2 存在(CA,AE)被认为是新路径,

  #1: A -> B -> C -> D -> E#2: A -> B -> C -> A -> E

处理路径#2 时,由于存在(CD,CA), 会出现以下的路径,但不会被视为新的路径

  #3: A -> B -> C -> A -> B -> C -> A -> B -> C -> D -> E

除了检测新元组外,模糊器还考虑粗略的元组命中计数, 分为以下桶:

1、2、3、4-7、8-15、16-31、32-127、128+

桶允许将仪器生成的 8 位计数器就地映射到 fuzzer 可执行文件依赖的 8 位位图,以跟踪已经看到的每个元组的执行计数

模糊策略

确定性策略包括:

  • 具有不同长度和步距的连续位翻转,(Sequential bit flips with varying lengths and stepovers)

  • 小整数的顺序加减法,(Sequential addition and subtraction of small integers)

  • 已知有趣整数的顺序插入(0、1、INT_MAX 等),(Sequential insertion of known interesting integers (0, 1, INT_MAX, etc))

非确定性步骤包括:

  • 堆叠位翻转 (stacked bit flips)
  • 插入 (insertions)
  • 删除 (deletions)
  • 算术 (arithmetics)
  • 不同测试用例的拼接 (splicing of different test cases)

afl-as.c

设计思想:

当使用 afl-gcc / afl-clang 编译程序时,工具链会自动寻找afl-as的位置,并调用此文件编译的程序afl-as

此汇编包装器的目的是

  1. 预处理由GCC/clang生成的汇编文件

    1. 处理输入的参数命令,为调用真正的as汇编器准备。
  2. 并在分支处插桩 afl-as.h 中包含的检测位。

    1. 处理输入文件,生成 modified_file。 根据afl-as.h在合适的的地方插桩。

      插桩执行代码:

      fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,R(MAP_SIZE));
      

      其本质上想捕获如下位置:

               ^main:      - function entry point (always instrumented)^.L0:       - GCC branch label^.LBB0_0:   - clang branch label (but only in clang mode)^\tjnz foo  - conditional branches
      
  3. 使用execvp调用as进行真正的汇编

    execvp(as_params[0], (char**)as_params)
    

afl-as.h 插桩部分

// 伪代码
cur_location = <COMPILE_TIME_RANDOM>; # cur_location 值是随机生成的,以简化链接复杂项目的过程并保持 XOR 输出均匀分布。
shared_mem[cur_location ^ prev_location]++; # 由调用者传递给检测的二进制文件。
prev_location = cur_location >> 1; # 保持元组的方向性 以区分 A^B 和 B^A ,并保持紧密循环的标识,区分A^A,B^B

说明:

存储 XOR异或数据对: 1) 当前执行分支的标识符; 2)之前执行的分支的标识符。即TL,DR 执行 shm_trace_map[cur_loc ^ prev_loc]++

插桩操作

fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,R(MAP_SIZE));

fprintf()将格式化字符串添加到汇编文件的相应位置,trampoline_fmt_64的具体内容如下:

/*** 这一段汇编代码,主要的操作是:* 保存rdx等寄存器* 将rcx的值设置为fprintf()所要打印的变量内容* 调用方法__afl_maybe_log()* 恢复寄存器*/
static const u8* trampoline_fmt_64 ="\n""/* --- AFL TRAMPOLINE (64-BIT) --- */\n""\n"".align 4\n""\n""leaq -(128+24)(%%rsp), %%rsp\n""movq %%rdx,  0(%%rsp)\n""movq %%rcx,  8(%%rsp)\n""movq %%rax, 16(%%rsp)\n""movq $0x%08x, %%rcx\n""call __afl_maybe_log\n""movq 16(%%rsp), %%rax\n""movq  8(%%rsp), %%rcx\n""movq  0(%%rsp), %%rdx\n""leaq (128+24)(%%rsp), %%rsp\n""\n""/* --- END --- */\n""\n";

__afl_maybe_log作为插桩代码所执行的实际内容,分析"movl $0x%08x, %%ecx\n"这条指令

R(MAP_SIZE)即为上述指令将rcx设置的值,即为。根据定义,宏MAP_SIZE为64K,;R(x)的定义是(random() % (x)),所以R(MAP_SIZE)即为0到MAP_SIZE之间的一个随机数。

因此,在处理到某个分支,需要插入桩代码时,afl-as会生成一个随机数,作为运行时保存在ecx中的值。而这个随机数,便是用于标识这个代码块的key。

检查 SHM 区域是否已映射

static const u8* main_payload_64 =
·····"  /* Check if SHM region is already mapped. */\n""\n""  movq  __afl_area_ptr(%rip), %rdx\n""  testq %rdx, %rdx\n""  je    __afl_setup\n""\n"
·····

分支记录

static const u8* main_payload_64 =
······
"__afl_store:\n""\n""  /* Calculate and store hit for the code location specified in rcx. */\n""\n"
#ifndef COVERAGE_ONLY"  xorq __afl_prev_loc(%rip), %rcx\n""  xorq %rcx, __afl_prev_loc(%rip)\n""  shrq $1, __afl_prev_loc(%rip)\n"
#endif /* ^!COVERAGE_ONLY */"\n"
#ifdef SKIP_COUNTS"  orb  $1, (%rdx, %rcx, 1)\n"
#else"  incb (%rdx, %rcx, 1)\n"
#endif /* ^SKIP_COUNTS */
·····

对应伪代码 shared_mem[cur_location ^ prev_location]++;

具体地,变量__afl_prev_loc保存的是前一次跳转的”位置”,其值与rcx做异或后,保存在rip中,并以rdx(共享内存)为基址,对rcx下标处进行加一操作。而rip的值右移1位后,保存在了变量__afl_prev_loc中。

则这里的rcx,保存的为伪代码中的cur_location。回忆之前介绍代码插桩的部分:

static const u8* trampoline_fmt_64 =
······"movq $0x%08x, %%rcx\n""call __afl_maybe_log\n"
······

在每个插桩处,afl-as会添加相应指令,将rcx的值设为0到MAP_SIZE之间的某个随机数,从而实现了伪代码中的cur_location = <COMPILE_TIME_RANDOM>;

因此,AFL为每个代码块生成一个随机数,作为其“位置”的记录;随后,对分支处的”源位置“和”目标位置“进行异或,并将异或的结果作为该分支的key,保存每个分支的执行次数。用于保存执行次数的实际上是一个哈希表,大小为MAP_SIZE=64K

afl-gcc.c

**设计思想: **

  1. 当前系统路径中找到afl-as汇编器所在位置,调用afls-as, afl-as以as的别名形式存在

    插桩检测位。编译器默认优先使用该路径中的汇编器和链接器,即 afl-as,实际的插桩工作发生在汇编的时候

  2. 读取输入的参数命令,根据输入的参数命令

    CC=%s/afl-gcc ./configure
    CXX=%s/afl-g++ ./configure
    

    1). 判断使用的afl编译器对应真实的编译器 gcc/g++clang/clang++

    将真实编译器填入cc_params[0]

    afl-gcc -> gcc
    afl-g++ -> g++
    afl-clang++ ->clang++
    afl-clang -> clang
    

    2). 读取其他相应的参数,并填充到cc_params数组中

  3. 调用系统命令execvp 执行真实的编译器

    execvp(cc_params[0], (char**)cc_params);
    

    execvp()的基本语法 (Basic Syntax of execvp())

    This function takes in the name of the UNIX command to run, as the first argument.

    该函数将要运行的UNIX命令的名称作为第一个参数。

    This is there in the <unistd.h> header file, so we must include it in our program.

    该文件位于<unistd.h>头文件中,因此我们必须将其包含在程序中。

    #include <unistd.h>
    int execvp(const char* command, char* argv[]);
    

    Here, we refer to a “command” as any binary executable file that is a part of the PATH environment variable. So, if you want to run custom programs, make sure that you add it to your PATH variable!

    在这里,我们将“命令”称为PATH环境变量一部分的任何二进制可执行文件。 因此,如果要运行自定义程序,请确保将其添加到PATH变量中!

    The second argument (argv) represents the list of arguments to command. This is an array of char* strings.

    第二个参数( argv )表示command的参数列表。 这是一个char*字符串数组。

    Here, argv contains the complete command, along with it’s arguments.

    在这里, argv包含完整的命令及其参数。

AFL(american fuzzy lop)学习二相关推荐

  1. AFL(american fuzzy lop)学习一

    AFL(american fuzzy lop)学习一 @sizaf AFL 的模糊方法 基于改进的边缘覆盖 插桩法引导的遗传算法 流程: 插桩 从源码编译程序时进行插桩,以记录代码覆盖率(Code C ...

  2. AFL(american fuzzy lop)学习三

    AFL(american fuzzy lop)学习三 @sizaif @2022-04-11 fork Server 为了提高性能,afl-fuzz 使用"fork server" ...

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

    AFL(American Fuzzy Lop)源码详细解读(3) 本篇是关于主循环阶段的内容,整个AFL最核心的部分,篇幅较长.最后简述一下afl_fuzz整体流程. 多亏大佬们的文章,对读源码帮助很 ...

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

    AFL(American Fuzzy Lop)源码详细解读(2) 本篇是关于 dry run (空跑.演练) 阶段的内容,一直到主循环之前. 多亏大佬们的文章,对读源码帮助很大: https://et ...

  5. AFL——American Fuzzy Lop的基础使用

    AFL--American Fuzzy Lop的基础使用 因为某些奇怪的原因,我一个没搞过pwn的得来搞代码fuzz,只好学一下,顺便记一下. AFL的安装 在部分源有的情况下可以直接使用apt-ge ...

  6. AFL(American Fuzzy Lop)源码详细解读(1)

    AFL(American Fuzzy Lop)源码详细解读(1) 多亏大佬们的文章,对读源码帮助很大: https://eternalsakura13.com/2020/08/23/afl/ http ...

  7. AFL(American Fuzzy Lop)-afl-fuzz.c

    转载AFL(American Fuzzy Lop)源码详细解读(1) AFL(American Fuzzy Lop)源码详细解读(1) 多亏大佬们的文章,对读源码帮助很大: https://etern ...

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

    这篇记录 llvm mode 中的 afl-llvm-pass.so.cc 文件和 afl-llvm-rt.o.c 文件,以及整体流程的简述. 对llvm这部分理解还比较浅. 可以阅读大佬的这篇文章: ...

  9. AFL (American fuzzy lop) 二进制程序模糊测试工具学习

    AFL 前言 AFL的安装 AFL运行界面介绍 AFL执行阶段介绍 fuzzing -- 有源码的程序 fuzzing -- 无源码的程序 总结 前言   在学习了一段时间的pwn后,我个人对漏洞挖掘 ...

最新文章

  1. Java中jsonObject与String等互转问题
  2. golang多语言支持
  3. Jupyter Notebook修改默认工作路径
  4. Tableau实战系列Tableau基础概念全解析 (二)-万字长文解析数据类型及数据集
  5. HTML中a标签/超链接标签的下划线怎么去掉
  6. Android秒级编译方案-FreeLine
  7. 第十一章 “她”值多少钱
  8. 是什么使波西米亚狂想曲成为杰作-数据科学视角
  9. 存储过程中while循环
  10. 亿级爆款背后,网易云音乐的生长之道
  11. 4.linux 命令行 光标移动技巧
  12. split函数python_python有split函数吗
  13. 【进阶修炼】——改善C#程序质量(4)
  14. 基于C语言图书馆管理系统编程设计
  15. python3 urlencode_Python3 parse.urlencode() 与parse.unquote()
  16. 「ZJOI2009」多米诺骨牌
  17. 女神找我帮忙--图片转成手绘,该不该答应?
  18. sdust cpp专业课复习
  19. 光学遥感影像的几何校正
  20. 视频制作软件哪个好,视频剪辑软件哪个好,电视剧怎么剪辑成短视频发布?

热门文章

  1. 视频 | 做客上海外语频道《财智对话》 老冒畅聊区块链新风口
  2. 推荐一款firefox的flv下载插件
  3. 数据分析技术教学大纲
  4. Jetson nano 入手系列之2—板载摄像头IMX219启动
  5. 【转载】PTN与IPRAN承载LTE的比较
  6. 外网如何连接校园网GPU服务器以及文件传输
  7. autojs简洁的登录界面
  8. C语言—中国古代著名算题。趣味题目:物不知其数。
  9. CE认证机构聚焦于CE整合
  10. 两分钟了解HTTP请求报文和响应报文