Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

cokeBeer/LibAFL-Learn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

7 Commits

Repository files navigation

LibAFL-Learn

一个中文版本的 LibAFL 笔记,主要内容是 LibAFL 原理相关的内容,同时也附加一些 LibAFL 使用方面的 tips ,方便查阅和参考。

关于LibAFL

LibAFL 是一个使用 rust 编写的 fuzz 库, 核心代码参考自著名的 fuzz 工具 AFL 以及其社区版本 AFL++ 。将 LibAFL 整合到你的项目中,可以快速获得可定制的 fuzz 能力 。

如何导入 LibAFL 作为依赖库

因为 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 的基本功能

LibAFL 提供了两个基本功能 (其他功能我暂时也没有用到,欢迎补充)

  • ForkServer Fuzz
  • InProcess Fuzz

第一个功能,ForkServer Fuzz, 和 AFL 中的 ForkServer Mode 类似,需要使用者自己对目标程序插桩,然后交给 fuzzer 测试即可。使用方法可以参考 forkserver_simple,可以看做对 AFL 经典功能的复刻。第二个功能,InProcess Fuzz, 不要求使用 afl-gcc 等工具对程序插桩,可以自己定义一个目标函数,并且对其进行 fuzz,可以自己提供覆盖率,crash 信息,灵活度很高,也是我主要使用的一个功能。使用方法可以参考 bady_fuzzer

InProcess Fuzz 的基本要素

创建并运行一个 InProcess Fuzz 可能用到以下要素

  • Observer:观察者
  • Harness:被 fuzz 的函数
  • Feedback:反馈
  • Objective:目标
  • State:状态
  • Monitor & Manager:监控&管理
  • Scheduler:调度器
  • Fuzzer:fuzzer
  • Mutator:变异器
  • Stage:阶段
  • Executor:执行器

我们一个一个介绍

入门

了解下面这些要素,你已经可以写一个实现自己目标的 fuzz 工具了。

Observer

观察者代表对一些量的观察,比如观察一个数组,观察一个 map,观察一块共享内存。使用下面的语句可以针对一块共享内存创建一个观察者。其中 StdMapObserver 是常用的观察者类型。它的构造函数中传入了一个由共享内存对象转化来的可变切片,表示 正在观察一块共享内存 。之后如果需要这块共享内存的信息,可以直接通过观察者获取。

// Create an observation channel using shared memory
let observer = unsafe { StdMapObserver::new("shared_memory", shmem.as_mut_slice()) };

Harness

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

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

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

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 & Manager

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

Scheduler 决定按何种顺序选取 corpus 来生成测试用例。例如一个常见的 scheduler 是 QueueScheduler, 它按照顺序从 corpus 中获取语料

let scheduler = QueueScheduler::new();

可以通过实现自己的 Scheduler 来决定选取语料的顺序

Fuzzer

Fuzzer 是对整个 fuzz 库的封装。使用下面的语句可以创建一个简单的 fuzzer

let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

可以通过 fuzzer 启动 fuzz

fuzzer.fuzz_loop()

Executor

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

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

Stage 是对 mutator 的进一步封装。Stage 从 corpus 中获取语料,利用 mutator 进行变异,然后交给 executor 。

Fuzz 流程分析

这里我们分析一下 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 的闭环。

Mutators 介绍

LibAFL 内置了一些实现好的 mutator。在上面的 mutator 一节我们也列举出来了。下面介绍一下每个 mutator 具体的变异方式。

BitFlipMutator

从 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)
 }
}

ByteFlipMutator

从 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)
 }
}

ByteIncMutator

从 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)
 }
}

BytesDecMutator

从 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)
 }
}

ByteNegMutator

从 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)
 }
}

ByteRandMutator

从 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)
 }
}

Byte/Word/Dword/Qword AddMutator

从 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;

Byte/Word/Dword InterestingMutator

从 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,
];

BytesDeleteMutator

从 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)
}

BytesExpandMutator

将 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]

BytesInsertMutator

向 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)
}

BytesRandInsertMutator

向 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)
}

BytesSetMutator

从 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)
}

BytesRandSetMutator

从 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)
}

BytesCopyMutator

将 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)
}

BytesInsertCopyMutator

从 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)
}

BytesSwapMutator

从 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)
 }

CrossoverInsertMutator

从 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)
}

CrossoverReplaceMutator

从 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)
 }

About

一个中文版本的 LibAFL 笔记,主要内容是 LibAFL 原理相关的内容,同时也附加一些 LibAFL 使用方面的 tips ,方便查阅和参考。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

AltStyle によって変換されたページ (->オリジナル) /