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:
Toka 2021-09-30 05:10:15 +09:00 committed by GitHub
parent 5a246175cf
commit f63b862160
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 295 additions and 128 deletions

View File

@ -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"

View File

@ -28,3 +28,73 @@ 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
```

View File

@ -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());
}
} }

View File

@ -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();

View File

@ -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

View File

@ -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.");
}

View File

@ -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"

View File

@ -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++");
} }

View File

@ -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()),

View File

@ -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")]