LibAFL的安装及基本使用

news/2024/3/29 17:34:06/文章来源:https://blog.csdn.net/u013648063/article/details/129270024

本教程安装LibAFL使用的是Ubuntu 22.04 操作系统

1. 安装

1.1 Rust 安装

Rust的安装,参照Rust官网:https://www.rust-lang.org/tools/install

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

1.2 LLVM安装

直接apt安装,安装的应该是LLVM 14,LibAFL说是在LLVM 11-15之间就行。

sudo apt update
sudo apt-get install llvm clang

1.3 LibAFL安装

cargo install cargo-make
git clone https://github.com/AFLplusplus/LibAFL
cd LibAFL
cargo build --release

自此安装完毕。

2. 基本使用

现在来使用这个LibAFL已经写好的模糊测试器(libfuzzer)来测试libpng。主要参考官方的这个教程:https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/libfuzzer_libpng

这个模糊测试器在LibAFL/fuzzers/libfuzzer_libpng目录下,先把他build起来。

cd fuzzers/libfuzzer_libpng
cargo build --release

这个操作会生成两个编译器(libafl_cc和libafl_cxx)的wrapper,需要使用他们来编译程序。他们会出现在target/release的文件夹下。

然后下载libpng,并解压

wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz

然后使用libafl_cc编译器来编译libpng,

cd libpng-1.6.37
./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
make CC="$(pwd)/../target/release/libafl_cc" CXX="$(pwd)/../target/release/libafl_cxx" -j `nproc`

然后可以发现编译后的静态库在这个目录下libpng-1.6.37/.libs/libpng16.a

因为我们测试的是libpng,它是一个库,所以还需要编译一个harness,来调用libpng的库。harness.cc位于fuzzers/libfuzzer_libpng下。

./target/release/libafl_cxx ./harness.cc libpng-1.6.37/.libs/libpng16.a -I libpng-1.6.37/ -o fuzzer_libpng -lz -lm

开始测试,先在一个终端运行下面的程序,它会开启一个tcp端口(1337),等待fuzzer 客户端连接,这个端口是本地的,目的只是用来初始化的握手。后续的通信是通过shared map。目前需要在libfuzzer_libpng的目录下运行,才可以访问到libpng的语料库。

./fuzzer_libpng

然后在另外开启另外一个终端,运行下面命令

./fuzzer_libpng

再切回到原来的终端,会发现开始跑模糊测试了。

这是第一个终端的界面,需要在另外一个终端执行./fuzzer_libpng才会出现下面的情况

在这里插入图片描述

另一个终端的界面

在这里插入图片描述

3. libfuzz_libpng是如何构造的

进入src目录下,会发现有lib.rs和bin目录,bin目录存放的是编译器wrapper的代码,也就是负责插桩的代码。lib.rs是构建fuzzer的代码。

3.1 libafl_cc.rs

简单来看就是个clang的包装器,加了个-fsanitize-coverage=trace-pc-guard选项。

下面是chatgpt对这部分代码的解释,感觉说的没啥问题。

这是一个Rust语言编写的程序,主要目的是作为一个编译器的包装器(wrapper)来调用Clang编译器,并在编译时链接静态库并进行覆盖率分析。
程序接受命令行参数作为输入,然后根据参数执行不同的操作。如果命令行参数的数量少于2,则程序会抛出一个panic异常。否则,程序会尝试解析命令行参数并使用Clang编译器进行编译。如果编译成功,则程序以编译器的返回代码(exit code)退出,否则程序也会抛出一个panic异常。
具体来说,程序首先使用Rust标准库中的env模块获取命令行参数,并检查是否至少传入了一个参数。接下来,程序通过调用ClangWrapper::new()方法创建一个ClangWrapper对象,然后根据包装器(wrapper)的名称来判断要使用C++编译器还是C编译器。如果包装器的名称以"cc"结尾,则使用C编译器,否则如果名称以"++"、"pp"或"xx"结尾,则使用C++编译器。如果无法确定应该使用哪种编译器,则程序会抛出一个panic异常。
然后,程序使用ClangWrapper对象的方法来添加链接静态库、设置覆盖率分析等编译选项,并运行编译器进行编译。如果编译器成功完成编译,则程序使用编译器的返回代码(exit code)退出。
总之,这个程序主要是作为一个包装器(wrapper)来调用Clang编译器,以便在编译时添加一些额外的选项。在这种情况下,它被用于编译fuzz测试。

