一个中文版本的 LibAFL 笔记,主要内容是 LibAFL 原理相关的内容,同时也附加一些 LibAFL 使用方面的 tips ,方便查阅和参考。
- LibAFL-Learn
- 关于LibAFL
- 如何导入 LibAFL 作为依赖库
- LibAFL 的基本功能
- InProcess Fuzz 的基本要素
- 入门
- 进阶
- Fuzz 流程分析
- Mutators 介绍
- BitFlipMutator
- ByteFlipMutator
- ByteIncMutator
- BytesDecMutator
- ByteNegMutator
- ByteRandMutator
- Byte/Word/Dword/Qword AddMutator
- Byte/Word/Dword InterestingMutator
- BytesDeleteMutator
- BytesExpandMutator
- BytesInsertMutator
- BytesRandInsertMutator
- BytesSetMutator
- BytesRandSetMutator
- BytesCopyMutator
- BytesInsertCopyMutator
- BytesSwapMutator
- CrossoverInsertMutator
- CrossoverReplaceMutator
LibAFL 是一个使用 rust 编写的 fuzz 库, 核心代码参考自著名的 fuzz 工具 AFL 以及其社区版本 AFL++ 。将 LibAFL 整合到你的项目中,可以快速获得可定制的 fuzz 能力 。
因为 LibAFL 是用 rust 开发的,所以你需要有一个 rust 项目才能导入 LibAFL (这里暂且不提 pylibafl )。如果你对 rust 完全不了解,请左转 Rust 语言圣经 。
我们在 cargo.toml 文件中导入 LibAFL
[dependencies]
libafl = "0.9.0"
这样你就可以在项目中使用 LibAFL 了。但是,LibAFL 的大版本存在许多 BUG,所以我一般会选择使用某一个修复了 BUG 的 commit 作为依赖库。 例如,你可以使用下面的语句导入一个指定 commit 的 LibAFL 作为依赖库, 这个 commit 是 0.9.0 版本之后的某一个 commit
[dependencies]
libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "0727c80" }
LibAFL 提供了两个基本功能 (其他功能我暂时也没有用到,欢迎补充)
- ForkServer Fuzz
- InProcess Fuzz
第一个功能,ForkServer Fuzz, 和 AFL 中的 ForkServer Mode 类似,需要使用者自己对目标程序插桩,然后交给 fuzzer 测试即可。使用方法可以参考 forkserver_simple,可以看做对 AFL 经典功能的复刻。第二个功能,InProcess Fuzz, 不要求使用 afl-gcc 等工具对程序插桩,可以自己定义一个目标函数,并且对其进行 fuzz,可以自己提供覆盖率,crash 信息,灵活度很高,也是我主要使用的一个功能。使用方法可以参考 bady_fuzzer 。
创建并运行一个 InProcess Fuzz 可能用到以下要素
- Observer:观察者
- Harness:被 fuzz 的函数
- Feedback:反馈
- Objective:目标
- State:状态
- Monitor & Manager:监控&管理
- Scheduler:调度器
- Fuzzer:fuzzer
- Mutator:变异器
- Stage:阶段
- Executor:执行器
我们一个一个介绍
了解下面这些要素,你已经可以写一个实现自己目标的 fuzz 工具了。
观察者代表对一些量的观察,比如观察一个数组,观察一个 map,观察一块共享内存。使用下面的语句可以针对一块共享内存创建一个观察者。其中 StdMapObserver 是常用的观察者类型。它的构造函数中传入了一个由共享内存对象转化来的可变切片,表示 正在观察一块共享内存
。之后如果需要这块共享内存的信息,可以直接通过观察者获取。
// Create an observation channel using shared memory
let observer = unsafe { StdMapObserver::new("shared_memory", shmem.as_mut_slice()) };
Harness 表示被 fuzz 的函数,通常是一个闭包。例如下面这个闭包。其中 input 是 fuzzer 每次传递给 harness 的输入,代码编写者可以对这个输入进行判断,来选择返回 crash 信号 ExitKind:Crash
还是 返回正常退出信号 ExitKind:Ok
。通常来说,代码编写者还要在 harness 函数里添加写入覆盖率信息的逻辑,引导 fuzzer。这里具体如何写入取决于 observer 的构建方式。如果 observer 观察的是一个数组,那么可以向数组写入信息,如果 observer 观察的是一块共享内存,那么可以向共享内存写入信息。
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
let mut buf = input.bytes();
if buf.len() == 1 {
return ExitKind::Crash;
}
WriteCoverage(); // 写入覆盖率信息
ExitKind::Ok
};
Feedback 表示一种抽象的反馈信息。上面提到 observer 创建了针对一块共享内存的观察,那么 feedback 就构建在 observer 提供的观察信息基础上,抽象成对于 fuzzer 有引导价值的一种反馈信息。例如,下面的语句创建了一个 feedback 。
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer);
Feedback 和 observer 的区别在于,observer 只是获取信息,但是 feedback 会记录和分析信息,并且通过信息判断一个测试用例是否是 interesting 的。
Objective 表示一种抽象的目标条件。和 feedback 相同, objective 实现了 Feedback trait,也可以判断一个测试用例是否是 interesting 的。例如,下面的语句创建了一个 objective,它实际上就是一个 CrashFeedback ,会在 harness 函数返回 ExitKind::Crash
时,表示测试用例是 interesting 的。
// A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new();
和 feedback 不同的是,如果一个 feedback 是 interesting 的,只表示这个测试用例有进一步 fuzz 的潜力。但是,如果一个 objective 是 interesting 的,则说明这个测试用例是我们真正需要的目标。
State 是一组复合信息,包含随机数模块,corpus,solution,feedback 和 objective。其中随机数模块为 fuzzer 在运行过程中提供了随机性支持,corpus 设置了 interesting 的测试用例的保存方式,solutions 设置了 objective 的保存方式,feedback 和 objective 则是上面创建的 feedback 和 objective。下面是一个简单的例子
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
// States of the feedbacks.
// The feedbacks can report the data that should persist in the State.
&mut feedback,
// Same for objective feedbacks
&mut objective,
)
可以通过 state 加载语料
state.load_initial_inputs_forced(
&mut fuzzer,
&mut executor,
&mut mgr,
&[PathBuf::from("./seeds")],
)?;
可以通过 state 查看 solutions 状态
state.solutions().is_empty()
可以通过 state 获取随机数
state.rand_mut().below(16);
Monitor 表示对于 fuzz 过程的监控。Monitor 实际上不是必须的。使用下面的代码可以创建一个简单的 monitor 和 manager
// The Monitor trait define how the fuzzer stats are displayed to the user
let mon = SimpleMonitor::new(|s| println!("{s}"));
let mut mgr = SimpleEventManager::new(mon);
它会在运行时打印出统计信息
了解下面这些要素,你可以改进你的 fuzz 工具
Scheduler 决定按何种顺序选取 corpus 来生成测试用例。例如一个常见的 scheduler 是 QueueScheduler, 它按照顺序从 corpus 中获取语料
let scheduler = QueueScheduler::new();
可以通过实现自己的 Scheduler 来决定选取语料的顺序
Fuzzer 是对整个 fuzz 库的封装。使用下面的语句可以创建一个简单的 fuzzer
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
可以通过 fuzzer 启动 fuzz
fuzzer.fuzz_loop()
Executor 负责将测试用例发送给 harness 运行。下面是一个简单的 executor
// Create the executor for an in-process function with just one observer
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(observer),
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create the Executor");
Mutator 表示如何对来自 corpus 的语料进行变异,生成测试用例。最常用的 mutator 是 havoc_mutations()
和 StdScheduledMutator 的组合
let mutator = StdScheduledMutator::new(havoc_mutations());
havoc_muations()
会返回一个 mutator 的元组,包含如下 mutator
/// Get the mutations that compose the Havoc mutator
#[must_use]
pub fn havoc_mutations() -> HavocMutationsType {
tuple_list!(
BitFlipMutator::new(),
ByteFlipMutator::new(),
ByteIncMutator::new(),
ByteDecMutator::new(),
ByteNegMutator::new(),
ByteRandMutator::new(),
ByteAddMutator::new(),
WordAddMutator::new(),
DwordAddMutator::new(),
QwordAddMutator::new(),
ByteInterestingMutator::new(),
WordInterestingMutator::new(),
DwordInterestingMutator::new(),
BytesDeleteMutator::new(),
BytesDeleteMutator::new(),
BytesDeleteMutator::new(),
BytesDeleteMutator::new(),
BytesExpandMutator::new(),
BytesInsertMutator::new(),
BytesRandInsertMutator::new(),
BytesSetMutator::new(),
BytesRandSetMutator::new(),
BytesCopyMutator::new(),
BytesInsertCopyMutator::new(),
BytesSwapMutator::new(),
CrossoverInsertMutator::new(),
CrossoverReplaceMutator::new(),
)
}
StdScheduledMutator 是对这些 mutator 的进一步封装。当 StdScheduledMutator 的 mutate
方法被调用时,StdScheduledMutator 会在这些 mutator 中随机选择多次进行变异
/// New default implementation for mutate.
/// Implementations must forward mutate() to this method
fn scheduled_mutate(
&mut self,
state: &mut S,
input: &mut I,
stage_idx: i32,
) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped;
let num = self.iterations(state, input);
for _ in 0..num {
let idx = self.schedule(state, input);
let outcome = self
.mutations_mut()
.get_and_mutate(idx, state, input, stage_idx)?;
if outcome == MutationResult::Mutated {
r = MutationResult::Mutated;
}
}
Ok(r)
}
可以通过实现自己的 mutator 来决定变异方式
Stage 是对 mutator 的进一步封装。Stage 从 corpus 中获取语料,利用 mutator 进行变异,然后交给 executor 。
这里我们分析一下 fuzz_one
方法的实现,这个方法表示进行一次 fuzz。它首先使用 scheduler 的 next
方法获取当前的 corpus id,然后交给 stage 处理
fn fuzz_one(
&mut self,
stages: &mut ST,
executor: &mut E,
state: &mut CS::State,
manager: &mut EM,
) -> Result<CorpusId, Error> {
// Init timer for scheduler
#[cfg(feature = "introspection")]
state.introspection_monitor_mut().start_timer();
// Get the next index from the scheduler
let idx = self.scheduler.next(state)?;
// Mark the elapsed time for the scheduler
#[cfg(feature = "introspection")]
state.introspection_monitor_mut().mark_scheduler_time();
// Mark the elapsed time for the scheduler
#[cfg(feature = "introspection")]
state.introspection_monitor_mut().reset_stage_index();
// Execute all stages
stages.perform_all(self, executor, state, manager, idx)?;
// Init timer for manager
#[cfg(feature = "introspection")]
state.introspection_monitor_mut().start_timer();
// Execute the manager
manager.process(self, state, executor)?;
// Mark the elapsed time for the manager
#[cfg(feature = "introspection")]
state.introspection_monitor_mut().mark_manager_time();
Ok(idx)
}
在 stages 里面调用 perform_all
方法,先使用第一个 stage 运行获取、运行测试用例,然后调用第二个 stages 元组
fn perform_all(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Head::State,
manager: &mut EM,
corpus_idx: CorpusId,
) -> Result<(), Error> {
// Perform the current stage
self.0
.perform(fuzzer, executor, state, manager, corpus_idx)?;
// Execute the remaining stages
self.1
.perform_all(fuzzer, executor, state, manager, corpus_idx)
}
perform
方法如下
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Z::State,
manager: &mut EM,
corpus_idx: CorpusId,
) -> Result<(), Error> {
let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx);
#[cfg(feature = "introspection")]
state.introspection_monitor_mut().finish_stage();
ret
}
在里面继续调用到了 perform_mutational
方法,这里根据 corpus_idx 从 state 中获取指定的 testcase
/// Runs this (mutational) stage for the given testcase
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
fn perform_mutational(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Z::State,
manager: &mut EM,
corpus_idx: CorpusId,
) -> Result<(), Error> {
let num = self.iterations(state, corpus_idx)?;
start_timer!(state);
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
let Ok(input) = I::try_transform_from(&mut testcase, state, corpus_idx) else { return Ok(()); };
drop(testcase);
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
for i in 0..num {
let mut input = input.clone();
start_timer!(state);
self.mutator_mut().mutate(state, &mut input, i as i32)?;
mark_feature_time!(state, PerfFeature::Mutate);
// Time is measured directly the `evaluate_input` function
let (untransformed, post) = input.try_transform_into(state)?;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?;
start_timer!(state);
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
post.post_exec(state, i as i32, corpus_idx)?;
mark_feature_time!(state, PerfFeature::MutatePostExec);
}
Ok(())
}
里面调用 evaluate_input
fn evaluate_input(
&mut self,
state: &mut Self::State,
executor: &mut E,
manager: &mut EM,
input: <Self::State as UsesInput>::Input,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
self.evaluate_input_events(state, executor, manager, input, true)
}
再调用 evaluate_input_events
fn evaluate_input_events(
&mut self,
state: &mut CS::State,
executor: &mut E,
manager: &mut EM,
input: <CS::State as UsesInput>::Input,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
self.evaluate_input_with_observers(state, executor, manager, input, send_events)
}
再调用 evaluate_input_with_observers
,这里分成两段,首先调用 execute_input
把 testcase 喂给闭包函数,然后调用 process_execution
获取反馈信息
fn evaluate_input_with_observers<E, EM>(
&mut self,
state: &mut Self::State,
executor: &mut E,
manager: &mut EM,
input: <Self::State as UsesInput>::Input,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
where
E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
EM: EventFirer<State = Self::State>,
{
let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers();
self.process_execution(state, manager, input, observers, &exit_kind, send_events)
}
第一段,execute_input
里面会调用 run_target
/// Runs the input and triggers observers and feedback
pub fn execute_input<E, EM>(
&mut self,
state: &mut CS::State,
executor: &mut E,
event_mgr: &mut EM,
input: &<CS::State as UsesInput>::Input,
) -> Result<ExitKind, Error>
where
E: Executor<EM, Self> + HasObservers<Observers = OT, State = CS::State>,
EM: UsesState<State = CS::State>,
OT: ObserversTuple<CS::State>,
{
start_timer!(state);
executor.observers_mut().pre_exec_all(state, input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers);
*state.executions_mut() += 1;
start_timer!(state);
let exit_kind = executor.run_target(self, state, event_mgr, input)?;
mark_feature_time!(state, PerfFeature::TargetExecution);
start_timer!(state);
executor
.observers_mut()
.post_exec_all(state, input, &exit_kind)?;
mark_feature_time!(state, PerfFeature::PostExecObservers);
Ok(exit_kind)
}
run_target
里实际就是调用之前的闭包函数 harness_fn
,执行我们自定义的逻辑
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error> {
self.handlers
.pre_run_target(self, fuzzer, state, mgr, input);
let ret = (self.harness_fn.borrow_mut())(input);
self.handlers.post_run_target();
Ok(ret)
}
第二段,process_execution
获取反馈信息,可以看到这里通过 objective 判断当前的 testcase 是否是 solution,通过 feedback 判断当前的 testcase 是否是 interesting 的,最后在 match 块内根据结果进行相应操作
/// Evaluate if a set of observation channels has an interesting state
fn process_execution<EM>(
&mut self,
state: &mut CS::State,
manager: &mut EM,
input: <CS::State as UsesInput>::Input,
observers: &OT,
exit_kind: &ExitKind,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>
where
EM: EventFirer<State = Self::State>,
{
let mut res = ExecuteInputResult::None;
#[cfg(not(feature = "introspection"))]
let is_solution = self
.objective_mut()
.is_interesting(state, manager, &input, observers, exit_kind)?;
#[cfg(feature = "introspection")]
let is_solution = self
.objective_mut()
.is_interesting_introspection(state, manager, &input, observers, exit_kind)?;
if is_solution {
res = ExecuteInputResult::Solution;
} else {
#[cfg(not(feature = "introspection"))]
let is_corpus = self
.feedback_mut()
.is_interesting(state, manager, &input, observers, exit_kind)?;
#[cfg(feature = "introspection")]
let is_corpus = self
.feedback_mut()
.is_interesting_introspection(state, manager, &input, observers, exit_kind)?;
if is_corpus {
res = ExecuteInputResult::Corpus;
}
}
match res {
ExecuteInputResult::None => {
self.feedback_mut().discard_metadata(state, &input)?;
self.objective_mut().discard_metadata(state, &input)?;
Ok((res, None))
}
ExecuteInputResult::Corpus => {
// Not a solution
self.objective_mut().discard_metadata(state, &input)?;
// Add the input to the main corpus
let mut testcase = Testcase::with_executions(input.clone(), *state.executions());
self.feedback_mut()
.append_metadata(state, observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?;
self.scheduler_mut().on_add(state, idx)?;
if send_events {
// TODO set None for fast targets
let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique {
None
} else {
Some(manager.serialize_observers::<OT>(observers)?)
};
manager.fire(
state,
Event::NewTestcase {
input,
observers_buf,
exit_kind: *exit_kind,
corpus_size: state.corpus().count(),
client_config: manager.configuration(),
time: current_time(),
executions: *state.executions(),
},
)?;
}
Ok((res, Some(idx)))
}
ExecuteInputResult::Solution => {
// Not interesting
self.feedback_mut().discard_metadata(state, &input)?;
// The input is a solution, add it to the respective corpus
let mut testcase = Testcase::with_executions(input, *state.executions());
self.objective_mut()
.append_metadata(state, observers, &mut testcase)?;
state.solutions_mut().add(testcase)?;
if send_events {
manager.fire(
state,
Event::Objective {
objective_size: state.solutions().count(),
},
)?;
}
Ok((res, None))
}
}
}
至此, fuzzer 完成了调度 testcase,执行 testcase,判断 testcase 是否是 solution 或者是 interesting,添加新的 corpus 和 crashes 的闭环。
LibAFL 内置了一些实现好的 mutator。在上面的 mutator 一节我们也列举出来了。下面介绍一下每个 mutator 具体的变异方式。
从 input 中随机选出一个字节,再随机选出一个比特,异或
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let bit = 1 << state.rand_mut().choose(0..8);
let byte = state.rand_mut().choose(input.bytes_mut());
*byte ^= bit;
Ok(MutationResult::Mutated)
}
}
从 input 中随机选出一个 byte,按位取反
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().is_empty() {
Ok(MutationResult::Skipped)
} else {
*state.rand_mut().choose(input.bytes_mut()) ^= 0xff;
Ok(MutationResult::Mutated)
}
}
从 input 中随机选出一个字节,加一
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let byte = state.rand_mut().choose(input.bytes_mut());
*byte = byte.wrapping_add(1);
Ok(MutationResult::Mutated)
}
}
从 input 中随机选出一个字节,减一
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let byte = state.rand_mut().choose(input.bytes_mut());
*byte = byte.wrapping_sub(1);
Ok(MutationResult::Mutated)
}
}
从 input 中随机选出一个字节,先按位取反,然后加1
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let byte = state.rand_mut().choose(input.bytes_mut());
*byte = (!(*byte)).wrapping_add(1);
Ok(MutationResult::Mutated)
}
}
从 input 中随机选出一个字节,然后使用一个 0-254 之间的随机值和它异或
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().is_empty() {
Ok(MutationResult::Skipped)
} else {
let byte = state.rand_mut().choose(input.bytes_mut());
*byte ^= 1 + state.rand_mut().below(254) as u8;
Ok(MutationResult::Mutated)
}
}
从 input 中随机选择一个目标大小的串 (Byte/Word/Dword/Qword),然后从下面四个操作里面随机选一个完成
- 加上一个随机值
- 减去一个随机值
- 交换大小端,加上一个随机值,交换大小端
- 交换大小端,减去一个随机值,交换大小端
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<$size>() {
Ok(MutationResult::Skipped)
} else {
// choose a random window of bytes (windows overlap) and convert to $size
let (index, bytes) = state
.rand_mut()
.choose(input.bytes().windows(size_of::<$size>()).enumerate());
let val = <$size>::from_ne_bytes(bytes.try_into().unwrap());
// mutate
let num = 1 + state.rand_mut().below(ARITH_MAX) as $size;
let new_val = match state.rand_mut().below(4) {
0 => val.wrapping_add(num),
1 => val.wrapping_sub(num),
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
};
// set bytes to mutated value
let new_bytes = &mut input.bytes_mut()[index..index + size_of::<$size>()];
new_bytes.copy_from_slice(&new_val.to_ne_bytes());
Ok(MutationResult::Mutated)
}
}
实现用到了宏,$size
表示串的类型,可能是 u8/u16/u3/u64
。这里 ARITH_MAX
是一个确定的值。
/// The max value that will be added or subtracted during add mutations
pub const ARITH_MAX: u64 = 35;
从 input 中随机选择一个目标大小的串(Byte/Word/Dword),然后随机使用一个 interesting 的值按大端序或者是小端序替换
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<$size>() {
Ok(MutationResult::Skipped)
} else {
let bytes = input.bytes_mut();
let upper_bound = (bytes.len() + 1 - size_of::<$size>()) as u64;
let idx = state.rand_mut().below(upper_bound) as usize;
let val = *state.rand_mut().choose(&$interesting) as $size;
let new_bytes = match state.rand_mut().choose(&[0, 1]) {
0 => val.to_be_bytes(),
_ => val.to_le_bytes(),
};
bytes[idx..idx + size_of::<$size>()].copy_from_slice(&new_bytes);
Ok(MutationResult::Mutated)
}
}
实现用到了宏,$size
表示串的类型,可能是 u8/u16/u32
。$interesting
表示 interesting 的值的数组
/// Interesting 8-bit values from AFL
pub const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127];
/// Interesting 16-bit values from AFL
pub const INTERESTING_16: [i16; 19] = [
-128, -1, 0, 1, 16, 32, 64, 100, 127, -32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767,
];
/// Interesting 32-bit values from AFL
pub const INTERESTING_32: [i32; 27] = [
-128,
-1,
0,
1,
16,
32,
64,
100,
127,
-32768,
-129,
128,
255,
256,
512,
1000,
1024,
4096,
32767,
-2147483648,
-100663046,
-32769,
32768,
65535,
65536,
100663045,
2147483647,
];
从 input 中删除随机长度的字节串
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
if size <= 2 {
return Ok(MutationResult::Skipped);
}
let range = rand_range(state, size, size);
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
input.bytes_mut().drain(range);
Ok(MutationResult::Mutated)
}
将 input 扩展 range 长度,然后从 range 的开始位置向前移动剩下的字节串,直到覆盖扩展的长度
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let max_size = state.max_size();
let size = input.bytes().len();
if size == 0 || size >= max_size {
return Ok(MutationResult::Skipped);
}
let mut range = rand_range(state, size, min(max_size - size, 16));
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
let new_size = range.len() + size;
let mut target = size;
core::mem::swap(&mut target, &mut range.end);
input.bytes_mut().resize(new_size, 0);
input.bytes_mut().copy_within(range, target);
Ok(MutationResult::Mutated)
}
有点复杂举个例子,最后 [2,3,4,5,6]
被向前移动 3 格,覆盖 [0,0,0]
input [0,1,2,3,4,5,6]
range [2,4]
resized input [0,1,2,3,4,5,6,0,0,0]
result [0,1,2,3,4,2,3,4,5,6]
向 input 中随机位置插入随机长度重复值的字节串,重复值来自 input 中的随机字节
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let max_size = state.max_size();
let size = input.bytes().len();
if size == 0 || size >= max_size {
return Ok(MutationResult::Skipped);
}
let amount = 1 + state.rand_mut().below(min(max_size - size, 16) as u64) as usize;
let offset = state.rand_mut().below(size as u64 + 1) as usize;
let val = input.bytes()[state.rand_mut().below(size as u64) as usize];
input
.bytes_mut()
.splice(offset..offset, core::iter::repeat(val).take(amount));
Ok(MutationResult::Mutated)
}
向 input 中随机位置插入随机长度重复值的字节串,和 BytesInsertMutator
不同,重复值是随机的
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let max_size = state.max_size();
let size = input.bytes().len();
if size >= max_size {
return Ok(MutationResult::Skipped);
}
let amount = 1 + state.rand_mut().below(min(max_size - size, 16) as u64) as usize;
let offset = state.rand_mut().below(size as u64 + 1) as usize;
let val = state.rand_mut().next() as u8;
input
.bytes_mut()
.splice(offset..offset, core::iter::repeat(val).take(amount));
Ok(MutationResult::Mutated)
}
从 input 中随机选择一个 range,替换为重复值的字节串,重复值来自 input
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
if size == 0 {
return Ok(MutationResult::Skipped);
}
let range = rand_range(state, size, min(size, 16));
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
let val = *state.rand_mut().choose(input.bytes());
let quantity = range.len();
input
.bytes_mut()
.splice(range, core::iter::repeat(val).take(quantity));
Ok(MutationResult::Mutated)
}
从 input 中随机选择一个 range,替换为重复值的字节串,和 BytesSetMutator
不同的是,重复值是随机生成的
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
if size == 0 {
return Ok(MutationResult::Skipped);
}
let range = rand_range(state, size, min(size, 16));
if range.is_empty() {
return Ok(MutationResult::Skipped);
}
let val = state.rand_mut().next() as u8;
let quantity = range.len();
input
.bytes_mut()
.splice(range, core::iter::repeat(val).take(quantity));
Ok(MutationResult::Mutated)
}
将 input 中的一段字节串拷贝到另一个位置
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
if size <= 1 {
return Ok(MutationResult::Skipped);
}
let target = state.rand_mut().below(size as u64) as usize;
let range = rand_range(state, size, size - target);
input.bytes_mut().copy_within(range, target);
Ok(MutationResult::Mutated)
}
从 input 中选出一个字节串,复制并且插入到 input 中
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
if size <= 1 || size == state.max_size() {
return Ok(MutationResult::Skipped);
}
let target = state.rand_mut().below(size as u64) as usize;
// make sure that the sampled range is both in bounds and of an acceptable size
let max_insert_len = min(size - target, state.max_size() - size);
let range = rand_range(state, size, max_insert_len);
self.tmp_buf.clear();
self.tmp_buf.extend(input.bytes()[range].iter().copied());
input
.bytes_mut()
.splice(target..target, self.tmp_buf.drain(..));
Ok(MutationResult::Mutated)
}
从 input 中选择两个不相交的字节串,交换
fn mutate(
&mut self,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
if size <= 1 {
return Ok(MutationResult::Skipped);
}
self.tmp_buf.clear();
let first = rand_range(state, size, size);
if state.rand_mut().next() & 1 == 0 && first.start != 0 {
let second = rand_range(state, first.start, first.start);
self.tmp_buf.extend(input.bytes_mut().drain(first.clone()));
self.tmp_buf
.extend(input.bytes()[second.clone()].iter().copied());
input
.bytes_mut()
.splice(first.start..first.start, self.tmp_buf.drain(first.len()..));
input.bytes_mut().splice(second, self.tmp_buf.drain(..));
Ok(MutationResult::Mutated)
} else if first.end != size {
let mut second = rand_range(state, size - first.end, size - first.end);
second.start += first.end;
second.end += first.end;
self.tmp_buf.extend(input.bytes_mut().drain(second.clone()));
self.tmp_buf
.extend(input.bytes()[first.clone()].iter().copied());
input.bytes_mut().splice(
second.start..second.start,
self.tmp_buf.drain(second.len()..),
);
input.bytes_mut().splice(first, self.tmp_buf.drain(..));
Ok(MutationResult::Mutated)
} else {
Ok(MutationResult::Skipped)
}
从 corpus 中随机选出一个字节串插入到 input 中
fn mutate(
&mut self,
state: &mut S,
input: &mut S::Input,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
let max_size = state.max_size();
if size >= max_size {
return Ok(MutationResult::Skipped);
}
// We don't want to use the testcase we're already using for splicing
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
if let Some(cur) = state.corpus().current() {
if idx == *cur {
return Ok(MutationResult::Skipped);
}
}
let other_size = state
.corpus()
.get(idx)?
.borrow_mut()
.load_input()?
.bytes()
.len();
if other_size < 2 {
return Ok(MutationResult::Skipped);
}
let range = rand_range(state, other_size, min(other_size, max_size - size));
let target = state.rand_mut().below(size as u64) as usize;
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
let other = other_testcase.load_input()?;
input
.bytes_mut()
.splice(target..target, other.bytes()[range].iter().copied());
Ok(MutationResult::Mutated)
}
从 corpus 中随机选择一个字节串替换 input 中的一个字节串
fn mutate(
&mut self,
state: &mut S,
input: &mut S::Input,
_stage_idx: i32,
) -> Result<MutationResult, Error> {
let size = input.bytes().len();
if size == 0 {
return Ok(MutationResult::Skipped);
}
// We don't want to use the testcase we're already using for splicing
let idx = random_corpus_id!(state.corpus(), state.rand_mut());
if let Some(cur) = state.corpus().current() {
if idx == *cur {
return Ok(MutationResult::Skipped);
}
}
let other_size = state
.corpus()
.get(idx)?
.borrow_mut()
.load_input()?
.bytes()
.len();
if other_size < 2 {
return Ok(MutationResult::Skipped);
}
let target = state.rand_mut().below(size as u64) as usize;
let range = rand_range(state, other_size, min(other_size, size - target));
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
let other = other_testcase.load_input()?;
input.bytes_mut().splice(
target..(target + range.len()),
other.bytes()[range].iter().copied(),
);
Ok(MutationResult::Mutated)
}