1. 程式人生 > 其它 >AFL原始碼分析之afl-as.c

AFL原始碼分析之afl-as.c

昨天閱讀了afl-gcc的原始碼,可以看出來afl-gcc主要用途是搜尋as所在的位置,然後加上必要的引數引數,在呼叫gcc進行實際的編譯

今天又繼續閱讀了afl-as.c的原始碼,這部分主要是對於fuzz插樁的編寫,閱讀完後不清楚可以看一下sakura師傅的部落格,有著對原始碼的理解,也非常感謝hollk師傅的原始碼註解,降低了閱讀的難度

(22條訊息) AFL原始碼分析之afl-as.c詳細註釋_hollk’s blog-CSDN部落格_afl原始碼

sakuraのAFL原始碼全註釋 | Sakuraのblog (eternalsakura13.com)

  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 GNU as
19 --------------------------------------- 20 21 Written and maintained by Michal Zalewski <[email protected]> 22 23 The sole purpose of this wrapper is to preprocess assembly files generated 24 by GCC / clang and inject the instrumentation bits included from afl-as.h. It 25 is automatically invoked by the toolchain when compiling programs using 26 afl-gcc / afl-clang. 27 28 Note that it's an explicit non-goal to instrument hand-written assembly, 29 be it in separate .s files or in __asm__ blocks. The only aspiration this 30 utility has right now is to be able to skip them gracefully and allow the 31 compilation process to continue. 32 33 That said, see experimental/clang_asm_normalize/ for a solution that may 34 allow clang users to make things work even with hand-crafted assembly. Just 35 note that there is no equivalent for GCC. 36 37 */ 38 39 #define AFL_MAIN 40 41 #include "config.h" 42 #include "types.h" 43 #include "debug.h" 44 #include "alloc-inl.h" 45 46 #include "afl-as.h" 47 48 #include <stdio.h> 49 #include <unistd.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <time.h> 53 #include <ctype.h> 54 #include <fcntl.h> 55 56 #include <sys/wait.h> 57 #include <sys/time.h> 58 59 static u8** as_params; /* Parameters passed to the real 'as' 傳遞給“as”的引數 */ 60 61 static u8* input_file; /* Originally specified input file 輸入檔案 */ 62 static u8* modified_file; /* Instrumented file for the real 'as' “as”進行插樁處理的檔案 */ 63 64 static u8 be_quiet, /* Quiet mode (no stderr output) 靜默模式(沒有標準輸出) */ 65 clang_mode, /* Running in clang mode? 是否執行在clang模式 */ 66 pass_thru, /* Just pass data through? 只通過資料 */ 67 just_version, /* Just show version? 只顯示版本 */ 68 sanitizer; /* Using ASAN / MSAN 是否使用ASAN/MSAN */ 69 70 static u32 inst_ratio = 100, /* Instrumentation probability (%) 插樁覆蓋率 */ 71 as_par_cnt = 1; /* Number of params to 'as' 傳遞給“as”的引數數量初始值 */ 72 73 /* If we don't find --32 or --64 in the command line, default to 74 instrumentation for whichever mode we were compiled with. This is not 75 perfect, but should do the trick for almost all use cases.如果輸入命令中沒有“--32”或“--64”,則預設檢測編譯時使用的模式 */ 76 77 #ifdef WORD_SIZE_64 78 79 static u8 use_64bit = 1; //64位的標誌 80 81 #else 82 83 static u8 use_64bit = 0; //32位的標誌 84 85 #ifdef __APPLE__ //如果是蘋國平臺 86 # error "Sorry, 32-bit Apple platforms are not supported." //提示蘋果不支援32位 87 #endif /* __APPLE__ */ 88 89 #endif /* ^WORD_SIZE_64 */ 90 91 92 /* Examine and modify parameters to pass to 'as'. Note that the file name 93 is always the last parameter passed by GCC, so we exploit this property 94 to keep the code simple. 檢查並修改要傳遞給'as'的引數。注意,檔名總是GCC傳遞的最後一個引數,因此我們利用這個屬性來保持程式碼簡單*/ 95 96 static void edit_params(int argc, char** argv) { 97 98 u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS"); //獲取環境變數TMPDIR和AFL_AS 99 u32 i; 100 101 #ifdef __APPLE__ // 如果 102 103 u8 use_clang_as = 0; 104 105 /* On MacOS X, the Xcode cctool 'as' driver is a bit stale and does not work 106 with the code generated by newer versions of clang that are hand-built 107 by the user. See the thread here: http://goo.gl/HBWDtn. 108 109 To work around this, when using clang and running without AFL_AS 110 specified, we will actually call 'clang -c' instead of 'as -q' to 111 compile the assembly file. 112 113 The tools aren't cmdline-compatible, but at least for now, we can 114 seemingly get away with this by making only very minor tweaks. Thanks 115 to Nico Weber for the idea. */ 116 117 if (clang_mode && !afl_as) { //如果使用clang模式且沒有獲取到afl_as變數就進入該分支 118 119 use_clang_as = 1; 120 121 afl_as = getenv("AFL_CC"); //獲取環境變數AFL_CC 122 if (!afl_as) afl_as = getenv("AFL_CXX"); //如果沒有獲取到上面的變數就獲取AFL_CXX或者賦值clang字串 123 if (!afl_as) afl_as = "clang"; 124 125 } 126 127 #endif /* __APPLE__ */ 128 129 /* Although this is not documented, GCC also uses TEMP and TMP when TMPDIR 130 is not set. We need to check these non-standard variables to properly 131 handle the pass_thru logic later on. */ 132 133 if (!tmp_dir) tmp_dir = getenv("TEMP"); //如果沒有獲取到TMPDIR就賦值下面三個中的一種 134 if (!tmp_dir) tmp_dir = getenv("TMP"); 135 if (!tmp_dir) tmp_dir = "/tmp"; 136 137 as_params = ck_alloc((argc + 32) * sizeof(u8*)); 為as_oarams開闢一段空間 138 139 as_params[0] = afl_as ? afl_as : (u8*)"as"; //將上面的afl_as賦值給as_params,如果沒有獲取到就將字串as賦值給as_params 140 141 as_params[argc] = 0; //設定最後一個引數為0 142 143 for (i = 1; i < argc - 1; i++) { //從第一個引數便利到最後一個引數 144 145 if (!strcmp(argv[i], "--64")) use_64bit = 1; //如果遍歷到--64字串就將use_64bit設定為1 146 else if (!strcmp(argv[i], "--32")) use_64bit = 0; //如果便利到--32字串就將use_64bit設定為零 147 148 #ifdef __APPLE__ //如果是蘋果平臺 149 150 /* The Apple case is a bit different... */ 151 152 if (!strcmp(argv[i], "-arch") && i + 1 < argc) { //如果遍歷到了-arch引數 153 154 if (!strcmp(argv[i + 1], "x86_64")) use_64bit = 1; //如果是arch x86_64 則設定use_64bint為1 155 else if (!strcmp(argv[i + 1], "i386")) //如果是-arch i386 則報錯 156 FATAL("Sorry, 32-bit Apple platforms are not supported."); 157 158 } 159 160 /* Strip options that set the preference for a particular upstream 161 assembler in Xcode. */ 162 163 if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q"))) //如果是clang模式並且引數是-q或者-Q則跳出迴圈 164 continue; 165 166 #endif /* __APPLE__ */ 167 168 as_params[as_par_cnt++] = argv[i]; 169 170 } 171 172 #ifdef __APPLE__ 173 174 /* When calling clang as the upstream assembler, append -c -x assembler 175 and hope for the best. */ 176 177 if (use_clang_as) { 178 179 as_params[as_par_cnt++] = "-c"; 180 as_params[as_par_cnt++] = "-x"; 181 as_params[as_par_cnt++] = "assembler"; //如果使用的是clang模式則在as_params追加上述三個引數 182 183 } 184 185 #endif /* __APPLE__ */ 186 187 input_file = argv[argc - 1]; //將argv最後一個引數賦值給input_file 188 189 if (input_file[0] == '-') { //如果input_file 的引數是- 190 191 if (!strcmp(input_file + 1, "-version")) { //如果是-version 192 just_version = 1; 193 modified_file = input_file; //則將just_version設定為1然後modified_file設定為-version 194 goto wrap_things_up; //跳轉到引數組合尾部尾部 195 } 196 197 if (input_file[1]) FATAL("Incorrect use (not called through afl-gcc?)"); //如果不是-version則丟擲異常 198 else input_file = NULL; 199 200 } else { 201 202 /* Check if this looks like a standard invocation as a part of an attempt 203 to compile a program, rather than using gcc on an ad-hoc .s file in 204 a format we may not understand. This works around an issue compiling 205 NSS. */ 206 207 if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) && //如果首字母不是- 判斷第9個和第五個位元組分把是不是/var/tmp和/tmp 如果都不是則設定pass_thru為1 208 strncmp(input_file, "/var/tmp/", 9) && 209 strncmp(input_file, "/tmp/", 5)) pass_thru = 1; 210 211 } 212 213 modified_file = alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(), //設定modified_file為類似tmp_dir/.afl-pid-time.s這樣的字串 214 (u32)time(NULL)); 215 216 wrap_things_up: 217 218 as_params[as_par_cnt++] = modified_file;//接收引數為modified最後一個引數 219 as_params[as_par_cnt] = NULL;//引數接收結束 220 221 } 222 223 224 /* Process input file, generate modified_file. Insert instrumentation in all 225 the appropriate places. */ 226 227 static void add_instrumentation(void) {//處理輸入檔案,生成modified_file,將樁插入所有釋放的位置 228 229 static u8 line[MAX_LINE]; 230 231 FILE* inf; 232 FILE* outf; 233 s32 outfd; 234 u32 ins_lines = 0; //插樁計數器 235 236 u8 instr_ok = 0, skip_csect = 0, skip_next_label = 0, 237 skip_intel = 0, skip_app = 0, instrument_next = 0; 238 239 #ifdef __APPLE__ 240 241 u8* colon_pos; 242 243 #endif /* __APPLE__ */ 244 245 if (input_file) { //如果存在輸入檔名稱 246 247 inf = fopen(input_file, "r"); //嘗試獲取input_file控制代碼,將fd賦值給inf 248 if (!inf) PFATAL("Unable to read '%s'", input_file); //如果獲取不到則,丟擲異常 249 250 } else inf = stdin; //如果不存在檔名則賦值標準輸入 251 252 outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600); //以寫的方式開啟modified_file,如果檔案已存在就直接開啟,如果沒有就建立一個 253 254 if (outfd < 0) PFATAL("Unable to write to '%s'", modified_file); //如果檔案沒有寫許可權,就丟擲異常 255 256 outf = fdopen(outfd, "w"); //嘗試開啟 257 258 if (!outf) PFATAL("fdopen() failed"); //打不開就丟擲異常 259 260 while (fgets(line, MAX_LINE, inf)) { //迴圈讀取inf指向的檔案的每一行到line陣列,每行最多MAX_LINE(8192)個位元組,含末尾“\0” 261 262 /* In some cases, we want to defer writing the instrumentation trampoline 263 until after all the labels, macros, comments, etc. If we're in this 264 mode, and if the line starts with a tab followed by a character, dump 265 the trampoline now. */ 266 267 if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok && 268 instrument_next && line[0] == '\t' && isalpha(line[1])) { //446行判斷是否為defered mode模式(判斷instrument_next和instr_ok是否都為1,以及line是否以\t開始,且line[1]是否是字母) 269 270 fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32, 271 R(MAP_SIZE)); //插樁 272 273 instrument_next = 0; //instrument_next設定為0 274 ins_lines++; //插樁計數器加1 275 276 } 277 278 /* Output the actual line, call it a day in pass-thru mode. */ 279 280 fputs(line, outf); 281 282 if (pass_thru) continue; 283 284 /* All right, this is where the actual fun begins. For one, we only want to 285 instrument the .text section. So, let's keep track of that in processed 286 files - and let's set instr_ok accordingly.首先,我們只想檢測.text部分。讓我們在已處理的檔案中跟蹤它,並相應地設定instr_ok */ 287 288 if (line[0] == '\t' && line[1] == '.') { //判斷讀入的行是否以\t開頭,以及line[1]是否為. 289 290 /* OpenBSD puts jump tables directly inline with the code, which is 291 a bit annoying. They use a specific format of p2align directives 292 around them, so we use that as a signal. OpenBSD將跳轉表直接內聯到程式碼中,這有點煩人。它們使用特定格式的p2align指令,所以我們將其用作訊號 */ 293 294 if (!clang_mode && instr_ok && !strncmp(line + 2, "p2align ", 8) && //檢查是否為p2align指令,如果是則設定skip_next_label為1 295 isdigit(line[10]) && line[11] == '\n') skip_next_label = 1;//instr_ok變數是一個flag,如果為1表示位於.text段,如果為0表示不再.text段 296 297 if (!strncmp(line + 2, "text\n", 5) || 298 !strncmp(line + 2, "section\t.text", 13) || 299 !strncmp(line + 2, "section\t__TEXT,__text", 21) || 300 !strncmp(line + 2, "section __TEXT,__text", 21)) { 301 instr_ok = 1; //匹配"text\n"、"section\t.text"、"section\t__TEXT,__text"、"section __TEXT,__text",如果匹配成功則設定instr_ok為1。跳出本次迴圈 302 continue; 303 } 304 305 if (!strncmp(line + 2, "section\t", 8) || 306 !strncmp(line + 2, "section ", 8) || 307 !strncmp(line + 2, "bss\n", 4) || 308 !strncmp(line + 2, "data\n", 5)) { 309 instr_ok = 0;//匹配"section\t"、"section "、"bss\n"、"data\n",如果匹配成功說明不是在.text段,設定instr_ok變數為0 310 continue; 311 } 312 313 } 314 315 /* Detect off-flavor assembly (rare, happens in gdb). When this is 316 encountered, we set skip_csect until the opposite directive is 317 seen, and we do not instrument. */ 318 319 if (strstr(line, ".code")) { //判斷架構 320 321 if (strstr(line, ".code32")) skip_csect = use_64bit; 322 if (strstr(line, ".code64")) skip_csect = !use_64bit; 323 324 } 325 326 /* Detect syntax changes, as could happen with hand-written assembly. 327 Skip Intel blocks, resume instrumentation when back to AT&T. */ 328 329 if (strstr(line, ".intel_syntax")) skip_intel = 1;//判斷是否為Intel彙編語法 330 if (strstr(line, ".att_syntax")) skip_intel = 0;//判斷是否為att彙編語法 331 332 /* Detect and skip ad-hoc __asm__ blocks, likewise skipping them. */ 333 334 if (line[0] == '#' || line[1] == '#') {//ad-hoc __asm__塊是否跳過 335 336 if (strstr(line, "#APP")) skip_app = 1; 337 if (strstr(line, "#NO_APP")) skip_app = 0; 338 339 } 340 341 /* If we're in the right mood for instrumenting, check for function 342 names or conditional labels. This is a bit messy, but in essence, 343 we want to catch:插樁時終端關注物件 344 345 ^main: - function entry point (always instrumented) 346 ^.L0: - GCC branch labelgcc下的分支標記 347 ^.LBB0_0: - clang branch label (but only in clang mode)clang下的分支標記(僅僅只是在clang模式中) 348 ^\tjnz foo - conditional branches條件跳轉分支標記 349 350 ...but not: 351 352 ^# BB#0: - clang comments 353 ^ # BB#0: - ditto 354 ^.Ltmp0: - clang non-branch labels 355 ^.LC0 - GCC non-branch labels 356 ^.LBB0_0: - ditto (when in GCC mode) 357 ^\tjmp foo - non-conditional jumps 358 359 Additionally, clang and GCC on MacOS X follow a different convention 360 with no leading dots on labels, hence the weird maze of #ifdefs 361 later on. 362 363 */ 364 365 if (skip_intel || skip_app || skip_csect || !instr_ok || 366 line[0] == '#' || line[0] == ' ') continue; 367 368 /* Conditional branch instruction (jnz, etc). We append the instrumentation 369 right after the branch (to instrument the not-taken path) and at the 370 branch destination label (handled later on). */ 371 372 if (line[0] == '\t') { 373 374 if (line[1] == 'j' && line[2] != 'm' && R(100) < inst_ratio) { //對於形如\tj[^m].格式的指令,即條件跳轉指令,且R()函式建立的隨機數小於插樁密度inst_ratio 375 376 fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32, 377 R(MAP_SIZE)); // 判斷是否為64位程式,使用fprintf函式將樁插在outf只想的檔案的\tj[^ m].跳轉指令位置,插入長度為R函式建立的小於MAP_SIZE的隨機數 378 379 ins_lines++; //插樁計數器+1,跳出迴圈進行下一次遍歷 380 381 } 382 383 continue; 384 385 } 386 387 /* Label of some sort. This may be a branch destination, but we need to 388 tread carefully and account for several different formatting 389 conventions. */ 390 391 #ifdef __APPLE__ 392 393 /* Apple: L<whatever><digit>: */ 394 395 if ((colon_pos = strstr(line, ":"))) { 396 397 if (line[0] == 'L' && isdigit(*(colon_pos - 1))) { 398 399 #else 400 401 /* Everybody else: .L<whatever>: */ 402 403 if (strstr(line, ":")) { //檢查line中是否存在“:” 404 405 if (line[0] == '.') { //檢查是否以“.”開始 406 407 #endif /* __APPLE__ */ 408 409 /* .L0: or LBB0_0: style jump destination */ 410 411 #ifdef __APPLE__ 412 413 /* Apple: L<num> / LBB<num> */ 414 415 if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3)))//檢查line[1]是否為數字,或者在clang模式下從line開始的三個位元組是否為LBB,並且隨機數小於插樁密度 416 && R(100) < )inst_ratio { 417 418 #else 419 420 /* Apple: .L<num> / .LBB<num> */ 421 422 if ((isdigit(line[2]) || (clang_mode && !strncmp(line + 1, "LBB", 3))) 423 && R(100) < inst_ratio) { //檢查line[2]是否為數字,或者在clang模式下從line[1]開始的三個位元組是否為LBB,並且隨機數小於插樁密度 424 425 #endif /* __APPLE__ */ 426 427 /* An optimization is possible here by adding the code only if the 428 label is mentioned in the code in contexts other than call / jmp. 429 That said, this complicates the code by requiring two-pass 430 processing (messy with stdin), and results in a speed gain 431 typically under 10%, because compilers are generally pretty good 432 about not generating spurious intra-function jumps. 433 434 We use deferred output chiefly to avoid disrupting 435 .Lfunc_begin0-style exception handling calculations (a problem on 436 MacOS X). */ 437 438 if (!skip_next_label) instrument_next = 1; else skip_next_label = 0; //檢查skip_next_label是否設定,是就將instrument_next設定為1 否就將skip_next_label設定為0 439 440 } 441 442 } else { 443 444 /* Function label (always instrumented, deferred mode). */ 445 446 instrument_next = 1; //否則代表這是一個function label,插樁^func,設定instrument_next為1(defered mode) 447 448 } 449 450 } 451 452 } 453 454 if (ins_lines)//如果插樁計數器不為0 455 fputs(use_64bit ? main_payload_64 : main_payload_32, outf); //向outf中寫入main_payload_64或main_payload_32 456 457 if (input_file) fclose(inf); //關閉檔案 458 fclose(outf); //關閉檔案 459 460 if (!be_quiet) { //如果使用的不是靜默模式 461 462 if (!ins_lines) WARNF("No instrumentation targets found%s.", //如果插樁計數器為空,拋異常 463 pass_thru ? " (pass-thru mode)" : ""); 464 else OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", //插樁成功輸出 465 ins_lines, use_64bit ? "64" : "32", 466 getenv("AFL_HARDEN") ? "hardened" : 467 (sanitizer ? "ASAN/MSAN" : "non-hardened"), 468 inst_ratio); 469 470 } 471 472 } 473 474 475 /* Main entry point 主函式*/ 476 477 int main(int argc, char** argv) { 478 479 s32 pid; 480 u32 rand_seed; 481 int status; 482 u8* inst_ratio_str = getenv("AFL_INST_RATIO");//獲取環境變數AFL_INST_RATIO(該環境變數主要控制檢測每個分支的概率,取值為0到100%,設定為0時值檢測函式入口的跳轉,而不會檢測函式分支的跳轉) 483 484 struct timeval tv; 485 struct timezone tz; 486 487 clang_mode = !!getenv(CLANG_ENV_VAR); 488 489 if (isatty(2) && !getenv("AFL_QUIET")) { 490 491 SAYF(cCYA "afl-as " cBRI VERSION cRST " by <[email protected]>\n"); 492 493 } else be_quiet = 1; 494 495 if (argc < 2) { 496 497 SAYF("\n" 498 "This is a helper application for afl-fuzz. It is a wrapper around GNU 'as',\n" 499 "executed by the toolchain whenever using afl-gcc or afl-clang. You probably\n" 500 "don't want to run this program directly.\n\n" 501 502 "Rarely, when dealing with extremely complex projects, it may be advisable to\n" 503 "set AFL_INST_RATIO to a value less than 100 in order to reduce the odds of\n" 504 "instrumenting every discovered branch.\n\n"); 505 506 exit(1); 507 508 } 509 510 gettimeofday(&tv, &tz);//獲取當前精確時間 511 512 rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid(); //通過當前時間與程序pid進行亦或處理 513 514 srandom(rand_seed);//獲得隨機化種子 515 516 edit_params(argc, argv);//檢查並修改引數以傳遞給“as”。檔名是以GCC傳遞的最後一個引數決定的。此函式主要設定變數as_params的值,以及use_64bit/modified_file的值 517 518 if (inst_ratio_str) {//如果獲取到"AFL_INST_RATIO"環境變數則進入分支 519 520 if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100) // 如果沒有將覆蓋率寫入inst_ratio變數或者inst_ratio中的值超過100的話,則進入分支丟擲異常 521 FATAL("Bad value of AFL_INST_RATIO (must be between 0 and 100)"); 522 523 } 524 525 if (getenv(AS_LOOP_ENV_VAR))//如果獲取到"__AFL_AS_LOOPCHECK"環境變數值,則進入分支 526 FATAL("Endless loop when calling 'as' (remove '.' from your PATH)");//丟擲異常 527 528 setenv(AS_LOOP_ENV_VAR, "1", 1);//設定"__AFL_AS_LOOPCHECK"環境變數為1 529 530 /* When compiling with ASAN, we don't have a particularly elegant way to skip 531 ASAN-specific branches. But we can probabilistically compensate for 532 that... */ 533 534 if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) { //獲取"AFL_USE_ASAN"或"AFL_USE_MSAN"環境變數,如果其中有一個值為1則進入分支 535 sanitizer = 1;//sanitizer設定為1 536 inst_ratio /= 3;//inst_ratio除以3 537 } 538 539 if (!just_version) add_instrumentation();//如果不是隻查詢version,那麼就會進入add_instrumentastion()函式,該函式主要處理輸入檔案,生成modified_file,將樁插入釋放的位置 540 541 if (!(pid = fork())) { //呼叫fork函式建立一個子程序。在執行execvp函式執行是 542 543 execvp(as_params[0], (char**)as_params);//執行命令和引數 544 FATAL("Oops, failed to execute '%s' - check your PATH", as_params[0]);//失敗了就丟擲異常 545 546 } 547 548 if (pid < 0) PFATAL("fork() failed");//等待子程序結束 549 550 if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed"); //讀取環境變數"AFL_KEEP_ASSEMBLY"失敗,則unlink掉modified_file 551 552 if (!getenv("AFL_KEEP_ASSEMBLY")) unlink(modified_file); 553 //設定該環境變數主要是為了防止afl-as刪掉插樁後的彙編檔案,設定為1會保留插樁後的彙編檔案 554 exit(WEXITSTATUS(status)); 555 556 }