use std::env;use libafl_cc::{ClangWrapper, CompilerWrapper};pub fn main() {let args: Vec<String> = env::args().collect();if args.len() > 1 {let mut dir = env::current_exe().unwrap();let wrapper_name = dir.file_name().unwrap().to_str().unwrap();let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {"cc" => false,"++" | "pp" | "xx" => true,_ => panic!("Could not figure out if c or c++ wrapper was called. Expected {dir:?} to end with c or cxx"),};dir.pop();let mut cc = ClangWrapper::new();if let Some(code) = cc.cpp(is_cpp)// silence the compiler wrapper output, needed for some configure scripts..silence(true).parse_args(&args).expect("Failed to parse the command line").link_staticlib(&dir, "libfuzzer_libpng").add_arg("-fsanitize-coverage=trace-pc-guard").run().expect("Failed to run the wrapped compiler"){std::process::exit(code);}} else {panic!("LibAFL CC: No Arguments given");}
}

3.2 lib.rs

lib.rs代码有点多,分段来看,首先导入库的部分,继承了LibAFL里很多有用的组件。

//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;use core::time::Duration;
#[cfg(feature = "crash")]
use std::ptr;
use std::{env, path::PathBuf};use libafl::{bolts::{current_nanos,rands::StdRand,tuples::{tuple_list, Merge},AsSlice,},corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},events::{setup_restarting_mgr_std, EventConfig, EventRestarter},executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},feedback_or, feedback_or_fast,feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},fuzzer::{Fuzzer, StdFuzzer},inputs::{BytesInput, HasTargetBytes},monitors::MultiMonitor,mutators::{scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},token_mutations::Tokens,},observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},schedulers::{powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,},stages::{calibrate::CalibrationStage, power::StdPowerMutationalStage},state::{HasCorpus, HasMetadata, StdState},Error,
};
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};

再看下主函数,主要是调用fuzz函数,传入了三个参数,分别是语料库的路径、崩溃文件目录以及随机种子。

pub fn libafl_main() {// Registry the metadata types used in this fuzzer// Needed only on no_std//RegistryBuilder::register::<Tokens>();println!("Workdir: {:?}",env::current_dir().unwrap().to_string_lossy().to_string());fuzz(&[PathBuf::from("./corpus")],PathBuf::from("./crashes"),1337,).expect("An error occurred while fuzzing");
}

fuzz函数中,首先创建了MultiMonitor来打印调试信息。

let monitor = MultiMonitor::new(|s| println!("{s}"));

RestartingManager让目标程序在模糊测试过程中崩溃时重新启动程序。

 let (state, mut restarting_mgr) =match setup_restarting_mgr_std(monitor, broker_port, EventConfig::AlwaysUnique) {Ok(res) => res,Err(err) => match err {Error::ShuttingDown => {return Ok(());}_ => {panic!("Failed to setup the restarter: {err}");}},};

edges_observer使用覆盖率映射表来观察程序的执行情况

  let edges_observer = unsafe {HitcountsMapObserver::new(StdMapObserver::from_mut_ptr("edges",EDGES_MAP.as_mut_ptr(),MAX_EDGES_NUM,))};

判断输入是否有趣。主要是基于覆盖率和执行的时间来进行判断。

    let time_observer = TimeObserver::new("time");let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false);let calibration = CalibrationStage::new(&map_feedback);let mut feedback = feedback_or!(// New maximization map feedback linked to the edges observer and the feedback statemap_feedback,// Time feedback, this one does not need a feedback stateTimeFeedback::with_observer(&time_observer));

判断输入是否是最终想要的,即是不是PoC。

let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());

如果重启失败了,需要重新创建状态。

  let mut state = state.unwrap_or_else(|| {StdState::new(// RNGStdRand::with_seed(current_nanos()),// Corpus that will be evolved, we keep it in memory for performanceInMemoryCorpus::new(),// Corpus in which we store solutions (crashes in this example),// on disk so the user can get them after stopping the fuzzerOnDiskCorpus::new(objective_dir).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,).unwrap()});

创建png字典。主要是libpng需要合法的png图片来作为输入。

if state.metadata().get::<Tokens>().is_none() {state.add_metadata(Tokens::from([vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header"IHDR".as_bytes().to_vec(),"IDAT".as_bytes().to_vec(),"PLTE".as_bytes().to_vec(),"IEND".as_bytes().to_vec(),]));}

构造一个具有多阶段的变异器。

let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));let power = StdPowerMutationalStage::new(mutator);let mut stages = tuple_list!(calibration, power);

从语料库获取种子的调度器(种子调度)

let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule(&mut state,&edges_observer,Some(PowerSchedule::FAST),));

把前面的组件组装为1个fuzzer

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

