fuzzfactory源码阅读(一)代码总览

本文介绍了FuzzFactory中如何通过C++代码实现针对六个特定领域的模糊测试,包括API接口、DSF映射和简化器函数。通过新域注册、DSF操作和示例代码展示了如何在AFL框架下快速定制模糊测试策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FuzzFactory 中,特定于域的模糊测试应用程序是通过检测测试程序来实现的。表 1 描述了实现本文中描述的六个域中的每个域所需的代码行。在我们的应用程序中,我们使用 LLVM 执行检测。
伪代码中用于特定领域模糊化的API。

 类型dsf_t; /* 特定于域的反馈图 */
 /* 注册一个新域。在初始化期间调用一次。*/ dsf_t new_域(int key_size, function reduce, int a_0);
/* 对 DSF 映射的更新。在测试执行期间调用。*/ 
int dsf_get(dsf_t dsf, int k);	返回 dsf[k] 
void dsf_set(dsf_t dsf, int k, int v);	// dsf[k] = v 
void dsf_increment(dsf_t dsf, int k, int v); // dsf[k] = dsf[k] + v 
void dsf_union(dsf_t dsf, int k, int v);	// dsf[k] = dsf[k] | v 
void dsf_maximize(dsf_t dsf, int k, int v); // dsf[k] = max(dsf[k], v)

在这里插入图片描述
图 11 概述了 FuzzFactory 提供的 API。类型dsf_t定义域特定映射的类型 。在我们的实现中,键和值始终是 32 位无符号整数。但是,用户可以指定DSF映射的大小;也就是说,它将包含的 keys 的数量。API 函数new_domain注册一个新域,其密钥集 K 包含key_size个密钥。参数 reduce 和 a_0分别提供化简器函数(类型 int x int -> int)和初始聚合值。对于慢速域,key_size为 1。对于 K 是一组程序位置 L 的应用程序,我们使用 216 key_size,并将 16 位伪随机数分配给基本块位置,类似于 AFL。对于增量模糊测试应用程序,其中 K = L×L,
我们使用哈希函数将两个基本块位置组合成一个整数值键。集合 V 和 A 通过使用 DSF 映射和 reduce 函数的实现隐式定义 。对于诸如有效性模糊测试之类的应用,其中 A 是一组数量级,我们使用位向量来表示集合。
该函数 new_domain 返回 DSF 映射的句柄,然后在后续中使用
图 11 中列出的 API,例如dsf_increment。在执行任何测试之前, 在测试 program 启动时插入对new_domain调用。由用户负责确保提供的简化器函数满足属性 1 和 2,这反过来又保证了单调聚合(定理 1)。以"dsf_"开头的 API 函数操作 DSF 映射。参数键必须在 [0, key_size) 范围内。

include文件夹

afl-llvm-rt.o.c

/* Domain-specific fuzzing */
u32* __fuzzfactory_dsf_map = (u32*) (&__afl_area_initial[MAP_SIZE]); /* Additional feedback maps */
static dsf_config dsf_configs[DSF_MAX]; // Array of configs
static u32 dsf_count = 0; // Length of above array (i.e, number of non-zero items)
/* SHM setup. */
/* Set waypoints map to be after the AFL code coverage shared memory region */
    __fuzzfactory_dsf_map = (u32*) &__afl_area_ptr[MAP_SIZE];

waypoints.h

/* Type of DSF map reference */
typedef int dsf_t;

/* Functions that update DSF map at run-time */
void __fuzzfactory_dsf_max(dsf_t id, u32 key, u32 value);
void __fuzzfactory_dsf_bitwise_or(dsf_t id, u32 key, u32 value);
void __fuzzfactory_dsf_set(dsf_t id, u32 key, u32 value);
void __fuzzfactory_dsf_increment(dsf_t id, u32 key, u32 value);

/* Same as above but first arg is pointer to DSF map */
void __fuzzfactory_dsfp_max(dsf_t* p, u32 key, u32 value);
void __fuzzfactory_dsfp_bitwise_or(dsf_t* p, u32 key, u32 value);
void __fuzzfactory_dsfp_set(dsf_t* p, u32 key, u32 value);
void __fuzzfactory_dsfp_increment(dsf_t* p, u32 key, u32 value);

