1

我想详细了解 AFL 的代码检测。编译示例程序sample.c

int main(int argc, char **argv) {
  int ret = 0;
  if(argc > 1) {
    ret = 7;
  } else {
    ret = 12;
  }
  return ret;
}

withgcc -c -o obj/sample-gcc.o src/sample.c和withafl-gcc -c -o obj/sample-afl-gcc.o src/sample.c反汇编 withobjdump -d会导致不同的汇编代码:

[海合会]

0000000000000000 <main>:
   0:   f3 0f 1e fa             endbr64 
   4:   55                      push   %rbp
   5:   48 89 e5                mov    %rsp,%rbp
   8:   89 7d ec                mov    %edi,-0x14(%rbp)
   b:   48 89 75 e0             mov    %rsi,-0x20(%rbp)
   f:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
  16:   83 7d ec 01             cmpl   $0x1,-0x14(%rbp)
  1a:   7e 09                   jle    25 <main+0x25>
  1c:   c7 45 fc 07 00 00 00    movl   $0x7,-0x4(%rbp)
  23:   eb 07                   jmp    2c <main+0x2c>
  25:   c7 45 fc 0c 00 00 00    movl   $0xc,-0x4(%rbp)
  2c:   8b 45 fc                mov    -0x4(%rbp),%eax
  2f:   5d                      pop    %rbp
  30:   c3                      retq 

[AFL-GCC]

0000000000000000 <main>:
   0:   48 8d a4 24 68 ff ff    lea    -0x98(%rsp),%rsp
   7:   ff 
   8:   48 89 14 24             mov    %rdx,(%rsp)
   c:   48 89 4c 24 08          mov    %rcx,0x8(%rsp)
  11:   48 89 44 24 10          mov    %rax,0x10(%rsp)
  16:   48 c7 c1 0e ff 00 00    mov    $0xff0e,%rcx
  1d:   e8 00 00 00 00          callq  22 <main+0x22>
  22:   48 8b 44 24 10          mov    0x10(%rsp),%rax
  27:   48 8b 4c 24 08          mov    0x8(%rsp),%rcx
  2c:   48 8b 14 24             mov    (%rsp),%rdx
  30:   48 8d a4 24 98 00 00    lea    0x98(%rsp),%rsp
  37:   00 
  38:   f3 0f 1e fa             endbr64 
  3c:   31 c0                   xor    %eax,%eax
  3e:   83 ff 01                cmp    $0x1,%edi
  41:   0f 9e c0                setle  %al
  44:   8d 44 80 07             lea    0x7(%rax,%rax,4),%eax
  48:   c3                      retq 
  • AFL(通常)在每个基本块前面添加一个蹦床来跟踪执行的路径 [https://github.com/mirrorer/afl/blob/master/afl-as.h#L130] -> 指令 0x00lea直到 0x30lea
  • AFL(通常)向程序添加一个主要有效负载(由于简单性我将其排除)[https://github.com/mirrorer/afl/blob/master/afl-as.h#L381]
  • AFL 声称使用 GCC 的包装器,所以我希望其他一切都是平等的。为什么 if-else-condition 的编译方式仍然不同?
  • 额外的问题:如果没有可用源代码的二进制文件应该在不使用 AFL 的 QEMU 模式或 Unicorn 模式的情况下手动检测,这可以通过(天真地)将主要有效负载和每个蹦床手动添加到二进制文件中来实现,还是有更好的方法?
4

1 回答 1

3

回复:为什么使用 gcc 和使用 afl-gcc 进行编译不同,简要查看 afl-gcc 源代码表明,默认情况下它会修改编译器参数、设置-O3 -funroll-loops(以及定义__AFL_COMPILERFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)。

根据文档(docs/env_variables.txt):

默认情况下,包装器附加 -O3 以优化构建。在极少数情况下,这会导致使用 -Werror 构建的程序出现问题,这仅仅是因为 -O3 可以进行更彻底的代码分析并发出额外的警告。要禁用优化,请设置 AFL_DONT_OPTIMIZE。

于 2021-02-10T10:36:20.450 回答