本文最后更新于:2023年10月6日 晚上
AFL源码分析(一) 笔者最近学了点fuzz,做了官方提供的示例后,对fuzz的理解还是一知半解的,所以特意阅读了AFL 源码,以加深对fuzz的理解。由于源码比较长,笔者分成了几篇文章。
文章参考了众多大佬的文章,还做了不少引用。所以,这篇文章仅作为笔者阅读源码的记录。
afl-gcc.c main 流程图如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 int main (int argc, char ** argv) { if (isatty(2 ) && !getenv("AFL_QUIET" )) { SAYF(cCYA "afl-cc " cBRI VERSION cRST " by <lcamtuf@google.com>\n" ); } else be_quiet = 1 ; if (argc < 2 ) { SAYF("\n" "This is a helper application for afl-fuzz. It serves as a drop-in replacement\n" "for gcc or clang, letting you recompile third-party code with the required\n" "runtime instrumentation. A common use pattern would be one of the following:\n\n" " CC=%s/afl-gcc ./configure\n" " CXX=%s/afl-g++ ./configure\n\n" "You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and AFL_AS.\n" "Setting AFL_HARDEN enables hardening optimizations in the compiled code.\n\n" , BIN_PATH, BIN_PATH); exit (1 ); } find_as(argv[0 ]); edit_params(argc, argv); execvp(cc_params[0 ], (char **)cc_params); FATAL("Oops, failed to execute '%s' - check your PATH" , cc_params[0 ]); return 0 ; }
为了方便查看cc_params的值,我们追加如下代码:
1 2 3 4 for (int i = 0 ; i < sizeof (cc_params); ++i) { printf ("\targ%d: %s\n" , i, cc_params[i]); }
当我们执行afl-gcc /home/p2lst/Documents/fuzz/test1/myafl.c -o /home/p2lst/Documents/fuzz/test1/myafl
时,输出如下:
1 2 3 4 5 6 7 8 arg0: gcc arg1: /home/ p2lst/Documents/ fuzz/test1/my afl.c arg2: -o arg3: /home/ p2lst/Documents/ fuzz/test1/my afl arg4: -B arg5: /home/ p2lst/tools/ afl-2.57 b arg6: -g arg7: -O3
可以看到,最终执行的是gcc。
由此可见,afl-gcc仅仅是对gcc进行再封装。
find_as 尝试在AFL_PATH或从argv[0]中找到汇编器as
。如果失败,中止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 static void find_as (u8* argv0) { u8 *afl_path = getenv("AFL_PATH" ); u8 *slash, *tmp; if (afl_path) { tmp = alloc_printf("%s/as" , afl_path); if (!access(tmp, X_OK)) { as_path = afl_path; ck_free(tmp); return ; } ck_free(tmp); } slash = strrchr (argv0, '/' ); if (slash) { u8 *dir; *slash = 0 ; dir = ck_strdup(argv0); *slash = '/' ; tmp = alloc_printf("%s/afl-as" , dir); if (!access(tmp, X_OK)) { as_path = dir; ck_free(tmp); return ; } ck_free(tmp); ck_free(dir); } if (!access(AFL_PATH "/as" , X_OK)) { as_path = AFL_PATH; return ; } FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH" ); }
edit_params 复制argv到 cc_params[] 数组,并做必要的处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 static void edit_params (u32 argc, char ** argv) { u8 fortify_set = 0 , asan_set = 0 ; u8 *name;#if defined(__FreeBSD__) && defined(__x86_64__) u8 m32_set = 0 ;#endif cc_params = ck_alloc((argc + 128 ) * sizeof (u8*)); name = strrchr (argv[0 ], '/' ); if (!name) name = argv[0 ]; else name++; if (!strncmp (name, "afl-clang" , 9 )) { clang_mode = 1 ; setenv(CLANG_ENV_VAR, "1" , 1 ); if (!strcmp (name, "afl-clang++" )) { u8* alt_cxx = getenv("AFL_CXX" ); cc_params[0 ] = alt_cxx ? alt_cxx : (u8*)"clang++" ; } else { u8* alt_cc = getenv("AFL_CC" ); cc_params[0 ] = alt_cc ? alt_cc : (u8*)"clang" ; } } else { #ifdef __APPLE__ if (!strcmp (name, "afl-g++" )) cc_params[0 ] = getenv("AFL_CXX" ); else if (!strcmp (name, "afl-gcj" )) cc_params[0 ] = getenv("AFL_GCJ" ); else cc_params[0 ] = getenv("AFL_CC" ); if (!cc_params[0 ]) { SAYF("\n" cLRD "[-] " cRST "On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n" " 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n" " set AFL_CC or AFL_CXX to specify the correct path to that compiler.\n" ); FATAL("AFL_CC or AFL_CXX required on MacOS X" ); }#else if (!strcmp (name, "afl-g++" )) { u8* alt_cxx = getenv("AFL_CXX" ); cc_params[0 ] = alt_cxx ? alt_cxx : (u8*)"g++" ; } else if (!strcmp (name, "afl-gcj" )) { u8* alt_cc = getenv("AFL_GCJ" ); cc_params[0 ] = alt_cc ? alt_cc : (u8*)"gcj" ; } else { u8* alt_cc = getenv("AFL_CC" ); cc_params[0 ] = alt_cc ? alt_cc : (u8*)"gcc" ; }#endif } while (--argc) { u8* cur = *(++argv); if (!strncmp (cur, "-B" , 2 )) { if (!be_quiet) WARNF("-B is already set, overriding" ); if (!cur[2 ] && argc > 1 ) { argc--; argv++; } continue ; } if (!strcmp (cur, "-integrated-as" )) continue ; if (!strcmp (cur, "-pipe" )) continue ; #if defined(__FreeBSD__) && defined(__x86_64__) if (!strcmp (cur, "-m32" )) m32_set = 1 ; #endif if (!strcmp (cur, "-fsanitize=address" ) || !strcmp (cur, "-fsanitize=memory" )) asan_set = 1 ; if (strstr (cur, "FORTIFY_SOURCE" )) fortify_set = 1 ; cc_params[cc_par_cnt++] = cur; } cc_params[cc_par_cnt++] = "-B" ; cc_params[cc_par_cnt++] = as_path; if (clang_mode) cc_params[cc_par_cnt++] = "-no-integrated-as" ; if (getenv("AFL_HARDEN" )) { cc_params[cc_par_cnt++] = "-fstack-protector-all" ; if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2" ; } if (asan_set) { setenv("AFL_USE_ASAN" , "1" , 1 ); } else if (getenv("AFL_USE_ASAN" )) { if (getenv("AFL_USE_MSAN" )) FATAL("ASAN and MSAN are mutually exclusive" ); if (getenv("AFL_HARDEN" )) FATAL("ASAN and AFL_HARDEN are mutually exclusive" ); cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE" ; cc_params[cc_par_cnt++] = "-fsanitize=address" ; } else if (getenv("AFL_USE_MSAN" )) { if (getenv("AFL_USE_ASAN" )) FATAL("ASAN and MSAN are mutually exclusive" ); if (getenv("AFL_HARDEN" )) FATAL("MSAN and AFL_HARDEN are mutually exclusive" ); cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE" ; cc_params[cc_par_cnt++] = "-fsanitize=memory" ; } if (!getenv("AFL_DONT_OPTIMIZE" )) { #if defined(__FreeBSD__) && defined(__x86_64__) if (!clang_mode || !m32_set) cc_params[cc_par_cnt++] = "-g" ; #else cc_params[cc_par_cnt++] = "-g" ;#endif cc_params[cc_par_cnt++] = "-O3" ; cc_params[cc_par_cnt++] = "-funroll-loops" ; cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1" ; cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1" ; } if (getenv("AFL_NO_BUILTIN" )) { cc_params[cc_par_cnt++] = "-fno-builtin-strcmp" ; cc_params[cc_par_cnt++] = "-fno-builtin-strncmp" ; cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp" ; cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp" ; cc_params[cc_par_cnt++] = "-fno-builtin-memcmp" ; cc_params[cc_par_cnt++] = "-fno-builtin-strstr" ; cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr" ; } cc_params[cc_par_cnt] = NULL ; }
参考链接
https://eternalsakura13.com/2020/08/23/afl/
https://hollk.blog.csdn.net/category_11470526.html
https://paper.seebug.org/1732/
https://www.z1r0.top/2023/03/23/AFL-fuzz%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/