AFL源码分析之afl-gcc.c
非常感谢网上师傅队afl源码的分析理解,能使我更容易去理解这部分代码
(22条消息) afl-gcc.c源码分析 源码精注释版_学习记录-CSDN博客
(22条消息) AFL源码分析之afl-gcc.c详细注释_hollk’s blog-CSDN博客
我阅读的是2.57版本的afl,要文件可以私我,
在次记录便于以后我的复习
1 /* 2 Copyright 2013 Google LLC All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at: 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 /* 18 american fuzzy lop - wrapper for GCC and clang 19 ---------------------------------------------- 20 21 Written and maintained by Michal Zalewski <lcamtuf@google.com> 22 23 This program is a drop-in replacement for GCC or clang. The most common way 24 of using it is to pass the path to afl-gcc or afl-clang via CC when invoking 25 ./configure. 26 27 (Of course, use CXX and point it to afl-g++ / afl-clang++ for C++ code.) 28 29 The wrapper needs to know the path to afl-as (renamed to 'as'). The default 30 is /usr/local/lib/afl/. A convenient way to specify alternative directories 31 would be to set AFL_PATH. 32 33 If AFL_HARDEN is set, the wrapper will compile the target app with various 34 hardening options that may help detect memory management issues more 35 reliably. You can also specify AFL_USE_ASAN to enable ASAN. 36 37 If you want to call a non-default compiler as a next step of the chain, 38 specify its location via AFL_CC or AFL_CXX. 39 40 */ 41 42 #define AFL_MAIN 43 44 #include "config.h" 45 #include "types.h" 46 #include "debug.h" 47 #include "alloc-inl.h" 48 49 #include <stdio.h> 50 #include <unistd.h> 51 #include <stdlib.h> 52 #include <string.h> 53 54 static u8* as_path; /* Path to the AFL 'as' wrapper as包装器的路径 */ 55 static u8** cc_params; /* Parameters passed to the real CC 传递给cc的参数 */ 56 static u32 cc_par_cnt = 1; /* Param count, including argv0 */ 57 static u8 be_quiet, /* Quiet mode 静默模式 */ 58 clang_mode; /* Invoked as afl-clang*? 调用afl-clang模式? */ 59 60 61 /* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived 62 from argv[0]. If that fails, abort. 试着在AFL_PATH或派生的位置找到我们的fake”GNU汇编器从argv[0]。如果失败,中止*/ 63 64 static void find_as(u8* argv0) { 65 //通过argv[0](当前文件的路径)来寻找对应的汇编器as(linux上as是常用的一个汇编器,负责把生成的汇编代码翻译到二进制) 66 u8 *afl_path = getenv("AFL_PATH"); //读取环境变量中的afl_path变量 67 u8 *slash, *tmp; 68 69 if (afl_path) { //如果成功获取到了afl_path变量 70 71 tmp = alloc_printf("%s/as", afl_path); //alloc_printf函数动态为afl_path分配一段空间 72 73 if (!access(tmp, X_OK)) { //监测路径是否可以访问 74 // access函数用来判断指定的文件或目录是否存在(F_OK),已存在的文件或目录是否有可读(R_OK)、可写(W_OK)、可执行(X_OK)权限。F_OK、R_OK、W_OK、X_OK这四种方式通过access函数中的第二个参数mode指定。如果指定的方式有效,则此函数返回0,否则返回-1。 75 76 as_path = afl_path; //如果可以访问则将as_path = afl_path 77 ck_free(tmp); //然后free掉tmp也就是alloc_printf申请的那段空间 78 return; //返回 79 } 80 81 ck_free(tmp); //如果无法访问路径,则也free掉tmp的空间大小 82 83 } 84 85 slash = strrchr(argv0, '/'); //如果获取afl_path变量失败 ,从argv0中查找/字符串 也就是提取当前的路径dir 86 87 if (slash) { //如果成功获取到了dir路径 88 89 u8 *dir; 90 91 *slash = 0; 92 dir = ck_strdup(argv0); //将argv0路径命名 93 *slash = '/'; 94 95 tmp = alloc_printf("%s/afl-as", dir); //为dir申请一段空间 96 97 if (!access(tmp, X_OK)) { //如果路径是可以访问到的 98 as_path = dir; //将路径赋值给as_path 99 ck_free(tmp); //然后将tmp空间释放掉 100 return; 101 } 102 103 ck_free(tmp); //如果访问不到路径则释放掉tmp的空间 104 ck_free(dir); 105 106 } 107 108 if (!access(AFL_PATH "/as", X_OK)) { //如果上面俩种情况都没有则寻找as抛出异常 109 as_path = AFL_PATH; //如果找到了就赋值 110 return; 111 } 112 113 FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH"); 114 115 } 116 117 118 /* Copy argv to cc_params, making the necessary edits.复制argv到cc_params,进行必要的编辑。 */ 119 120 static void edit_params(u32 argc, char** argv) { 121 122 u8 fortify_set = 0, asan_set = 0; //设置cc的参数 123 u8 *name; 124 125 #if defined(__FreeBSD__) && defined(__x86_64__) 126 u8 m32_set = 0; 127 #endif 128 129 cc_params = ck_alloc((argc + 128) * sizeof(u8*)); //为cc_params开辟内存空间 130 131 name = strrchr(argv[0], '/'); //获取/后的编译器名称 132 if (!name) name = argv[0]; else name++; 133 134 if (!strncmp(name, "afl-clang", 9)) { //如果name是以afl-clang开头的 135 136 clang_mode = 1; //则设置clang_mode的模式为1 137 138 setenv(CLANG_ENV_VAR, "1", 1); 139 140 if (!strcmp(name, "afl-clang++")) { //如果name中的变量是afl-clang++ 141 u8* alt_cxx = getenv("AFL_CXX"); //则获取环境变量 afl_cxx 142 cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; //如果获得获取到环境变量值,那么将环境变量值付给cc_params,如果没有获取到则直接给字符串“clang++” 143 } 144 else { 145 } else { 146 u8* alt_cc = getenv("AFL_CC"); //如果name中的变量不是afl-clang++则获取环境变量AFL_cc 147 cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";//如果获取到环境变量值,那么将环境变量值赋给cc_params,如果没有则直接给字符串“clang” 148 } 149 150 } else { 151 152 /* With GCJ and Eclipse installed, you can actually compile Java! The 153 instrumentation will work (amazingly). Alas, unhandled exceptions do 154 not call abort(), so afl-fuzz would need to be modified to equate 155 non-zero exit codes with crash conditions when working with Java 156 binaries. Meh. */ 157 158 #ifdef __APPLE__ //如果没有afl_clang分支而且还是apple的平台,就会进入这个分支 159 160 if (!strcmp(name, "afl-g++")) cc_params[0] = getenv("AFL_CXX"); //如果对比的值是afl-g++ 则获取环境变量afl_cxx的值并且赋值给cc_params 161 else if (!strcmp(name, "afl-gcj")) cc_params[0] = getenv("AFL_GCJ"); //如果对比的值是afl-gcj,测获取环境变量afl_gcj的值并且赋值给afl_gcj 162 else cc_params[0] = getenv("AFL_CC"); //如果都不是则获取环境变量AFL_cc的值赋值给cc_parms 163 164 if (!cc_params[0]) { //如果cc_params没有值,则提示mac下有限使用afl-alang,如果要使用afl-gcc需要配置路径 165 166 SAYF("\n" cLRD "[-] " cRST 167 "On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n" 168 " 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n" 169 " set AFL_CC or AFL_CXX to specify the correct path to that compiler.\n"); 170 171 FATAL("AFL_CC or AFL_CXX required on MacOS X"); 172 173 } 174 175 #else 176 177 if (!strcmp(name, "afl-g++")) { //判断name的值是不是afl-g++ 178 u8* alt_cxx = getenv("AFL_CXX"); //获取环境变量AFL_CXX的值赋值给alt_cxx 179 cc_params[0] = alt_cxx ? alt_cxx : (u8*)"g++"; //如果获取到了值则将值赋值给cc_params,如果没有获取到则直接将字符串g++给cc_params 180 } else if (!strcmp(name, "afl-gcj")) { //判断name的值是不是afl-gcj 181 u8* alt_cc = getenv("AFL_GCJ"); //获取环境变量afl_gcj的值赋值给alt_cc 182 cc_params[0] = alt_cc ? alt_cc : (u8*)"gcj"; //如果获取到了值则将值赋值给cc_params,如果没有获取到则将字符串gcj赋值给cc_params 183 } else { 184 u8* alt_cc = getenv("AFL_CC"); //如果都不是则获取环境变量afl_cc的值赋值给alt_cc 185 cc_params[0] = alt_cc ? alt_cc : (u8*)"gcc";//将alt_cc的值赋值给cc_params,如果没有获取到则将字符串gcc赋值给cc_params 186 } 187 188 #endif /* __APPLE__ */ 189 190 } 191 192 while (--argc) { //进入while循环扫描argv数组 给cc_params赋值(可见217行 193 u8* cur = *(++argv);//获取参数 194 195 if (!strncmp(cur, "-B", 2)) { //如果当前的参数是-B 196 197 if (!be_quiet) WARNF("-B is already set, overriding"); //判断静默模式是否关闭,如果关闭则提示"-B"以设置 198 199 if (!cur[2] && argc > 1) { argc--; argv++; }// 200 continue; 201 202 } 203 204 if (!strcmp(cur, "-integrated-as")) continue; //如果扫描到-integrated-as 则跳过 205 206 if (!strcmp(cur, "-pipe")) continue; //如果扫描到-pipe 则跳过 207 208 #if defined(__FreeBSD__) && defined(__x86_64__) //判断如果是freebsd系统或者是x86_64的系统 209 if (!strcmp(cur, "-m32")) m32_set = 1; //判断当前的参数是不是-m32,并且将m32_set的值赋值为1 210 #endif 211 212 if (!strcmp(cur, "-fsanitize=address") || //如果当前的参数为-fsanitize=address或者-fsanitize=memory,则将asan_set的值赋值为1 (这俩个参数是为了告诉gcc检查内存访问错误 213 !strcmp(cur, "-fsanitize=memory")) asan_set = 1; 214 215 if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; //如果当前的参数为"FORTIFY_SOURCE",则将fortify_set 赋值为1(这个参数是为了检查fortify保护是否开启) 216 217 cc_params[cc_par_cnt++] = cur; //给cc_params赋值,cc_par_cnt++初值值为1 218 219 } 220 221 cc_params[cc_par_cnt++] = "-B"; 222 cc_params[cc_par_cnt++] = as_path; //跳出循环后,向cc_params中加入"-B" 以及前面find_as函数赋值的as_path 组成"-B as_path" 223 224 if (clang_mode) //判断clang_mode的值,在136行有分支将值设置为1 225 cc_params[cc_par_cnt++] = "-no-integrated-as"; //如果是的话则将cc_params的值追加参数为 "-no-integrated-as" 226 227 if (getenv("AFL_HARDEN")) { //获取环境变量afl_harden的值,如果获取到进入该分支 228 229 cc_params[cc_par_cnt++] = "-fstack-protector-all"; //cc_params追加参数"-fstack-protector-all" 230 231 if (!fortify_set) //检查是否设置fortify_set参数是否设置 (215行)如果没有则cc_params追加参数"-D_FORTIFY_SOURCE=2" 232 cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; 233 234 } 235 236 if (asan_set) { //判断是否检查内存 位置在215 237 238 /* Pass this on to afl-as to adjust map density.将此传递给afl-as以调整地图密度 */ 239 240 setenv("AFL_USE_ASAN", "1", 1); //如果检查内存了则将AFL_USE_ASAN环境变量设置为1 241 242 } else if (getenv("AFL_USE_ASAN")) { //如果设置成功则进入该分支 243 244 if (getenv("AFL_USE_MSAN")) //获取AFL_USE_MSAN是否设置成功,如果成功则提示asan和msan是互斥的 245 FATAL("ASAN and MSAN are mutually exclusive"); 246 247 if (getenv("AFL_HARDEN"))//获取"AFL_HARDEN"是否设置为1,存在则提示ASAN和AFL_HARDEN是互斥的 248 FATAL("ASAN and AFL_HARDEN are mutually exclusive"); 249 250 cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; 251 cc_params[cc_par_cnt++] = "-fsanitize=address";//如果上述两个环境变量都没有设置,则再cc_params中追加"-U_FORTIFY_SOURCE"和"-fsanitize=address"两个参数 252 253 } else if (getenv("AFL_USE_MSAN")) { //获取AFL_USE_MSAN环境变量进入该分支 254 255 if (getenv("AFL_USE_ASAN")) //获取AFL_USE_ASAN是否设置为1,如果设置则提示ASAN和MSAN是互斥的 256 FATAL("ASAN and MSAN are mutually exclusive"); 257 258 if (getenv("AFL_HARDEN")) //获取AFL_HARDEN"是否设置为1,如果设置则提示MSAN和AFL_HARDEN"是互斥的 259 FATAL("MSAN and AFL_HARDEN are mutually exclusive"); 260 261 cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; 262 cc_params[cc_par_cnt++] = "-fsanitize=memory";//如果上述两个环境变量都没有设置,则再cc_params中追加"-U_FORTIFY_SOURCE"和"-fsanitize=memory"两个参数 263 264 265 } 266 267 if (!getenv("AFL_DONT_OPTIMIZE")) { //获取AFL_DONT_OPTIMIZE环境变量,失败进入分支 268 269 #if defined(__FreeBSD__) && defined(__x86_64__) //如果是freebsd或者x86_64的系统进入分支 270 271 /* On 64-bit FreeBSD systems, clang -g -m32 is broken, but -m32 itself 272 works OK. This has nothing to do with us, but let's avoid triggering 273 that bug. */ 274 275 if (!clang_mode || !m32_set)//如果没有设置clang模式或者没有设置-m32参数则进入分支 (在136行) 276 cc_params[cc_par_cnt++] = "-g";//cc_params中追加“-g”参数 277 278 #else //如果不是上述俩系统进入该分支 279 280 cc_params[cc_par_cnt++] = "-g";//cc_params中追加“-g”参数 281 282 #endif 283 284 cc_params[cc_par_cnt++] = "-O3";//在cc_params中追加“-O3”参数 285 cc_params[cc_par_cnt++] = "-funroll-loops"; 286 287 /* Two indicators that you're building for fuzzing; one of them is 288 AFL-specific, the other is shared with libfuzzer.你要为模糊设计的两个指标;其中一个是afl特异性,另一个与libfuzzer共享。 */ 289 290 cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; 291 cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";//cc_params中追加上述几个参数 292 293 } 294 295 if (getenv("AFL_NO_BUILTIN")) { //如果设置了"AFL_NO_BUILTIN"环境变量则进入该分支 296 297 cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; 298 cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; 299 cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; 300 cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; 301 cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; 302 cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; 303 cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";//在cc_params中追加上述参数 304 305 } 306 307 cc_params[cc_par_cnt] = NULL;//cc_params最后追加NULL,表示参数数组结束 308 309 } 310 311 312 /* Main entry point程序的主入口 */ 313 314 int main(int argc, char** argv) { 315 316 if (isatty(2) && !getenv("AFL_QUIET")) { 317 318 SAYF(cCYA "afl-cc " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); 319 320 } else be_quiet = 1; 321 322 if (argc < 2) { 323 324 SAYF("\n" 325 "This is a helper application for afl-fuzz. It serves as a drop-in replacement\n" 326 "for gcc or clang, letting you recompile third-party code with the required\n" 327 "runtime instrumentation. A common use pattern would be one of the following:\n\n" 328 329 " CC=%s/afl-gcc ./configure\n" 330 " CXX=%s/afl-g++ ./configure\n\n" 331 332 "You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and AFL_AS.\n" 333 "Setting AFL_HARDEN enables hardening optimizations in the compiled code.\n\n", 334 BIN_PATH, BIN_PATH); 335 336 exit(1); 337 338 } 339 340 find_as(argv[0]);//主要来查找汇编器 341 342 edit_params(argc, argv); //通过传入编译的参数来进行参数处理,将确定好的参数放入cc_params[]数组 343 344 execvp(cc_params[0], (char**)cc_params);//调用该函数执行afl-gcc(cc_params[0]为编译器,(char**)cc_params为编译器参数) 345 346 347 FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); 348 349 return 0; 350 351 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)