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

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

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