构造harness的wrapper,不太理解这段代码,推测是libfuzzer的特性所以需要这么一段。

  let mut harness = |input: &BytesInput| {let target = input.target_bytes();let buf = target.as_slice();#[cfg(feature = "crash")]if buf.len() > 4 && buf[4] == 0 {unsafe {eprintln!("Crashing (for testing purposes)");let addr = ptr::null_mut();*addr = 1;}}libfuzzer_test_one_input(buf);ExitKind::Ok};

构建一个超时的执行器,也就是在给定的时间内执行程序。

 let mut executor = TimeoutExecutor::new(InProcessExecutor::new(&mut harness,tuple_list!(edges_observer, time_observer),&mut fuzzer,&mut state,&mut restarting_mgr,)?,// 10 seconds timeoutDuration::new(10, 0),);// The actual target run starts here.// Call LLVMFUzzerInitialize() if present.let args: Vec<String> = env::args().collect();if libfuzzer_initialize(&args) == -1 {println!("Warning: LLVMFuzzerInitialize failed with -1");}

处理下初始语料库为空的情况

   // In case the corpus is empty (on first run), resetif state.must_load_initial_inputs() {state.load_initial_inputs(&mut fuzzer, &mut executor, &mut restarting_mgr, corpus_dirs).unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", &corpus_dirs));println!("We imported {} inputs from disk.", state.corpus().count());}

迭代执行

 let iters = 1_000_000;fuzzer.fuzz_loop_for(&mut stages,&mut executor,&mut state,&mut restarting_mgr,iters,)?;

总的来说有点像搭积木的感觉,但是目前对每个积木怎么搭的还不是很了解,后续再看看别的fuzzer是怎么实现的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_75504.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

表格形式的Sarsa与Q_learning算法

环境如下&#xff1a; 这是一个简单的环境&#xff0c;绿色方块代表终点&#xff0c;白色方块代表可行点&#xff0c;灰色方块代表陷阱 用Sarsa算法和Q_learning算法训练得到value表格 代码如下&#xff1a; (jupyter notebook上的代码&#xff0c;所以顺序看起来有点儿奇怪) …

Java8 新特性强大的Stream API

一、Stream API 说明 Java8中有两大最为重要的改变。第一个是 Lambda 表达式&#xff1b;另外一个则是 Stream API。 Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充&#xff0c;因为Stream API可以极大提供Ja…

【博学谷学习记录】超强总结,用心分享丨人工智能 特征工程 特征变换 分箱学习总结

目录概念分箱的作用等频分箱等距分箱*卡方分箱公式例子概念 特征构造的过程中&#xff0c;对特征做分箱处理时必不可少的过程分箱就是将连续变量离散化&#xff0c;合并成较少的状态 分箱的作用 离散特征的增加和减少都很容易&#xff0c;易于模型的快速迭代&#xff1b;稀疏…

基于自定义训练函数的BP神经网络回归分析

目录 背影 BP神经网络的原理 BP神经网络的定义 BP神经网络的神经元 BP神经网络的激活函数 BP神经网络的传递函数 基于自定义训练函数的BP神经网络回归分析 背影 BP神经网络是一种成熟的神经网络&#xff0c;拥有很多训练函数&#xff0c;传递函数&#xff0c;激活函数&#x…

数学小课堂:无穷小(用动态和极限的眼光看世界)

文章目录 引言I 极限1.1 柯西对极限的认知1.2 极限准确的定义1.3 数列极限的定义1.4 函数极限的定义1.5 无穷小(特殊的极限)1.6 定量和逆向思维1.7 认知升级的过程引言 身处于渐变世界的人类,难以理解瞬间突变。 老师的作用,就是用大白话,把数学语言所写的知识,翻译成大…

腾讯安全与锐捷网络战略合作,威胁情报能力“被集成”

2月28日&#xff0c;腾讯安全和锐捷网络在北京联合举办“威胁情报”战略合作发布会。双方发布了一款集成了腾讯安全威胁情报的新一代防火墙&#xff0c;并举办战略合作签约仪式。会上&#xff0c;锐捷网络安全产品事业部总经理项小升、腾讯安全总经理陈龙代表双方签署战略合作协…

Python可视化界面编程入门

Python可视化界面编程入门具体实现代码如所示&#xff1a; &#xff08;1&#xff09;普通可视化界面编程代码入门&#xff1a; import sys from PyQt5.QtWidgets import QWidget,QApplication #导入两个类来进行程序界面编程if __name__"__main__":#创建一个Appl…

k8s学习之路 | Day17 k8s 工作负载

文章目录工作负载的定义工作负载资源分类工作负载的定义 官方参考链接&#xff1a;https://kubernetes.io/docs/concepts/workloads/ A workload is an application running on Kubernetes. Whether your workload is a single component or several that work together, on K…

《C++ Primer Plus》(第6版)第6章编程练习

《C Primer Plus》&#xff08;第6版&#xff09;第6章编程练习《C Primer Plus》&#xff08;第6版&#xff09;第6章编程练习1. 大小写转换2. 平均值3. 菜单4. 成员5. 收入所得税6. 捐款7. 统计单词8. 统计文件字符数9. 重写编程练习6《C Primer Plus》&#xff08;第6版&…

创建对象的方式和对属性的操作

javaScript支持多种编程范式&#xff0c;包括函数式编程和面向对象编程&#xff0c;javaScript的对象被设计成一组属性的无序集合&#xff0c;由key和value组成。 创建对象的两种方式 早期使用创建对象方式最多的是使用Object类&#xff0c;使用new关键字来创建一个对象&…

docker-compose安装kafka和php简单测试

docker-compose.yml内容&#xff1a; version: 3.1 services: zookeeper: container_name: zookeeper image: zookeeper:3.6 ports: - 2181:2181 kafka: image: wurstmeister/kafka container_name: kafka depends_on: - zookeeper …

解决Spring Data Jpa 实体类自动创建数据库表失败问题

先说一下我遇到的这个问题&#xff0c;首先我是通过maven创建了一个spring boot的工程&#xff0c;引入了Spring data jpa&#xff0c;结果实体类创建好之后&#xff0c;运行工程却没有在数据库中自动创建数据表。 找了半天发现是一个配置的问题! hibernate.ddl-auto节点的配…

【Python实战】激情澎湃,2023极品劲爆舞曲震撼全场,爬虫一键采集DJ大串烧,一曲醉人女声DJ舞曲,人人都听醉~(排行榜采集,妙啊~)

导语 哈喽&#xff01;大家好。我是木木子吖~今天给大家带来爬虫的内容哈。 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 今天教大家Python爬虫实战一键采集大家喜欢的DJ舞曲哦&#xff01; …

01-Oracle入门基础知识讲解

本章内容主要是讲解Oracle基础知识&#xff0c;安装完Oracle后第一次使用所必须了解的一些常用软件及命令&#xff0c;Oracle的体系结构等知识。 一、进入SQL Plus客户端软件 1.进入SQLPLUS客户端windows界面 2.进入DOS窗口界面 普通用户登录&#xff1a;conn 用户名称/密码 …

taobao.user.avatar.get

&#xffe5;开放平台基础API不需用户授权 根据混淆nick查询用户头像 公共参数 请求地址: HTTP地址 http://gw.api.taobao.com/router/rest 公共请求参数: 公共响应参数: 点击获取key和secret 请求参数 请求示例 TaobaoClient client new DefaultTaobaoClient(url, appkey,…

实现RecyclerView二级列表

自定义RecyclerView的adapter实现二级列表 图片大于5MB&#xff0c;CSDN不让上传&#xff0c;使用github链接&#xff0c;如果看不到请使用科学上网 https://github.com/nanjolnoSat/PersonalProject/blob/recyclerexpandableadapter/Recyclerexpanableadapter/pic/pic1.gif 源…

Kotlin学习:5.2、异步数据流 Flow

Flow一、Flow1、Flow是什么东西&#xff1f;2、实现功能3、特点4、冷流和热流5、流的连续性6、流的构建器7、流的上下文8、指定流所在协程9、流的取消9.1、超时取消9.2、主动取消9.3、密集型任务的取消10、背压和优化10.1、buffer 操作符10.2、 flowOn10.3、conflate 操作符10.…

同为(TOWE)防雷产品助力福建移动南平分公司防雷改造

01 公司简介中国移动通信集团福建有限公司南平分公司属于福建移动地级分公司&#xff0c;所属行业为电信、广播电视和卫星传输服务。现已建成覆盖范围广、业务品种多、通信质量高的综合通信网络&#xff0c;具备行业领先的经营管理制度。移动通信大楼的综合防雷及地接系统&…

Fedora系统安装KubeVela

话不多说直接看命令 Docker安装 Vela安装需要先安装Docker sudo yum -y install docker只需这行命令便可以自动添加 yum和dnf理论上都能成功&#xff0c;但是很看网速&#xff0c;&#xff0c;&#xff0c;实践证明yum是最好的。 如果发生报错mirrors trieds大概率就是网速超…

Kubernetes06:Controller (Deployment无状态应用)

Kubernetes06:Controller 1、什么是controller 管理和运行容器的对象&#xff0c;是一个物理概念 在集群上管理和运行容器的对象 2、Pod和Controller之间的关系 Pod是通过controller来实现应用的运维 比如伸缩、滚动升级等等操作Pod和Controller之间通过 label 标签建立关系…