/* Macros for use in manual insertion of DSF calls */
#define FUZZFACTORY_DSF_MAX(id, k, v) (__fuzzfactory_dsf_max(id, k, v))
#define FUZZFACTORY_DSF_BIT(id, k, v) (__fuzzfactory_dsf_bitwise_or(id, k, v))
#define FUZZFACTORY_DSF_SET(id, k, v) (__fuzzfactory_dsf_set(id, k, v))
#define FUZZFACTORY_DSF_INC(id, k, v) (__fuzzfactory_dsf_increment(id, k, v))

void __afl_waypoints_set_state(u32 state);
u32  __afl_waypoints_get_state();
void __afl_waypoints_hash_state(int num_args, ...);

#define AFL_WAYPOINTS_SET_STATE(state) __afl_waypoints_set_state(state)
#define AFL_WAYPOINTS_GET_STATE() (__afl_waypoints_get_state())
#define AFL_WAYPOINTS_HASH_STATE(num_args, ...) (__afl_waypoints_hash_state((num_args), ##__VA_ARGS__))

/* Max number of domain-specific maps */
#define DSF_MAX 4

/* Config for domain-specific fuzzing */
typedef struct dsf_config_t {
  int start;
  int end;
  int reducer;
  u32 initial;
} dsf_config;

/* Register a new domain-specific fuzzing front-end */
dsf_t __fuzzfactory_new_domain(u32 size, enum fuzzfactory_reducer reducer, u32 initial);

#define FUZZFACTORY_DSF_NEW(name, size, reducer, initial) dsf_t name; \
  __attribute__((constructor(0))) static void __init_##name() { \
  name = __fuzzfactory_new_domain(size, reducer, initial); \
} \

#else // Not compiling with AFL

reducers.h

这个文件只定义了还原器函数的枚举,它作为枚举值在模糊器(afl-fuzz.c)之间通过 IPC 通信。作为枚举值,在模糊器(afl-fuzz.c)和仪器测试程序之间通过 IPC 通信。和仪器测试程序之间通过IPC通信。
这些还原器函数的实现在其他地方(reducers.c)。 而且必须与此文件保持同步。该实现只链接到模糊器中;测试程序不需要它。

enum fuzzfactory_reducer {
  FUZZFACTORY_REDUCER_MAX,
  FUZZFACTORY_REDUCER_MIN,
  FUZZFACTORY_REDUCER_LOG_BUCKET,
  FUZZFACTORY_REDUCER_BIT_UNION,
  FUZZFACTORY_REDUCER_BIT_INTERSECT,
};

llvm_mode文件夹中:
在这里插入图片描述

afl-catch-dlclose.so.c

int dlclose (void *handle); 函数描述: dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

afl-clang-fast.c

#ifdef USE_TRACE_PC
  cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
  cc_params[cc_par_cnt++] = "-mllvm";
  cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
#else
  if (!getenv("WAYPOINTS_DISABLE_COVERAGE")) {
    cc_params[cc_par_cnt++] = "-Xclang";
    cc_params[cc_par_cnt++] = "-load";
    cc_params[cc_par_cnt++] = "-Xclang";
    cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
  }

  /* Waypoints passes */ 
  char* domains = getenv("WAYPOINTS");
  if (!domains) {
    domains = getenv("DOMAINS");
    if (!domains)
      domains = "";
  }
  
  char* comma = ",";
  char* domain = strtok(domains, comma);

  while (domain != NULL) {
    printf("Found domain: %s\n", domain);
    cc_params[cc_par_cnt++] = "-Xclang";
    cc_params[cc_par_cnt++] = "-load";
    cc_params[cc_par_cnt++] = "-Xclang";
    cc_params[cc_par_cnt++] = alloc_printf("%s/waypoints-%s-pass.so", obj_path, domain);
    cc_params[cc_par_cnt++] = alloc_printf("%s/waypoints-%s-rt.o", obj_path, domain);

    domain = strtok(NULL, comma);
  }

afl-llvm-rt.o.c

/* SHM setup. */

