s1341 5c856cccc8
WIP: Implement ASAN instrumentation using frida (#45)
* frida_asan: Implemented initial asan runtime library

* frida_asan: Switch to hashbrown

* Implemented GOT-based hooking to isolate the hooking of the memory functions. Implemented initial ASAN instrumentation

* WIP: Shadowing all used memory. Currently tracking pages using a BTreeSet. Slow AF!

* Add SigTrap to unix_signals and inprocess

* Working frida-asan, almost no speed degradation.

Currently the shadow check is reversed, so it checks only that the shadow is not 0.
We need to implement sub-8-byte checking.

* Format

* Cleanup and formatting

* Sub-qword and 16-byte checks implemented; Fixed unaligned access to QWORD

* Pass the ucontext_t to signal handlers. Initial regdump on crash

* Fix typo

* Make the context argument a mut ref

* Add missing files; Implement initial reporting

* Refactor out gothook; Move safety checkers to dynasm

* Get rid of const assembly blobs no longer needed

* Move to a handler function instead of using SIGTRAP.

This bloats the transformed code, but doesn't seem to have a major impact on performance.

Also, implemented pretty backtraces and assembly output.

* Formatting

* Get rid of all the pinning crap I wasted my day on, We don't need it

* windows fixes

* ashmem

* ashmem_service: server side ready

* ashmem_service: client side ready. Ready for integration

* ashmem_service: changes to UnixShMem to make it 'threadable'

* ashmem_service: format

* ashmem_service: Undo changes to UnixShMem, make the thread own the AshmemService instead; Fix protocol bug

* ashmem_service: working ashmem service. Fix merge issues

* use the newly released capston e 0.8.0; Fix a nasty bug where the afl_area an pc_pointer were reversed. Changed Vectors to Boxed [u8]

* Implement type detection for reporting; Implement double-free/unallocated free checking

* fmt

* Cleanup code a little

* frida-asan: This is an omnibus commit. Should probably have been a bunch of small commits, but I don't have the time/patience.

 - Implemented DrCov support in order to debug a failing harness. This is actually
   generic and should be moved out of libafl_frida.
 - Implemented LIBAFL_FRIDA_OPTIONS env var to pass options to the frida helper,
   to dynamically enable/disable asan and drcov.
 - Implemented memory reuse - after each test case the used pages are recycled and
   can be reused in the next test case.
 - Implemented and tested vectorized instruction instrumentation.
 - Implemented not instrumenting atomic load/store instructions. The cost of
   trying to emulate their behaviour is too high at the moment.
 - Implemented probing of shadow bit to determine the best match for the current
   system.
 - Implemented shadow memory pre-mapping where it is available. We probe for this
   too.
 - Implemented ability to specify a list of modules to instrument on the command
   line. This allows fine-grained control of which modules are instrumented for
   coverage/asan/drcov.
 - Implemented unpoisoning of the Input target_bytes in a pre_exec hook.
 - Added support for zero-sized allocations. We return 0x10 bytes at the moment.
 - Added all known operator new/delete functions to hooks.
 - Added workaround for frida_gum_allocate_near bug.
 - Cleaned up reporting, added reporting for different error types.

* frida-asan: Implement leak detection

* Fix merge issues

* Rebased on dev to get llmp/shmem changes; Clippy fixes

* Add FridaOptions struct

* Add the Custom ExitKind; Get rid of Clone/PartialEq on ExitKind

* Make it possible to recover from an ASAN error

* Add SIGTRAP to crashing signals

* Add back (conditional) crashing on Asan errors.

* Fix too-large immediates in add instruction

* Implement RcShMemProvider, finally fix the EOP bug

* Clear ASAN_ERRORS before each test

* Fix warnings; Fix review issues

* Cleanup prints

* Add timeout to Frida mode

* Make allocation-/free-site backtraces optional

* CPU Context and backtrace (on android/aarch64 atm) on crash

* Make stalker conditional

* Add metadata to solution, and write metadata files

* Add addresses to backtrace; Add reporting of ASAN stack errors; Fix ASAN reporting bugs

* Remove meaningless backtrace on crash

* Fix the x0, x1 load in report

* use upstream color-backtrace

* use __builtin_thread_pointer instead of custom asm

* Don't unwrap ASAN_ERRORS if it isn't some

* Fix bug where we weren't clearing the drcov basicblocks after each run

* Fix bug where we were dropping an ashmem too soon

* Fix OwnedPtr instead of CPtr

* Fix gettls for all archs

* cfg guards for target arch, disabling Frida-ASAN/-DrCov if not on aarch64

* Cargo fmt

* Only panic in options when asan/drcov are turned on; Merge fixes

* gothook only supported on unix

* Fix gettls on msvc

* Another attempt to fix MSVC gettls

* Fix backtrace use

* nostd fixes; warning fixes

* formatting

* Migrate FridaEdgeCoverageHelper into libafl_frida, and rename to FridaInstrumentationHelper

* Clean up uses

* Move DrCovWriter to libafl_targets

* Refactor DrCovWriter to get a vec of DrCovBasicBlocks; formatting

* Update to newer backtrace which supports android with gimli

* windows fixes

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: andreafioraldi <andreafioraldi@gmail.com>
2021-04-28 10:12:49 +02:00

166 lines
4.8 KiB
Rust

/*!
This shows how llmp can be used directly, without libafl abstractions
*/
extern crate alloc;
use alloc::rc::Rc;
#[cfg(all(unix, feature = "std"))]
use core::{cell::RefCell, convert::TryInto, time::Duration};
#[cfg(all(unix, feature = "std"))]
use std::{thread, time};
use libafl::bolts::llmp::Tag;
#[cfg(all(unix, feature = "std"))]
use libafl::{
bolts::{
llmp,
shmem::{ShMemProvider, StdShMemProvider},
},
Error,
};
const _TAG_SIMPLE_U32_V1: Tag = 0x51300321;
const _TAG_MATH_RESULT_V1: Tag = 0x77474331;
const _TAG_1MEG_V1: Tag = 0xB1111161;
#[cfg(all(unix, feature = "std"))]
fn adder_loop(port: u16) -> ! {
let shmem_provider = StdShMemProvider::new().unwrap();
let mut client = llmp::LlmpClient::create_attach_to_tcp(shmem_provider, port).unwrap();
let mut last_result: u32 = 0;
let mut current_result: u32 = 0;
loop {
let mut msg_counter = 0;
loop {
let (_sender, tag, buf) = match client.recv_buf().unwrap() {
None => break,
Some(msg) => msg,
};
msg_counter += 1;
match tag {
_TAG_SIMPLE_U32_V1 => {
current_result =
current_result.wrapping_add(u32::from_le_bytes(buf.try_into().unwrap()));
}
_ => println!(
"Adder Client ignored unknown message {} with {} bytes",
tag,
buf.len()
),
};
}
if current_result != last_result {
println!(
"Adder handled {} messages, reporting {} to broker",
msg_counter, current_result
);
client
.send_buf(_TAG_MATH_RESULT_V1, &current_result.to_le_bytes())
.unwrap();
last_result = current_result;
}
thread::sleep(time::Duration::from_millis(100));
}
}
#[cfg(all(unix, feature = "std"))]
fn large_msg_loop(port: u16) -> ! {
let mut client =
llmp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new().unwrap(), port).unwrap();
let meg_buf = [1u8; 1 << 20];
loop {
client.send_buf(_TAG_1MEG_V1, &meg_buf).unwrap();
println!("Sending the next megabyte");
thread::sleep(time::Duration::from_millis(100))
}
}
#[cfg(all(unix, feature = "std"))]
fn broker_message_hook(
client_id: u32,
tag: llmp::Tag,
message: &[u8],
) -> Result<llmp::LlmpMsgHookResult, Error> {
match tag {
_TAG_SIMPLE_U32_V1 => {
println!(
"Client {:?} sent message: {:?}",
client_id,
u32::from_le_bytes(message.try_into().unwrap())
);
Ok(llmp::LlmpMsgHookResult::ForwardToClients)
}
_TAG_MATH_RESULT_V1 => {
println!(
"Adder Client has this current result: {:?}",
u32::from_le_bytes(message.try_into().unwrap())
);
Ok(llmp::LlmpMsgHookResult::Handled)
}
_ => {
println!("Unknwon message id received!");
Ok(llmp::LlmpMsgHookResult::ForwardToClients)
}
}
}
#[cfg(not(unix))]
fn main() {
todo!("LLMP is not yet supported on this platform.");
}
#[cfg(unix)]
fn main() {
/* The main node has a broker, and a few worker threads */
let mode = std::env::args()
.nth(1)
.expect("no mode specified, chose 'broker', 'ctr', 'adder', or 'large'");
let port: u16 = std::env::args()
.nth(2)
.unwrap_or("1337".into())
.parse::<u16>()
.unwrap();
println!("Launching in mode {} on port {}", mode, port);
match mode.as_str() {
"broker" => {
let mut broker = llmp::LlmpBroker::new(StdShMemProvider::new().unwrap()).unwrap();
broker
.launch_listener(llmp::Listener::Tcp(
std::net::TcpListener::bind(format!("127.0.0.1:{}", port)).unwrap(),
))
.unwrap();
broker.loop_forever(&mut broker_message_hook, Some(Duration::from_millis(5)))
}
"ctr" => {
let mut client =
llmp::LlmpClient::create_attach_to_tcp(StdShMemProvider::new().unwrap(), port)
.unwrap();
let mut counter: u32 = 0;
loop {
counter = counter.wrapping_add(1);
client
.send_buf(_TAG_SIMPLE_U32_V1, &counter.to_le_bytes())
.unwrap();
println!("CTR Client writing {}", counter);
thread::sleep(Duration::from_secs(1))
}
}
"adder" => {
adder_loop(port);
}
"large" => {
large_msg_loop(port);
}
_ => {
println!("No valid mode supplied");
}
}
}