You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AFL/afl-gcc.c

358 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
Copyright 2013 Google LLC All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 这部分是版权声明和许可证信息说明这个文件是在Apache License 2.0下发布的。
/*
american fuzzy lop - wrapper for GCC and clang
----------------------------------------------
Written and maintained by Michal Zalewski <lcamtuf@google.com>
This program is a drop-in replacement for GCC or clang. The most common way
of using it is to pass the path to afl-gcc or afl-clang via CC when invoking
./configure.
(Of course, use CXX and point it to afl-g++ / afl-clang++ for C++ code.)
The wrapper needs to know the path to afl-as (renamed to 'as'). The default
is /usr/local/lib/afl/. A convenient way to specify alternative directories
would be to set AFL_PATH.
If AFL_HARDEN is set, the wrapper will compile the target app with various
hardening options that may help detect memory management issues more
reliably. You can also specify AFL_USE_ASAN to enable ASAN.
If you want to call a non-default compiler as a next step of the chain,
specify its location via AFL_CC or AFL_CXX.
*/
// 这部分是注释,提供了关于这个程序的概述和使用说明。
#define AFL_MAIN
#include "config.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
// 这些是包含的头文件其中一些是AFL自己的头文件其他的是C标准库的头文件
static u8* as_path; /* Path to the AFL 'as' wrapper */
static u8** cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
static u8 be_quiet, /* Quiet mode */
clang_mode; /* Invoked as afl-clang*? */
// 这些是全局变量声明。`as_path`存储AFL汇编器的路径`cc_params`存储传递给实际编译器的参数,`cc_par_cnt`是参数计数器,`be_quiet`用于控制
// 是否静默模式,`clang_mode`指示是否以`afl-clang`或`afl-clang++`模式调用。
/* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived
from argv[0]. If that fails, abort. */
static void find_as(u8* argv0) {
// 这个函数尝试在AFL_PATH环境变量指定的路径或从argv[0]派生的路径中找到AFL的“假”GNU汇编器。如果找不到程序将终止。
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");
}
/* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char** argv) {
//定义了一个函数edit_params它接受两个参数argc是参数的数量argv是参数的数组。
u8 fortify_set = 0, asan_set = 0;//声明两个变量fortify_set和asan_set用于跟踪是否已经设置了FORTIFY_SOURCE和address sanitizerASan标志
u8 *name;//用于存储程序的名称
#if defined(__FreeBSD__) && defined(__x86_64__)
u8 m32_set = 0;
#endif
cc_params = ck_alloc((argc + 128) * sizeof(u8*));//分配内存以存储修改后的参数列表大小为argc + 128个u8*类型的指针。
name = strrchr(argv[0], '/');//找到argv[0](程序的路径)中最后一个'/'字符,这通常用于获取程序的名称。
if (!name) name = argv[0]; else name++;//如果name为NULL即argv[0]中没有'/'则name指向argv[0]的开始。否则name向前移动一个字符跳过'/'。
if (!strncmp(name, "afl-clang", 9)) {
clang_mode = 1;//检查程序名称是否以"afl-clang"开头如果是设置clang_mode标志为1
setenv(CLANG_ENV_VAR, "1", 1);//设置环境变量CLANG_ENV_VAR为"1"这可能用于通知其他部分的AFL工具链正在使用Clang。
if (!strcmp(name, "afl-clang++")) {
u8* alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";//如果AFL_CXX设置将其值作为第一个参数否则使用"clang++"。
} else {
u8* alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";//否则尝试获取环境变量AFL_CC的值。
}
} else {
/* With GCJ and Eclipse installed, you can actually compile Java! The
instrumentation will work (amazingly). Alas, unhandled exceptions do
not call abort(), so afl-fuzz would need to be modified to equate
non-zero exit codes with crash conditions when working with Java
binaries. Meh. */
#ifdef __APPLE__
//在Apple系统上根据程序名称设置不同的编译器。如果AFL_CXX、AFL_GCJ或AFL_CC环境变量设置使用它们的值否则使用默认的编译器名称
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]) {
//输出错误信息指出在MacOS X上需要设置AFL_CC或AFL_CXX环境变量。
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
//对于非Apple系统根据程序名称设置不同的编译器。如果相应的环境变量设置使用它们的值否则使用默认的编译器名称。
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 /* __APPLE__ */
}
while (--argc) {
u8* cur = *(++argv);
if (!strncmp(cur, "-B", 2)) {//如果当前参数以"-B"开头,输出警告信息,并跳过后续参数(如果当前参数后面紧跟着的是编译器的路径)。
if (!be_quiet) WARNF("-B is already set, overriding");//如果程序不在静默模式,输出警告信息。
if (!cur[2] && argc > 1) { argc--; argv++; }//如果-B后面紧跟着的是编译器的路径跳过这个路径。
continue;
}
if (!strcmp(cur, "-integrated-as")) continue;//如果参数是"-integrated-as",跳过它。
if (!strcmp(cur, "-pipe")) continue;//如果参数是"-pipe",跳过它。
#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;//如果参数是"-fsanitize=address"或"-fsanitize=memory"设置asan_set标志。
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;//如果参数包含"FORTIFY_SOURCE"设置fortify_set标志。
cc_params[cc_par_cnt++] = cur;
}
cc_params[cc_par_cnt++] = "-B";
cc_params[cc_par_cnt++] = as_path;
//向参数列表中添加"-B"和AFL汇编器的路径。
if (clang_mode)
cc_params[cc_par_cnt++] = "-no-integrated-as";//如果clang_mode标志设置向参数列表中添加`"-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) {//检查是否设置了asan_set标志。
/* Pass this on to afl-as to adjust map density. */
setenv("AFL_USE_ASAN", "1", 1);//如果设置设置环境变量AFL_USE_ASAN为"1"
} else if (getenv("AFL_USE_ASAN")) {//如果asan_set标志未设置但设置了环境变量AFL_USE_ASAN。
if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive");//如果同时设置了AFL_USE_MSAN输出错误信息并终止程序。
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive");//如果同时设置了AFL_HARDEN输出错误信息并终止程序。
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=address";//向参数列表中添加"-U_FORTIFY_SOURCE"和"-fsanitize=address"。
} else if (getenv("AFL_USE_MSAN")) {
if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive");//如果同时设置了AFL_USE_ASAN输出错误信息并终止程序。
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive");//如果同时设置了AFL_HARDEN输出错误信息并终止程序。
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=memory";//向参数列表中添加"-U_FORTIFY_SOURCE"和"-fsanitize=memory"。
}
if (!getenv("AFL_DONT_OPTIMIZE")) {//检查是否设置了环境变量AFL_DONT_OPTIMIZE。
#if defined(__FreeBSD__) && defined(__x86_64__)
/* On 64-bit FreeBSD systems, clang -g -m32 is broken, but -m32 itself
works OK. This has nothing to do with us, but let's avoid triggering
that bug. */
if (!clang_mode || !m32_set)
cc_params[cc_par_cnt++] = "-g";//如果不是Clang模式或没有设置m32_set标志向参数列表中添加"-g"。
#else
cc_params[cc_par_cnt++] = "-g";
#endif//结束#if defined(__FreeBSD__) && defined(__x86_64__)条件编译块。
cc_params[cc_par_cnt++] = "-O3";
cc_params[cc_par_cnt++] = "-funroll-loops";//向参数列表中添加"-O3"和"-funroll-loops",这些是优化选项。
/* Two indicators that you're building for fuzzing; one of them is
AFL-specific, the other is shared with libfuzzer. */
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";
//如果设置,向参数列表中添加一系列"-fno-builtin-*"选项,这些选项禁用编译器的内置函数。
}
cc_params[cc_par_cnt] = NULL;
}
/* Main entry point */
//最后是函数结束语,结束函数定义。
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;
}