Frida for Windows (#287)
* harness.cc for win * no backtrace for frida_gum * build.rs message * cfg guards * at least libafl_frida builds with cfg guards * fuzzer.rs builds on win * clean up * build instructions * ps * fix * clang * fix * article * static option to make it run on powershell * vscode build instructions * dllexport! * fix * build.rs * fix & fmt * message * msys not necessary anymore * Update README.md Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
parent
5a246175cf
commit
f63b862160
@ -19,11 +19,18 @@ debug = true
|
|||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
num_cpus = "1.0"
|
num_cpus = "1.0"
|
||||||
which = "4.1"
|
which = "4.1"
|
||||||
|
xz = "0.1.0"
|
||||||
|
flate2 = "1.0.22"
|
||||||
|
tar = "0.4.37"
|
||||||
|
reqwest = { version = "0.11.4", features = ["blocking"] }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]}
|
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]}
|
||||||
capstone = "0.8.0"
|
capstone = "0.8.0"
|
||||||
frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] }
|
frida-gum = { version = "0.5.2", features = [ "auto-download", "event-sink", "invocation-listener"] }
|
||||||
libafl_frida = { path = "../../libafl_frida", version = "0.6.1", features = ["cmplog"] }
|
libafl_frida = { path = "../../libafl_frida", version = "0.6.1", features = ["cmplog"] }
|
||||||
libafl_targets = { path = "../../libafl_targets", version = "0.6.1" , features = ["sancov_cmplog"] }
|
libafl_targets = { path = "../../libafl_targets", version = "0.6.1" , features = ["sancov_cmplog"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
@ -27,4 +27,74 @@ This means running --cores each client will start itself again to listen for cra
|
|||||||
By restarting the actual fuzzer, it can recover from these exit conditions.
|
By restarting the actual fuzzer, it can recover from these exit conditions.
|
||||||
|
|
||||||
After building the libpng-harness, too, you can run `find . -name libpng-harness.so` to find the location of your harness, then run
|
After building the libpng-harness, too, you can run `find . -name libpng-harness.so` to find the location of your harness, then run
|
||||||
`./target/release/frida_libpng ./libpng-harness.so LLVMFuzzerTestOneInput ./libpng-harness.so --cores=0`
|
`./target/release/frida_libpng ./libpng-harness.so LLVMFuzzerTestOneInput ./libpng-harness.so --cores=0`
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
You can also fuzz libpng-1.6.37 on windows with frida mode!
|
||||||
|
|
||||||
|
### To build it with visual studio
|
||||||
|
1. Install clang for windows (make sure you add LLVM to the system path!)
|
||||||
|
[https://github.com/llvm/llvm-project/releases/tag/llvmorg-12.0.1](https://github.com/llvm/llvm-project/releases/tag/llvmorg-12.0.1)
|
||||||
|
2. Build libpng1.6.37
|
||||||
|
- Open libpng-1.6.37/projects/vstudio/vstudio.sln
|
||||||
|
- Open Build->Configuration Manager
|
||||||
|
- select Release for Active soltuion configuration and
|
||||||
|
- select <New>->x64 for Active solution platform (Copy settings from Win32)
|
||||||
|
- Then for libpng, pngstest, pngtest, pngunknown, pngvalid, zlib in Solution Explorer, choose General -> Configuration Type -> Static library(.lib)
|
||||||
|
- C/C++ -> Treat Warnings As Errors -> No
|
||||||
|
- C/C++ -> Code Generation -> Runtime Library -> Multi-threaded (/MT)
|
||||||
|
- Finally you can build libpng-1.6.37
|
||||||
|
3. Compile the harness
|
||||||
|
Fire up a powershell at this directory.
|
||||||
|
```
|
||||||
|
cp .\libpng-1.6.37\projects\vstudio\x64\Release\libpng16.lib .
|
||||||
|
cp .\libpng-1.6.37\projects\vstudio\x64\Release\zlib.lib .
|
||||||
|
cp .\target\release\frida_libpng.exe .
|
||||||
|
clang++ -O3 -c -I.\libpng-1.6.37 .\harness.cc -o .\harness.o
|
||||||
|
clang++ -L.\zlib.dll .\harness.o .\libpng16.lib -lzlib -shared -o .\libpng-harness.dll
|
||||||
|
```
|
||||||
|
4. Run the fuzzer
|
||||||
|
```
|
||||||
|
./frida_libpng.exe ./libpng-harness.dll LLVMFuzzerTestOneInput ./libpng-harness.dll --cores=0
|
||||||
|
```
|
||||||
|
|
||||||
|
### To build it with msys2
|
||||||
|
1. Install and setup msys2 (https://www.msys2.org/)
|
||||||
|
2. (Optional) If you prefer to compile libpng with clang, you can install it and its dependecy with
|
||||||
|
```
|
||||||
|
pacman -S mingw-w64-x86_64-clang
|
||||||
|
pacman -S mingw-w64-clang-x86_64-zlib
|
||||||
|
```
|
||||||
|
and
|
||||||
|
```
|
||||||
|
export LDFLAGS='-L/clang64/lib'
|
||||||
|
export CPPFLAGS='-I/clang64/include'
|
||||||
|
export CC=clang
|
||||||
|
export CXX=clang++
|
||||||
|
```
|
||||||
|
3. Compile frida_libpng (possibly from your powershell)
|
||||||
|
```
|
||||||
|
cargo build --release
|
||||||
|
cp ./target/release/frida_libpng.exe .
|
||||||
|
```
|
||||||
|
4. Compile libpng-1.6.37 with the following commands
|
||||||
|
```
|
||||||
|
cd libpng-1.6.37
|
||||||
|
./configure --enable-hardware-optimizations=yes --with-pic=yes
|
||||||
|
make
|
||||||
|
cd ..
|
||||||
|
```
|
||||||
|
5. Compile the harness with gcc or clang++
|
||||||
|
```
|
||||||
|
g++ -O3 -c -I./libpng-1.6.37 -fPIC harness.cc -o harness.o
|
||||||
|
g++ -O3 harness.o ./libpng-1.6.37/.libs/libpng16.a -static -shared -lz -o libpng-harness.dll
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
clang++ -O3 -c -I./libpng-1.6.37 -fPIC harness.cc -o harness.o
|
||||||
|
clang++ -O3 harness.o ./libpng-1.6.37/.libs/libpng16.a -static -shared -lz -o libpng-harness.dll
|
||||||
|
```
|
||||||
|
6. Run the fuzzer
|
||||||
|
```
|
||||||
|
./frida_libpng.exe ./libpng-harness.dll LLVMFuzzerTestOneInput ./libpng-harness.dll --cores=0
|
||||||
|
```
|
||||||
|
@ -2,14 +2,21 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
|
fs::{rename, File},
|
||||||
|
io,
|
||||||
path::Path,
|
path::Path,
|
||||||
process::{exit, Command},
|
process::{exit, Command},
|
||||||
};
|
};
|
||||||
|
|
||||||
use which::which;
|
use which::which;
|
||||||
|
|
||||||
|
use flate2::read::GzDecoder;
|
||||||
|
use tar::Archive;
|
||||||
|
use xz::read::XzDecoder;
|
||||||
|
|
||||||
const LIBPNG_URL: &str =
|
const LIBPNG_URL: &str =
|
||||||
"https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz";
|
"https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz";
|
||||||
|
const ZLIB_URL: &str = "https://zlib.net/zlib-1.2.11.tar.gz";
|
||||||
|
|
||||||
fn build_dep_check(tools: &[&str]) {
|
fn build_dep_check(tools: &[&str]) {
|
||||||
for tool in tools {
|
for tool in tools {
|
||||||
@ -26,112 +33,156 @@ fn build_dep_check(tools: &[&str]) {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
println!("cargo:warning=Skipping libpng frida example on Windows");
|
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
||||||
exit(0);
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
}
|
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||||
|
println!("cargo:rerun-if-changed=harness.cc");
|
||||||
|
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let libpng = format!("{}/libpng-1.6.37", &cwd);
|
||||||
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
let libpng_path = Path::new(&libpng);
|
||||||
let out_dir = out_dir.to_string_lossy().to_string();
|
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
||||||
let out_dir_path = Path::new(&out_dir);
|
|
||||||
std::fs::create_dir_all(&out_dir).unwrap_or_else(|_| panic!("Failed to create {}", &out_dir));
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
let zlib = format!("{}/zlib", &cwd);
|
||||||
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
let zlib_1_2_11 = format!("{}/zlib-1.2.11", &cwd);
|
||||||
println!("cargo:rerun-if-changed=harness.cc");
|
let zlib_path = Path::new(&zlib);
|
||||||
|
let zlib_tar = format!("{}/zlib-1.2.11.tar.gz", &cwd);
|
||||||
|
|
||||||
build_dep_check(&["clang", "clang++", "wget", "tar", "make"]);
|
if !libpng_path.is_dir() {
|
||||||
|
if !Path::new(&libpng_tar).is_file() {
|
||||||
|
println!("cargo:warning=Libpng not found, downloading...");
|
||||||
|
// Download libpng
|
||||||
|
let mut resp = reqwest::blocking::get(LIBPNG_URL).expect("Libpng download failed");
|
||||||
|
let mut out = File::create(&libpng_tar).expect("Libpng download failed");
|
||||||
|
io::copy(&mut resp, &mut out).expect("Libpng downlaod failed");
|
||||||
|
|
||||||
let libpng = format!("{}/libpng-1.6.37", &out_dir);
|
let tar_xz = File::open(&libpng_tar).expect("Libpng extraction failed");
|
||||||
let libpng_path = Path::new(&libpng);
|
let tar = XzDecoder::new(tar_xz);
|
||||||
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
let mut archive = Archive::new(tar);
|
||||||
|
archive.unpack(&cwd).expect("Libpng extraction failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !zlib_path.is_dir() {
|
||||||
|
if !Path::new(&zlib_tar).is_file() {
|
||||||
|
println!("cargo:warning=Zlib not found, downloading...");
|
||||||
|
// Download Zlib
|
||||||
|
let mut resp = reqwest::blocking::get(ZLIB_URL).expect("Zlib download failed");
|
||||||
|
let mut out = File::create(&zlib_tar).expect("Zlib download failed");
|
||||||
|
io::copy(&mut resp, &mut out).expect("Zlib downlaod failed");
|
||||||
|
|
||||||
// Enforce clang for its -fsanitize-coverage support.
|
let tar_gz = File::open(&zlib_tar).expect("Zlib extraction failed");
|
||||||
let clang = match env::var("CLANG_PATH") {
|
let tar = GzDecoder::new(tar_gz);
|
||||||
Ok(path) => path,
|
let mut archive = Archive::new(tar);
|
||||||
Err(_) => "clang".to_string(),
|
archive.unpack(&cwd).expect("Zlib extraction failed");
|
||||||
};
|
rename(zlib_1_2_11, zlib).expect("Zlib extraction failed");
|
||||||
let clangpp = format!("{}++", &clang);
|
}
|
||||||
std::env::set_var("CC", &clang);
|
}
|
||||||
std::env::set_var("CXX", &clangpp);
|
|
||||||
let ldflags = match env::var("LDFLAGS") {
|
|
||||||
Ok(val) => val,
|
|
||||||
Err(_) => "".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// println!("cargo:warning=output path is {}", libpng);
|
println!("cargo:warning=Now compile libpng with either visual studio or msys2");
|
||||||
if !libpng_path.is_dir() {
|
} else {
|
||||||
if !Path::new(&libpng_tar).is_file() {
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
println!("cargo:warning=Libpng not found, downloading...");
|
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
||||||
// Download libpng
|
let out_dir = out_dir.to_string_lossy().to_string();
|
||||||
Command::new("wget")
|
let out_dir_path = Path::new(&out_dir);
|
||||||
.arg("-c")
|
std::fs::create_dir_all(&out_dir)
|
||||||
.arg(LIBPNG_URL)
|
.unwrap_or_else(|_| panic!("Failed to create {}", &out_dir));
|
||||||
.arg("-O")
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||||
|
println!("cargo:rerun-if-changed=harness.cc");
|
||||||
|
|
||||||
|
build_dep_check(&["clang", "clang++", "wget", "tar", "make"]);
|
||||||
|
|
||||||
|
let libpng = format!("{}/libpng-1.6.37", &out_dir);
|
||||||
|
let libpng_path = Path::new(&libpng);
|
||||||
|
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
||||||
|
|
||||||
|
// Enforce clang for its -fsanitize-coverage support.
|
||||||
|
let clang = match env::var("CLANG_PATH") {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(_) => "clang".to_string(),
|
||||||
|
};
|
||||||
|
let clangpp = format!("{}++", &clang);
|
||||||
|
std::env::set_var("CC", &clang);
|
||||||
|
std::env::set_var("CXX", &clangpp);
|
||||||
|
let ldflags = match env::var("LDFLAGS") {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// println!("cargo:warning=output path is {}", libpng);
|
||||||
|
if !libpng_path.is_dir() {
|
||||||
|
if !Path::new(&libpng_tar).is_file() {
|
||||||
|
println!("cargo:warning=Libpng not found, downloading...");
|
||||||
|
// Download libpng
|
||||||
|
Command::new("wget")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(LIBPNG_URL)
|
||||||
|
.arg("-O")
|
||||||
|
.arg(&libpng_tar)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
Command::new("tar")
|
||||||
|
.current_dir(&out_dir_path)
|
||||||
|
.arg("xvf")
|
||||||
.arg(&libpng_tar)
|
.arg(&libpng_tar)
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
Command::new(format!("{}/configure", &libpng))
|
||||||
|
.current_dir(&libpng_path)
|
||||||
|
.args(&[
|
||||||
|
"--disable-shared",
|
||||||
|
&format!("--host={}", env::var("TARGET").unwrap())[..],
|
||||||
|
])
|
||||||
|
.env("CC", &clang)
|
||||||
|
.env("CXX", &clangpp)
|
||||||
|
.env(
|
||||||
|
"CFLAGS",
|
||||||
|
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
||||||
|
)
|
||||||
|
.env(
|
||||||
|
"CXXFLAGS",
|
||||||
|
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
||||||
|
)
|
||||||
|
.env(
|
||||||
|
"LDFLAGS",
|
||||||
|
//format!("-g -fPIE -fsanitize=address {}", ldflags),
|
||||||
|
format!("-g -fPIE {}", ldflags),
|
||||||
|
)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
Command::new("make")
|
||||||
|
.current_dir(&libpng_path)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
Command::new("tar")
|
|
||||||
.current_dir(&out_dir_path)
|
|
||||||
.arg("xvf")
|
|
||||||
.arg(&libpng_tar)
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
Command::new(format!("{}/configure", &libpng))
|
|
||||||
.current_dir(&libpng_path)
|
|
||||||
.args(&[
|
|
||||||
"--disable-shared",
|
|
||||||
&format!("--host={}", env::var("TARGET").unwrap())[..],
|
|
||||||
])
|
|
||||||
.env("CC", &clang)
|
|
||||||
.env("CXX", &clangpp)
|
|
||||||
.env(
|
|
||||||
"CFLAGS",
|
|
||||||
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
|
||||||
)
|
|
||||||
.env(
|
|
||||||
"CXXFLAGS",
|
|
||||||
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
|
||||||
)
|
|
||||||
.env(
|
|
||||||
"LDFLAGS",
|
|
||||||
//format!("-g -fPIE -fsanitize=address {}", ldflags),
|
|
||||||
format!("-g -fPIE {}", ldflags),
|
|
||||||
)
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
Command::new("make")
|
|
||||||
.current_dir(&libpng_path)
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let status = cc::Build::new()
|
let status = cc::Build::new()
|
||||||
.cpp(true)
|
.cpp(true)
|
||||||
.get_compiler()
|
.get_compiler()
|
||||||
.to_command()
|
.to_command()
|
||||||
.current_dir(&cwd)
|
.current_dir(&cwd)
|
||||||
.arg("-I")
|
.arg("-I")
|
||||||
.arg(&libpng)
|
.arg(&libpng)
|
||||||
//.arg("-D")
|
//.arg("-D")
|
||||||
//.arg("HAS_DUMMY_CRASH=1")
|
//.arg("HAS_DUMMY_CRASH=1")
|
||||||
.arg("-fPIC")
|
.arg("-fPIC")
|
||||||
.arg("-shared")
|
.arg("-shared")
|
||||||
.arg("-O3")
|
.arg("-O3")
|
||||||
//.arg("-fomit-frame-pointer")
|
//.arg("-fomit-frame-pointer")
|
||||||
.arg(if env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" {
|
.arg(if env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" {
|
||||||
"-static-libstdc++"
|
"-static-libstdc++"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
})
|
})
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(format!("{}/libpng-harness.so", &out_dir))
|
.arg(format!("{}/libpng-harness.so", &out_dir))
|
||||||
.arg("./harness.cc")
|
.arg("./harness.cc")
|
||||||
.arg(format!("{}/.libs/libpng16.a", &libpng))
|
.arg(format!("{}/.libs/libpng16.a", &libpng))
|
||||||
.arg("-l")
|
.arg("-l")
|
||||||
.arg("z")
|
.arg("z")
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(status.success());
|
assert!(status.success());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,10 +88,17 @@ static char * allocation = NULL;
|
|||||||
__attribute__((noinline))
|
__attribute__((noinline))
|
||||||
void func3( char * alloc) {
|
void func3( char * alloc) {
|
||||||
//printf("func3\n");
|
//printf("func3\n");
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (rand() == 0) {
|
||||||
|
alloc[0x1ff] = 0xde;
|
||||||
|
printf("alloc[0x200]: %d\n", alloc[0x200]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (random() == 0) {
|
if (random() == 0) {
|
||||||
alloc[0x1ff] = 0xde;
|
alloc[0x1ff] = 0xde;
|
||||||
printf("alloc[0x200]: %d\n", alloc[0x200]);
|
printf("alloc[0x200]: %d\n", alloc[0x200]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
__attribute__((noinline))
|
__attribute__((noinline))
|
||||||
void func2() {
|
void func2() {
|
||||||
@ -104,10 +111,19 @@ void func1() {
|
|||||||
//printf("func1\n");
|
//printf("func1\n");
|
||||||
func2();
|
func2();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Export this symbol
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define HARNESS_EXPORTS __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
# define HARNESS_EXPORTS
|
||||||
|
#endif
|
||||||
|
|
||||||
// Entry point for LibFuzzer.
|
// Entry point for LibFuzzer.
|
||||||
// Roughly follows the libpng book example:
|
// Roughly follows the libpng book example:
|
||||||
// http://www.libpng.org/pub/png/book/chapter13.html
|
// http://www.libpng.org/pub/png/book/chapter13.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
HARNESS_EXPORTS extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
|
|
||||||
if (size >= 8 && *(uint64_t*)data == 0xABCDEFAA8F1324AA){
|
if (size >= 8 && *(uint64_t*)data == 0xABCDEFAA8F1324AA){
|
||||||
abort();
|
abort();
|
||||||
|
@ -52,10 +52,13 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use libafl_frida::{
|
use libafl_frida::{
|
||||||
asan_errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
|
|
||||||
helper::{FridaHelper, FridaInstrumentationHelper, MAP_SIZE},
|
helper::{FridaHelper, FridaInstrumentationHelper, MAP_SIZE},
|
||||||
FridaOptions,
|
FridaOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use libafl_frida::asan_errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS};
|
||||||
|
|
||||||
use libafl_targets::cmplog::{CmpLogObserver, CMPLOG_MAP};
|
use libafl_targets::cmplog::{CmpLogObserver, CMPLOG_MAP};
|
||||||
|
|
||||||
struct FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S>
|
struct FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S>
|
||||||
@ -107,6 +110,7 @@ where
|
|||||||
if self.helper.stalker_enabled() {
|
if self.helper.stalker_enabled() {
|
||||||
self.stalker.deactivate();
|
self.stalker.deactivate();
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
if unsafe { ASAN_ERRORS.is_some() && !ASAN_ERRORS.as_ref().unwrap().is_empty() } {
|
if unsafe { ASAN_ERRORS.is_some() && !ASAN_ERRORS.as_ref().unwrap().is_empty() } {
|
||||||
println!("Crashing target as it had ASAN errors");
|
println!("Crashing target as it had ASAN errors");
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -257,25 +261,7 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Not supported on windows right now
|
|
||||||
#[cfg(windows)]
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn fuzz(
|
|
||||||
_module_name: &str,
|
|
||||||
_symbol_name: &str,
|
|
||||||
_corpus_dirs: &[PathBuf],
|
|
||||||
_objective_dir: &Path,
|
|
||||||
_broker_port: u16,
|
|
||||||
_cores: &[usize],
|
|
||||||
_stdout_file: Option<&str>,
|
|
||||||
_broker_addr: Option<SocketAddr>,
|
|
||||||
_configuration: String,
|
|
||||||
) -> Result<(), ()> {
|
|
||||||
todo!("Example not supported on Windows");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The actual fuzzer
|
/// The actual fuzzer
|
||||||
#[cfg(unix)]
|
|
||||||
#[allow(clippy::too_many_lines, clippy::too_many_arguments)]
|
#[allow(clippy::too_many_lines, clippy::too_many_arguments)]
|
||||||
unsafe fn fuzz(
|
unsafe fn fuzz(
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
@ -343,12 +329,17 @@ unsafe fn fuzz(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Feedbacks to recognize an input as solution
|
// Feedbacks to recognize an input as solution
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
let objective = feedback_or_fast!(
|
let objective = feedback_or_fast!(
|
||||||
CrashFeedback::new(),
|
CrashFeedback::new(),
|
||||||
TimeoutFeedback::new(),
|
TimeoutFeedback::new(),
|
||||||
AsanErrorsFeedback::new()
|
AsanErrorsFeedback::new()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
|
||||||
|
|
||||||
// If not restarting, create a State from scratch
|
// If not restarting, create a State from scratch
|
||||||
let mut state = state.unwrap_or_else(|| {
|
let mut state = state.unwrap_or_else(|| {
|
||||||
StdState::new(
|
StdState::new(
|
||||||
@ -391,8 +382,11 @@ unsafe fn fuzz(
|
|||||||
// A fuzzer with feedbacks and a corpus scheduler
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
frida_helper.register_thread();
|
frida_helper.register_thread();
|
||||||
// Create the executor for an in-process function with just one observer for edge coverage
|
// Create the executor for an in-process function with just one observer for edge coverage
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
let mut executor = FridaInProcessExecutor::new(
|
let mut executor = FridaInProcessExecutor::new(
|
||||||
&gum,
|
&gum,
|
||||||
InProcessExecutor::new(
|
InProcessExecutor::new(
|
||||||
@ -410,6 +404,20 @@ unsafe fn fuzz(
|
|||||||
Duration::new(30, 0),
|
Duration::new(30, 0),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let mut executor = FridaInProcessExecutor::new(
|
||||||
|
&gum,
|
||||||
|
InProcessExecutor::new(
|
||||||
|
&mut frida_harness,
|
||||||
|
tuple_list!(edges_observer, time_observer,),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut mgr,
|
||||||
|
)?,
|
||||||
|
&mut frida_helper,
|
||||||
|
Duration::new(30, 0),
|
||||||
|
);
|
||||||
|
|
||||||
// In case the corpus is empty (on first run), reset
|
// In case the corpus is empty (on first run), reset
|
||||||
if state.corpus().count() < 1 {
|
if state.corpus().count() < 1 {
|
||||||
state
|
state
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
#[cfg(unix)]
|
|
||||||
mod fuzzer;
|
mod fuzzer;
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
fuzzer::main();
|
fuzzer::main();
|
||||||
}
|
}
|
||||||
#[cfg(not(unix))]
|
|
||||||
pub fn main() {
|
|
||||||
todo!("Frida not yet supported on this OS.");
|
|
||||||
}
|
|
||||||
|
@ -27,7 +27,7 @@ hashbrown = "0.11"
|
|||||||
libloading = "0.7.0"
|
libloading = "0.7.0"
|
||||||
rangemap = "0.1.10"
|
rangemap = "0.1.10"
|
||||||
frida-gum-sys = { version = "0.3", features = [ "auto-download", "event-sink", "invocation-listener"] }
|
frida-gum-sys = { version = "0.3", features = [ "auto-download", "event-sink", "invocation-listener"] }
|
||||||
frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] }
|
frida-gum = { version = "0.5.2", features = [ "auto-download", "event-sink", "invocation-listener"] }
|
||||||
core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity_rs", rev = "6648a7a" }
|
core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity_rs", rev = "6648a7a" }
|
||||||
regex = "1.4"
|
regex = "1.4"
|
||||||
dynasmrt = "1.0.1"
|
dynasmrt = "1.0.1"
|
||||||
|
@ -4,5 +4,6 @@ fn main() {
|
|||||||
cc::Build::new().file("src/gettls.c").compile("libgettls.a");
|
cc::Build::new().file("src/gettls.c").compile("libgettls.a");
|
||||||
|
|
||||||
// Force linking against libc++
|
// Force linking against libc++
|
||||||
|
#[cfg(unix)]
|
||||||
println!("cargo:rustc-link-lib=dylib=c++");
|
println!("cargo:rustc-link-lib=dylib=c++");
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,15 @@ use num_traits::cast::FromPrimitive;
|
|||||||
|
|
||||||
use rangemap::RangeMap;
|
use rangemap::RangeMap;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
|
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
use crate::{asan_rt::AsanRuntime, FridaOptions};
|
use crate::{asan_rt::AsanRuntime, FridaOptions};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
use crate::FridaOptions;
|
||||||
|
|
||||||
#[cfg(feature = "cmplog")]
|
#[cfg(feature = "cmplog")]
|
||||||
use crate::cmplog_rt::CmpLogRuntime;
|
use crate::cmplog_rt::CmpLogRuntime;
|
||||||
|
|
||||||
@ -54,7 +59,7 @@ enum SpecialCmpLogCase {
|
|||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
const ANONYMOUS_FLAG: MapFlags = MapFlags::MAP_ANON;
|
const ANONYMOUS_FLAG: MapFlags = MapFlags::MAP_ANON;
|
||||||
#[cfg(not(target_vendor = "apple"))]
|
#[cfg(not(any(target_vendor = "apple", target_os = "windows")))]
|
||||||
const ANONYMOUS_FLAG: MapFlags = MapFlags::MAP_ANONYMOUS;
|
const ANONYMOUS_FLAG: MapFlags = MapFlags::MAP_ANONYMOUS;
|
||||||
|
|
||||||
/// An helper that feeds [`FridaInProcessExecutor`] with user-supplied instrumentation
|
/// An helper that feeds [`FridaInProcessExecutor`] with user-supplied instrumentation
|
||||||
@ -63,6 +68,7 @@ pub trait FridaHelper<'a> {
|
|||||||
fn transformer(&self) -> &Transformer<'a>;
|
fn transformer(&self) -> &Transformer<'a>;
|
||||||
|
|
||||||
/// Register a new thread with this `FridaHelper`
|
/// Register a new thread with this `FridaHelper`
|
||||||
|
#[cfg(unix)]
|
||||||
fn register_thread(&mut self);
|
fn register_thread(&mut self);
|
||||||
|
|
||||||
/// Called prior to execution of an input
|
/// Called prior to execution of an input
|
||||||
@ -94,6 +100,7 @@ pub struct FridaInstrumentationHelper<'a> {
|
|||||||
transformer: Option<Transformer<'a>>,
|
transformer: Option<Transformer<'a>>,
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
capstone: Capstone,
|
capstone: Capstone,
|
||||||
|
#[cfg(unix)]
|
||||||
asan_runtime: AsanRuntime,
|
asan_runtime: AsanRuntime,
|
||||||
#[cfg(feature = "cmplog")]
|
#[cfg(feature = "cmplog")]
|
||||||
cmplog_runtime: CmpLogRuntime,
|
cmplog_runtime: CmpLogRuntime,
|
||||||
@ -109,6 +116,7 @@ impl<'a> FridaHelper<'a> for FridaInstrumentationHelper<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Register the current thread with the [`FridaInstrumentationHelper`]
|
/// Register the current thread with the [`FridaInstrumentationHelper`]
|
||||||
|
#[cfg(unix)]
|
||||||
fn register_thread(&mut self) {
|
fn register_thread(&mut self) {
|
||||||
self.asan_runtime.register_thread();
|
self.asan_runtime.register_thread();
|
||||||
}
|
}
|
||||||
@ -258,6 +266,7 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
modules_to_instrument: &'a [&str],
|
modules_to_instrument: &'a [&str],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// workaround frida's frida-gum-allocate-near bug:
|
// workaround frida's frida-gum-allocate-near bug:
|
||||||
|
#[cfg(unix)]
|
||||||
unsafe {
|
unsafe {
|
||||||
for _ in 0..512 {
|
for _ in 0..512 {
|
||||||
mmap(
|
mmap(
|
||||||
@ -295,6 +304,7 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
.detail(true)
|
.detail(true)
|
||||||
.build()
|
.build()
|
||||||
.expect("Failed to create Capstone object"),
|
.expect("Failed to create Capstone object"),
|
||||||
|
#[cfg(not(windows))]
|
||||||
asan_runtime: AsanRuntime::new(options.clone()),
|
asan_runtime: AsanRuntime::new(options.clone()),
|
||||||
#[cfg(feature = "cmplog")]
|
#[cfg(feature = "cmplog")]
|
||||||
cmplog_runtime: CmpLogRuntime::new(),
|
cmplog_runtime: CmpLogRuntime::new(),
|
||||||
@ -342,6 +352,7 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
if helper.options().coverage_enabled() {
|
if helper.options().coverage_enabled() {
|
||||||
helper.emit_coverage_mapping(address, &output);
|
helper.emit_coverage_mapping(address, &output);
|
||||||
}
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
if helper.options().drcov_enabled() {
|
if helper.options().drcov_enabled() {
|
||||||
instruction.put_callout(|context| {
|
instruction.put_callout(|context| {
|
||||||
let real_address =
|
let real_address =
|
||||||
@ -393,6 +404,7 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
if helper.options().asan_enabled() || helper.options().drcov_enabled() {
|
if helper.options().asan_enabled() || helper.options().drcov_enabled() {
|
||||||
helper.asan_runtime.add_stalked_address(
|
helper.asan_runtime.add_stalked_address(
|
||||||
output.writer().pc() as usize - 4,
|
output.writer().pc() as usize - 4,
|
||||||
@ -404,6 +416,8 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
helper.transformer = Some(transformer);
|
helper.transformer = Some(transformer);
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
if helper.options().asan_enabled() || helper.options().drcov_enabled() {
|
if helper.options().asan_enabled() || helper.options().drcov_enabled() {
|
||||||
helper.asan_runtime.init(gum, modules_to_instrument);
|
helper.asan_runtime.init(gum, modules_to_instrument);
|
||||||
}
|
}
|
||||||
@ -779,6 +793,8 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
writer.put_b_label(after_report_impl);
|
writer.put_b_label(after_report_impl);
|
||||||
|
|
||||||
self.current_report_impl = writer.pc();
|
self.current_report_impl = writer.pc();
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
writer.put_bytes(self.asan_runtime.blob_report());
|
writer.put_bytes(self.asan_runtime.blob_report());
|
||||||
|
|
||||||
writer.put_label(after_report_impl);
|
writer.put_label(after_report_impl);
|
||||||
@ -915,6 +931,7 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert the check_shadow_mem code blob
|
// Insert the check_shadow_mem code blob
|
||||||
|
#[cfg(unix)]
|
||||||
match width {
|
match width {
|
||||||
1 => writer.put_bytes(&self.asan_runtime.blob_check_mem_byte()),
|
1 => writer.put_bytes(&self.asan_runtime.blob_check_mem_byte()),
|
||||||
2 => writer.put_bytes(&self.asan_runtime.blob_check_mem_halfword()),
|
2 => writer.put_bytes(&self.asan_runtime.blob_check_mem_halfword()),
|
||||||
|
@ -4,10 +4,13 @@ It can report coverage and, on supported architecutres, even reports memory acce
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/// The frida-asan allocator
|
/// The frida-asan allocator
|
||||||
|
#[cfg(unix)]
|
||||||
pub mod alloc;
|
pub mod alloc;
|
||||||
/// Handling of ASAN errors
|
/// Handling of ASAN errors
|
||||||
|
#[cfg(unix)]
|
||||||
pub mod asan_errors;
|
pub mod asan_errors;
|
||||||
/// The frida address sanitizer runtime
|
/// The frida address sanitizer runtime
|
||||||
|
#[cfg(unix)]
|
||||||
pub mod asan_rt;
|
pub mod asan_rt;
|
||||||
|
|
||||||
#[cfg(feature = "cmplog")]
|
#[cfg(feature = "cmplog")]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user