static void __afl_map_shm(void) {

  u8 *id_str = getenv(SHM_ENV_VAR);

  /* If we are running under AFL, attach to the appropriate region, replacing the
     early-stage __afl_area_initial region that is needed to allow some really
     hacky .init code to work correctly in projects such as OpenSSL. */

  if (id_str) {

    u32 shm_id = atoi(id_str);

    __afl_area_ptr = shmat(shm_id, NULL, 0);

    /* Whooooops. */

    if (__afl_area_ptr == (void *)-1) _exit(1);

    /* Write something into the bitmap so that even with low AFL_INST_RATIO,
       our parent doesn't give up on us. */

    __afl_area_ptr[0] = 1;
    
    /* Set waypoints map to be after the AFL code coverage shared memory region */
    __fuzzfactory_dsf_map = (u32*) &__afl_area_ptr[MAP_SIZE];
# 将航点图设置在AFL代码覆盖共享内存区域之后
  }

}

fuzzfactory.hpp

hpp,其实质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的调用者只需要include该hpp文件即可,无需再将cpp加入到project中进行编译。
而实现代码将直接编译到调用者的obj文件中,不再生成单独的obj,
采用hpp将大幅度减少调用 project中的cpp文件数与编译次数,也不用再发布烦人的lib与dll,因此非常适合用来编写公用的开源库。
表 2.定义用于注入代码的检测函数,该代码更新特定于 domain 的反馈映射。它们在表 3 到 8 中使用。如果在对被测程序进行编译时传递期间遇到相应的语法对象,则会激活钩子。这些钩子的处理程序逻辑可以在被测的预备忘中注入代码。操作是在检测期间用于实际注入代码的函数。实用程序函数在编译时可用于处理程序逻辑。
检测挂钩 描述
new_basic_block() 在被测程序的控制流图中基本块的开头激活。
entry_point() 在测试执行的入口点激活(例如 ,启动 main 函数)。
func_call(name, args) 在调用名为 name 的函数的表达式中激活,该表达式带有参数 args。
bin_expr(type, left, op, right) 激活通过该格式的二进制操作器进行表达
“左 op right”(例如 x == 42),其中操作数具有类型 类型 (例如 long)。
开关(类型, 阀, 案例) 在类型类型的值 val 上遇到 switch 语句时激活,其中 cases 是 case 子句的列表。
检测操作 描述
insert_after(inst) 在当前激活其检测挂钩的指令之后立即插入指令 inst。
insert_before(inst) 在当前激活其检测挂钩的指令之前插入一条指令 inst。
实用程序函数 描述
current_program_loc() 返回与当前检测位置相对应的程序位置(即集合 L 中的值)。
target_program_loc(case) 返回程序位置(即,集合 L 中的值),该位置是 switch 语句中事例的目标。
comm_bits(a, b, n) 计算两个 n 字节操作数 a 和 b 之间的公共位数。例如,comm_bits(1025, 1026, 4) = 30,因为这些 32 位操作数中只有 2 位不同。
实现。传统上,实现每个这样的领域都需要在修改模糊测试工具(如AFL)以实现特定于领域的目标时付出非凡的努力。使用FuzzFactory,上述六个域中的四个可以在少于30行C++中实现。表 1 列出了使用 FuzzFactory 实现本文中介绍的六个域中的每个域所需的代码行。第 6 节提供了有关我们实现的更多详细信息。对于重新实现先前工作的域,该表还列出了实现相应的专用独立模糊测试工具所需的代码行。

还有其他的:

afl-showdsf.c

模仿showmap的showdsf。一个非常简单的工具,运行目标二进制文件,并以人类可读的形式显示特定领域反馈的内容。

afl-fuzz.c

见下一篇

reducers.c

参数 reduce 和 a_0分别提供化简器函数(类型 int x int -> int)和初始聚合值。

/* Make sure that this array is consistent with the enum defined in reducers.h */
reducer_t dsf_reducers[] = {
  [FUZZFACTORY_REDUCER_MAX]        = reducer_max,
  [FUZZFACTORY_REDUCER_MIN]        = reducer_min,
  [FUZZFACTORY_REDUCER_LOG_BUCKET] = reducer_log_bucket,
  [FUZZFACTORY_REDUCER_BIT_UNION]  = reducer_bit_union,
  [FUZZFACTORY_REDUCER_BIT_INTERSECT]  = reducer_bit_intersection,
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

席八

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值