diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index c59b89c88c5..23d7c9146b9 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -6,9 +6,8 @@ edition = "2018" build = "build.rs" [features] -default = ["std", "frida"] +default = ["std"] std = [] -frida = ["frida-gum", "frida-gum-sys"] [profile.release] lto = true @@ -22,10 +21,10 @@ num_cpus = "1.0" which = "4.1" [target.'cfg(unix)'.dependencies] -libafl = { path = "../../libafl/", features = [ "std" ] } #, "llmp_small_maps", "llmp_debug"]} +libafl = { path = "../../libafl/", features = [ "std", "llmp_compression" ] } #, "llmp_small_maps", "llmp_debug"]} capstone = "0.8.0" -frida-gum = { version = "0.4", optional = true, features = [ "auto-download", "event-sink", "invocation-listener"] } -frida-gum-sys = { version = "0.2.4", optional = true, features = [ "auto-download", "event-sink", "invocation-listener"] } +frida-gum = { version = "0.4", git = "https://github.com/s1341/frida-rust", features = [ "auto-download", "event-sink", "invocation-listener"] } +#frida-gum = { version = "0.4", path = "../../../frida-rust/frida-gum", features = [ "auto-download", "event-sink", "invocation-listener"] } libafl_frida = { path = "../../libafl_frida", version = "0.1.0" } lazy_static = "1.4.0" libc = "0.2" diff --git a/fuzzers/frida_libpng/harness.cc b/fuzzers/frida_libpng/harness.cc index b5e3e6eda8c..625ab3b18f3 100644 --- a/fuzzers/frida_libpng/harness.cc +++ b/fuzzers/frida_libpng/harness.cc @@ -89,7 +89,8 @@ __attribute__((noinline)) void func3( char * alloc) { printf("func3\n"); if (random() == 0) { - alloc[0xff] = 0xde; + alloc[0x1ff] = 0xde; + printf("alloc[0x200]: %d\n", alloc[0x200]); } } __attribute__((noinline)) diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index 26dc39bbd3c..1c14e6b6662 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -17,8 +17,10 @@ libc = "0.2.92" hashbrown = "0.11" libloading = "0.7.0" rangemap = "0.1.10" -frida-gum = { version = "0.4.0", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } -frida-gum-sys = { version = "0.2.4", features = [ "auto-download", "event-sink", "invocation-listener"] } +frida-gum = { version = "0.4.0", git = "https://github.com/s1341/frida-rust", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } +frida-gum-sys = { version = "0.2.4", git = "https://github.com/s1341/frida-rust", features = [ "auto-download", "event-sink", "invocation-listener"] } +#frida-gum = { version = "0.4.0", path = "../../frida-rust/frida-gum", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } +#frida-gum-sys = { version = "0.2.4", path = "../../frida-rust/frida-gum-sys", features = [ "auto-download", "event-sink", "invocation-listener"] } regex = "1.4" dynasmrt = "1.0.1" capstone = "0.8.0" diff --git a/libafl_frida/src/asan_rt.rs b/libafl_frida/src/asan_rt.rs index 5f3a42a5822..5c325a00f13 100644 --- a/libafl_frida/src/asan_rt.rs +++ b/libafl_frida/src/asan_rt.rs @@ -24,7 +24,7 @@ use color_backtrace::{default_output_stream, BacktracePrinter, Verbosity}; use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; #[cfg(unix)] use gothook::GotHookLibrary; -use libc::{_SC_PAGESIZE, getrlimit64, rlimit64, sysconf}; +use libc::{getrlimit64, rlimit64, sysconf, _SC_PAGESIZE}; use rangemap::RangeSet; use serde::{Deserialize, Serialize}; use std::{ @@ -90,7 +90,10 @@ impl Allocator { addr as *mut c_void, page_size, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED | MapFlags::MAP_NORESERVE, + MapFlags::MAP_PRIVATE + | MapFlags::MAP_ANONYMOUS + | MapFlags::MAP_FIXED + | MapFlags::MAP_NORESERVE, -1, 0, ) @@ -110,7 +113,10 @@ impl Allocator { addr as *mut c_void, addr + addr, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED | MapFlags::MAP_PRIVATE | MapFlags::MAP_NORESERVE, + MapFlags::MAP_ANONYMOUS + | MapFlags::MAP_FIXED + | MapFlags::MAP_PRIVATE + | MapFlags::MAP_NORESERVE, -1, 0, ) @@ -161,7 +167,8 @@ impl Allocator { let mut current_size = size; while current_size <= self.largest_allocation { if self.allocation_queue.contains_key(¤t_size) { - if let Some(metadata) = self.allocation_queue.entry(current_size).or_default().pop() { + if let Some(metadata) = self.allocation_queue.entry(current_size).or_default().pop() + { return Some(metadata); } } @@ -184,8 +191,7 @@ impl Allocator { } let rounded_up_size = self.round_up_to_page(size); - let metadata = if let Some(mut metadata) = self.find_smallest_fit(rounded_up_size) - { + let metadata = if let Some(mut metadata) = self.find_smallest_fit(rounded_up_size) { //println!("reusing allocation at {:x}, (actual mapping starts at {:x}) size {:x}", metadata.address, metadata.address - self.page_size, size); metadata.is_malloc_zero = is_malloc_zero; metadata.size = size; @@ -214,11 +220,7 @@ impl Allocator { } }; - self.map_shadow_for_region( - mapping, - mapping + rounded_up_size, - false, - ); + self.map_shadow_for_region(mapping, mapping + rounded_up_size, false); let mut metadata = AllocationMetadata { address: mapping, @@ -593,6 +595,7 @@ extern "C" { pub struct AsanRuntime { regs: [usize; 32], + blob_report: Option>, blob_check_mem_byte: Option>, blob_check_mem_halfword: Option>, blob_check_mem_dword: Option>, @@ -677,6 +680,7 @@ impl AsanRuntime { pub fn new(options: FridaOptions) -> Rc> { let res = Rc::new(RefCell::new(Self { regs: [0; 32], + blob_report: None, blob_check_mem_byte: None, blob_check_mem_halfword: None, blob_check_mem_dword: None, @@ -803,8 +807,11 @@ impl AsanRuntime { let stack_address = &stack_var as *const _ as *const c_void as usize; let (start, end, _, _) = find_mapping_for_address(stack_address).unwrap(); - let mut stack_rlimit = rlimit64 { rlim_cur: 0, rlim_max: 0 }; - assert!(unsafe { getrlimit64(3, &mut stack_rlimit as *mut rlimit64 ) } == 0); + let mut stack_rlimit = rlimit64 { + rlim_cur: 0, + rlim_max: 0, + }; + assert!(unsafe { getrlimit64(3, &mut stack_rlimit as *mut rlimit64) } == 0); println!("stack_rlimit: {:?}", stack_rlimit); @@ -816,7 +823,10 @@ impl AsanRuntime { max_start as *mut c_void, start - max_start, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED | MapFlags::MAP_PRIVATE | MapFlags::MAP_STACK, + MapFlags::MAP_ANONYMOUS + | MapFlags::MAP_FIXED + | MapFlags::MAP_PRIVATE + | MapFlags::MAP_STACK, -1, 0, ) @@ -831,7 +841,7 @@ impl AsanRuntime { let tls_address = unsafe { get_tls_ptr() } as usize; // we need to mask off the highest byte, due to 'High Byte Ignore" #[cfg(target_os = "android")] - let tls_address = tls_address & 0xffffffffffffff; + let tls_address = tls_address & 0xffffffffffffff; let (start, end, _, _) = find_mapping_for_address(tls_address).unwrap(); (start, end) @@ -1413,113 +1423,12 @@ impl AsanRuntime { } } - /// Generate the instrumentation blobs for the current arch. - #[allow(clippy::similar_names)] // We allow things like dword and qword - fn generate_instrumentation_blobs(&mut self) { + fn generate_shadow_check_blob(&mut self, bit: u32) -> Box<[u8]> { let shadow_bit = Allocator::get().shadow_bit as u32; macro_rules! shadow_check { ($ops:ident, $bit:expr) => {dynasm!($ops ; .arch aarch64 - //; brk #5 - ; b >skip_report - - ; report: - ; stp x29, x30, [sp, #-0x10]! - ; mov x29, sp - - ; ldr x0, >self_regs_addr - ; stp x2, x3, [x0, #0x10] - ; stp x4, x5, [x0, #0x20] - ; stp x6, x7, [x0, #0x30] - ; stp x8, x9, [x0, #0x40] - ; stp x10, x11, [x0, #0x50] - ; stp x12, x13, [x0, #0x60] - ; stp x14, x15, [x0, #0x70] - ; stp x16, x17, [x0, #0x80] - ; stp x18, x19, [x0, #0x90] - ; stp x20, x21, [x0, #0xa0] - ; stp x22, x23, [x0, #0xb0] - ; stp x24, x25, [x0, #0xc0] - ; stp x26, x27, [x0, #0xd0] - ; stp x28, x29, [x0, #0xe0] - ; stp x30, xzr, [x0, #0xf0] - ; mov x28, x0 - ; .dword (0xd53b4218u32 as i32) // mrs x24, nzcv - //; ldp x0, x1, [sp], #144 - ; ldp x0, x1, [sp, 0x10] - ; stp x0, x1, [x28] - - ; adr x25, >done - ; str x25, [x28, 0xf8] - - ; adr x25, eh_frame_fde - ; adr x27, >fde_address - ; ldr w26, [x27] - ; cmp w26, #0x0 - ; b.ne >skip_register - ; sub x25, x25, x27 - ; str w25, [x27] - ; ldr x1, >register_frame_func - //; brk #11 - ; blr x1 - ; skip_register: - ; ldr x0, >self_addr - ; ldr x1, >trap_func - ; blr x1 - - ; .dword (0xd51b4218u32 as i32) // msr nzcv, x24 - ; ldr x0, >self_regs_addr - ; ldp x2, x3, [x0, #0x10] - ; ldp x4, x5, [x0, #0x20] - ; ldp x6, x7, [x0, #0x30] - ; ldp x8, x9, [x0, #0x40] - ; ldp x10, x11, [x0, #0x50] - ; ldp x12, x13, [x0, #0x60] - ; ldp x14, x15, [x0, #0x70] - ; ldp x16, x17, [x0, #0x80] - ; ldp x18, x19, [x0, #0x90] - ; ldp x20, x21, [x0, #0xa0] - ; ldp x22, x23, [x0, #0xb0] - ; ldp x24, x25, [x0, #0xc0] - ; ldp x26, x27, [x0, #0xd0] - ; ldp x28, x29, [x0, #0xe0] - ; ldp x30, xzr, [x0, #0xf0] - - ; ldp x29, x30, [sp], #0x10 - ; b >done - ; self_addr: - ; .qword self as *mut _ as *mut c_void as i64 - ; self_regs_addr: - ; .qword &mut self.regs as *mut _ as *mut c_void as i64 - ; trap_func: - ; .qword AsanRuntime::handle_trap as *mut c_void as i64 - ; register_frame_func: - ; .qword __register_frame as *mut c_void as i64 - ; eh_frame_cie: - ; .dword 0x14 - ; .dword 0x00 - ; .dword 0x00527a01 - ; .dword 0x011e7c01 - ; .dword 0x001f0c1b - ; eh_frame_fde: - ; .dword 0x14 - ; .dword 0x18 - ; fde_address: - ; .dword 0x0 // <-- address offset goes here - ; .dword 0x104 - //advance_loc 12 - //def_cfa r29 (x29) at offset 16 - //offset r30 (x30) at cfa-8 - //offset r29 (x29) at cfa-16 - ; .dword 0x1d0c4c00 - ; .dword (0x9d029e10 as u32 as i32) - ; .dword 0x04 - // empty next FDE: - ; .dword 0x0 - ; .dword 0x0 - - ; skip_report: + ; mov x1, #1 ; add x1, xzr, x1, lsl #shadow_bit ; add x1, x1, x0, lsr #3 @@ -1531,115 +1440,25 @@ impl AsanRuntime { ; lsr x1, x1, #16 ; lsr x1, x1, x0 ; tbnz x1, #$bit, >done - ; b done + ; nop // will be replaced by b to report ; done: );}; } + let mut ops = dynasmrt::VecAssembler::::new(0); + shadow_check!(ops, bit); + let ops_vec = ops.finalize().unwrap(); + ops_vec[..ops_vec.len() - 4].to_vec().into_boxed_slice() + } + + fn generate_shadow_check_exact_blob(&mut self, val: u32) -> Box<[u8]> { + let shadow_bit = Allocator::get().shadow_bit as u32; macro_rules! shadow_check_exact { ($ops:ident, $val:expr) => {dynasm!($ops ; .arch aarch64 - ; b >skip_report - - ; report: - ; stp x29, x30, [sp, #-0x10]! - ; mov x29, sp - - ; ldr x0, >self_regs_addr - ; stp x2, x3, [x0, #0x10] - ; stp x4, x5, [x0, #0x20] - ; stp x6, x7, [x0, #0x30] - ; stp x8, x9, [x0, #0x40] - ; stp x10, x11, [x0, #0x50] - ; stp x12, x13, [x0, #0x60] - ; stp x14, x15, [x0, #0x70] - ; stp x16, x17, [x0, #0x80] - ; stp x18, x19, [x0, #0x90] - ; stp x20, x21, [x0, #0xa0] - ; stp x22, x23, [x0, #0xb0] - ; stp x24, x25, [x0, #0xc0] - ; stp x26, x27, [x0, #0xd0] - ; stp x28, x29, [x0, #0xe0] - ; stp x30, xzr, [x0, #0xf0] - ; mov x28, x0 - ; .dword (0xd53b4218u32 as i32) // mrs x24, nzcv - ; ldp x0, x1, [sp, 0x10] - ; stp x0, x1, [x28] - - ; adr x25, >done - ; add x25, x25, 4 - ; str x25, [x28, 0xf8] - - ; adr x25, eh_frame_fde - ; adr x27, >fde_address - ; ldr w26, [x27] - ; cmp w26, #0x0 - ; b.ne >skip_register - ; sub x25, x25, x27 - ; str w25, [x27] - ; ldr x1, >register_frame_func - //; brk #11 - ; blr x1 - ; skip_register: - ; ldr x0, >self_addr - ; ldr x1, >trap_func - ; blr x1 - - ; .dword (0xd51b4218u32 as i32) // msr nzcv, x24 - ; ldr x0, >self_regs_addr - ; ldp x2, x3, [x0, #0x10] - ; ldp x4, x5, [x0, #0x20] - ; ldp x6, x7, [x0, #0x30] - ; ldp x8, x9, [x0, #0x40] - ; ldp x10, x11, [x0, #0x50] - ; ldp x12, x13, [x0, #0x60] - ; ldp x14, x15, [x0, #0x70] - ; ldp x16, x17, [x0, #0x80] - ; ldp x18, x19, [x0, #0x90] - ; ldp x20, x21, [x0, #0xa0] - ; ldp x22, x23, [x0, #0xb0] - ; ldp x24, x25, [x0, #0xc0] - ; ldp x26, x27, [x0, #0xd0] - ; ldp x28, x29, [x0, #0xe0] - ; ldp x30, xzr, [x0, #0xf0] - - ; ldp x29, x30, [sp], #0x10 - ; b >done - ; self_addr: - ; .qword self as *mut _ as *mut c_void as i64 - ; self_regs_addr: - ; .qword &mut self.regs as *mut _ as *mut c_void as i64 - ; trap_func: - ; .qword AsanRuntime::handle_trap as *mut c_void as i64 - ; register_frame_func: - ; .qword __register_frame as *mut c_void as i64 - ; eh_frame_cie: - ; .dword 0x14 - ; .dword 0x00 - ; .dword 0x00527a01 - ; .dword 0x011e7c01 - ; .dword 0x001f0c1b - ; eh_frame_fde: - ; .dword 0x14 - ; .dword 0x18 - ; fde_address: - ; .dword 0x0 // <-- address offset goes here - ; .dword 0x104 - //advance_loc 12 - //def_cfa r29 (x29) at offset 16 - //offset r30 (x30) at cfa-8 - //offset r29 (x29) at cfa-16 - ; .dword 0x1d0c4c00 - ; .dword (0x9d029e10 as u32 as i32) - ; .dword 0x04 - // empty next FDE: - ; .dword 0x0 - ; .dword 0x0 - - - ; skip_report: + ; mov x1, #1 ; add x1, xzr, x1, lsl #shadow_bit ; add x1, x1, x0, lsr #3 @@ -1651,92 +1470,153 @@ impl AsanRuntime { ; lsr x1, x1, #16 ; lsr x1, x1, x0 ; .dword -717536768 // 0xd53b4200 //mrs x0, NZCV - ; and x1, x1, #$val + ; and x1, x1, #$val as u64 ; cmp x1, #$val ; b.eq >done - ; b done + ; nop // will be replaced by b to report ; done: - ; .dword -719633920 //0xd51b4200 // msr nvcz, x0 );}; } - let mut ops_check_mem_byte = - dynasmrt::VecAssembler::::new(0); - shadow_check!(ops_check_mem_byte, 0); - self.blob_check_mem_byte = Some(ops_check_mem_byte.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_halfword = - dynasmrt::VecAssembler::::new(0); - shadow_check!(ops_check_mem_halfword, 1); - self.blob_check_mem_halfword = Some( - ops_check_mem_halfword - .finalize() - .unwrap() - .into_boxed_slice(), + let mut ops = dynasmrt::VecAssembler::::new(0); + shadow_check_exact!(ops, val); + let ops_vec = ops.finalize().unwrap(); + ops_vec[..ops_vec.len() - 4].to_vec().into_boxed_slice() + } + + /// + /// Generate the instrumentation blobs for the current arch. + #[allow(clippy::similar_names)] // We allow things like dword and qword + fn generate_instrumentation_blobs(&mut self) { + let mut ops_report = dynasmrt::VecAssembler::::new(0); + dynasm!(ops_report + ; .arch aarch64 + + ; report: + ; stp x29, x30, [sp, #-0x10]! + ; mov x29, sp + // save the nvcz and the 'return-address'/address of instrumented instruction + ; stp x0, x1, [sp, #-0x10]! + + ; ldr x0, >self_regs_addr + ; stp x2, x3, [x0, #0x10] + ; stp x4, x5, [x0, #0x20] + ; stp x6, x7, [x0, #0x30] + ; stp x8, x9, [x0, #0x40] + ; stp x10, x11, [x0, #0x50] + ; stp x12, x13, [x0, #0x60] + ; stp x14, x15, [x0, #0x70] + ; stp x16, x17, [x0, #0x80] + ; stp x18, x19, [x0, #0x90] + ; stp x20, x21, [x0, #0xa0] + ; stp x22, x23, [x0, #0xb0] + ; stp x24, x25, [x0, #0xc0] + ; stp x26, x27, [x0, #0xd0] + ; stp x28, x29, [x0, #0xe0] + ; stp x30, xzr, [x0, #0xf0] + ; mov x28, x0 + + ; mov x25, x1 // address of instrumented instruction. + ; str x25, [x28, 0xf8] + + ; .dword 0xd53b4218u32 as i32 // mrs x24, nzcv + ; ldp x0, x1, [sp, 0x20] + ; stp x0, x1, [x28] + + ; adr x25, eh_frame_fde + ; adr x27, >fde_address + ; ldr w26, [x27] + ; cmp w26, #0x0 + ; b.ne >skip_register + ; sub x25, x25, x27 + ; str w25, [x27] + ; ldr x1, >register_frame_func + //; brk #11 + ; blr x1 + ; skip_register: + ; ldr x0, >self_addr + ; ldr x1, >trap_func + ; blr x1 + + ; .dword 0xd51b4218u32 as i32 // msr nzcv, x24 + ; ldr x0, >self_regs_addr + ; ldp x2, x3, [x0, #0x10] + ; ldp x4, x5, [x0, #0x20] + ; ldp x6, x7, [x0, #0x30] + ; ldp x8, x9, [x0, #0x40] + ; ldp x10, x11, [x0, #0x50] + ; ldp x12, x13, [x0, #0x60] + ; ldp x14, x15, [x0, #0x70] + ; ldp x16, x17, [x0, #0x80] + ; ldp x18, x19, [x0, #0x90] + ; ldp x20, x21, [x0, #0xa0] + ; ldp x22, x23, [x0, #0xb0] + ; ldp x24, x25, [x0, #0xc0] + ; ldp x26, x27, [x0, #0xd0] + ; ldp x28, x29, [x0, #0xe0] + ; ldp x30, xzr, [x0, #0xf0] + + // restore nzcv. and 'return address' + ; ldp x0, x1, [sp], #0x10 + ; ldp x29, x30, [sp], #0x10 + ; br x1 // go back to the 'return address' + + ; self_addr: + ; .qword self as *mut _ as *mut c_void as i64 + ; self_regs_addr: + ; .qword &mut self.regs as *mut _ as *mut c_void as i64 + ; trap_func: + ; .qword AsanRuntime::handle_trap as *mut c_void as i64 + ; register_frame_func: + ; .qword __register_frame as *mut c_void as i64 + ; eh_frame_cie: + ; .dword 0x14 + ; .dword 0x00 + ; .dword 0x00527a01 + ; .dword 0x011e7c01 + ; .dword 0x001f0c1b + ; eh_frame_fde: + ; .dword 0x14 + ; .dword 0x18 + ; fde_address: + ; .dword 0x0 // <-- address offset goes here + ; .dword 0x104 + //advance_loc 12 + //def_cfa r29 (x29) at offset 16 + //offset r30 (x30) at cfa-8 + //offset r29 (x29) at cfa-16 + ; .dword 0x1d0c4c00 + ; .dword 0x9d029e10 as u32 as i32 + ; .dword 0x04 + // empty next FDE: + ; .dword 0x0 + ; .dword 0x0 ); + self.blob_report = Some(ops_report.finalize().unwrap().into_boxed_slice()); + + self.blob_check_mem_byte = Some(self.generate_shadow_check_blob(0)); + self.blob_check_mem_halfword = Some(self.generate_shadow_check_blob(1)); + self.blob_check_mem_dword = Some(self.generate_shadow_check_blob(2)); + self.blob_check_mem_qword = Some(self.generate_shadow_check_blob(3)); + self.blob_check_mem_16bytes = Some(self.generate_shadow_check_blob(4)); - let mut ops_check_mem_dword = - dynasmrt::VecAssembler::::new(0); - shadow_check!(ops_check_mem_dword, 2); - self.blob_check_mem_dword = - Some(ops_check_mem_dword.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_qword = - dynasmrt::VecAssembler::::new(0); - shadow_check!(ops_check_mem_qword, 3); - self.blob_check_mem_qword = - Some(ops_check_mem_qword.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_16bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check!(ops_check_mem_16bytes, 4); - self.blob_check_mem_16bytes = - Some(ops_check_mem_16bytes.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_3bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check_exact!(ops_check_mem_3bytes, 3); - self.blob_check_mem_3bytes = - Some(ops_check_mem_3bytes.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_6bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check_exact!(ops_check_mem_6bytes, 6); - self.blob_check_mem_6bytes = - Some(ops_check_mem_6bytes.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_12bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check_exact!(ops_check_mem_12bytes, 12); - self.blob_check_mem_12bytes = - Some(ops_check_mem_12bytes.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_24bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check_exact!(ops_check_mem_24bytes, 24); - self.blob_check_mem_24bytes = - Some(ops_check_mem_24bytes.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_32bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check_exact!(ops_check_mem_32bytes, 32); - self.blob_check_mem_32bytes = - Some(ops_check_mem_32bytes.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_48bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check_exact!(ops_check_mem_48bytes, 48); - self.blob_check_mem_48bytes = - Some(ops_check_mem_48bytes.finalize().unwrap().into_boxed_slice()); - - let mut ops_check_mem_64bytes = - dynasmrt::VecAssembler::::new(0); - shadow_check_exact!(ops_check_mem_64bytes, 64); - self.blob_check_mem_64bytes = - Some(ops_check_mem_64bytes.finalize().unwrap().into_boxed_slice()); + self.blob_check_mem_3bytes = Some(self.generate_shadow_check_exact_blob(3)); + self.blob_check_mem_6bytes = Some(self.generate_shadow_check_exact_blob(6)); + self.blob_check_mem_12bytes = Some(self.generate_shadow_check_exact_blob(12)); + self.blob_check_mem_24bytes = Some(self.generate_shadow_check_exact_blob(24)); + self.blob_check_mem_32bytes = Some(self.generate_shadow_check_exact_blob(32)); + self.blob_check_mem_48bytes = Some(self.generate_shadow_check_exact_blob(48)); + self.blob_check_mem_64bytes = Some(self.generate_shadow_check_exact_blob(64)); } + /// Get the blob which implements the report funclet + #[inline] + pub fn blob_report(&self) -> &[u8] { + self.blob_report.as_ref().unwrap() + } /// Get the blob which checks a byte access #[inline] pub fn blob_check_mem_byte(&self) -> &[u8] { diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index d53308f192f..fd9a76830e1 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -9,7 +9,10 @@ use libafl::utils::find_mapping_for_path; use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter}; #[cfg(target_arch = "aarch64")] -use capstone::arch::{arm64::{Arm64OperandType, Arm64Extender, Arm64Shift}, ArchOperand::Arm64Operand}; +use capstone::arch::{ + arm64::{Arm64Extender, Arm64OperandType, Arm64Shift}, + ArchOperand::Arm64Operand, +}; use capstone::{ arch::{self, BuildsCapstone}, Capstone, Insn, @@ -55,6 +58,7 @@ pub struct FridaInstrumentationHelper<'a> { map: [u8; MAP_SIZE], previous_pc: [u64; 1], current_log_impl: u64, + current_report_impl: u64, /// Transformer that has to be passed to FridaInProcessExecutor transformer: Option>, capstone: Capstone, @@ -88,10 +92,7 @@ impl<'a> FridaHelper<'a> for FridaInstrumentationHelper<'a> { let mut hasher = AHasher::new_with_keys(0, 0); hasher.write(input.target_bytes().as_slice()); - let filename = format!( - "./coverage/{:016x}.drcov", - hasher.finish(), - ); + let filename = format!("./coverage/{:016x}.drcov", hasher.finish(),); DrCovWriter::new(&filename, &self.ranges, &mut self.drcov_basic_blocks).write(); } @@ -205,6 +206,7 @@ impl<'a> FridaInstrumentationHelper<'a> { map: [0u8; MAP_SIZE], previous_pc: [0u64; 1], current_log_impl: 0, + current_report_impl: 0, transformer: None, capstone: Capstone::new() .arm64() @@ -221,10 +223,14 @@ impl<'a> FridaInstrumentationHelper<'a> { if options.stalker_enabled() { for (id, module_name) in modules_to_instrument.iter().enumerate() { let (lib_start, lib_end) = find_mapping_for_path(module_name.to_str().unwrap()); - println!("including range {:x}-{:x} for {:?}", lib_start, lib_end, module_name); - helper - .ranges - .insert(lib_start..lib_end, (id as u16, module_name.to_str().unwrap())); + println!( + "including range {:x}-{:x} for {:?}", + lib_start, lib_end, module_name + ); + helper.ranges.insert( + lib_start..lib_end, + (id as u16, module_name.to_str().unwrap()), + ); } if helper.options.drcov_enabled() { @@ -311,7 +317,7 @@ impl<'a> FridaInstrumentationHelper<'a> { #[cfg(target_arch = "aarch64")] #[inline] fn emit_shadow_check( - &self, + &mut self, _address: u64, output: &StalkerOutput, basereg: capstone::RegId, @@ -330,6 +336,22 @@ impl<'a> FridaInstrumentationHelper<'a> { None }; + if self.current_report_impl == 0 + || !writer.can_branch_directly_to(self.current_report_impl) + || !writer.can_branch_directly_between(writer.pc() + 128, self.current_report_impl) + { + let after_report_impl = writer.code_offset() + 2; + + #[cfg(target_arch = "x86_64")] + writer.put_jmp_near_label(after_report_impl); + #[cfg(target_arch = "aarch64")] + writer.put_b_label(after_report_impl); + + self.current_report_impl = writer.pc(); + writer.put_bytes(self.asan_runtime.borrow().blob_report()); + + writer.put_label(after_report_impl); + } //writer.put_brk_imm(1); // Preserve x0, x1: @@ -401,14 +423,18 @@ impl<'a> FridaInstrumentationHelper<'a> { if extender_encoding != -1 && shift_amount < 0b1000 { // emit add extended register: https://developer.arm.com/documentation/ddi0602/latest/Base-Instructions/ADD--extended-register---Add--extended-register-- - writer.put_bytes(&(0x8b210000 | ((extender_encoding as u32) << 13) | (shift_amount << 10)).to_le_bytes()); + writer.put_bytes( + &(0x8b210000 | ((extender_encoding as u32) << 13) | (shift_amount << 10)) + .to_le_bytes(), + ); } else if shift_encoding != -1 { - writer.put_bytes(&(0x8b010000 | ((shift_encoding as u32) << 22) | (shift_amount << 10)).to_le_bytes()); + writer.put_bytes( + &(0x8b010000 | ((shift_encoding as u32) << 22) | (shift_amount << 10)) + .to_le_bytes(), + ); } else { panic!("extender: {:?}, shift: {:?}", extender, shift); } - - }; } @@ -469,9 +495,23 @@ impl<'a> FridaInstrumentationHelper<'a> { 16 => writer.put_bytes(&self.asan_runtime.borrow().blob_check_mem_16bytes()), 24 => writer.put_bytes(&self.asan_runtime.borrow().blob_check_mem_24bytes()), 32 => writer.put_bytes(&self.asan_runtime.borrow().blob_check_mem_32bytes()), + 48 => writer.put_bytes(&self.asan_runtime.borrow().blob_check_mem_48bytes()), + 64 => writer.put_bytes(&self.asan_runtime.borrow().blob_check_mem_64bytes()), _ => false, }; + // Add the branch to report + //writer.put_brk_imm(0x12); + writer.put_branch_address(self.current_report_impl); + + match width { + 3 | 6 | 12 | 24 | 32 | 48 | 64 => { + let msr_nvcz_x0: u32 = 0xd51b4200; + writer.put_bytes(&msr_nvcz_x0.to_le_bytes()); + } + _ => (), + } + // Restore x0, x1 assert!(writer.put_ldp_reg_reg_reg_offset( Aarch64Register::X0, @@ -554,7 +594,17 @@ impl<'a> FridaInstrumentationHelper<'a> { &self, _address: u64, instr: &Insn, - ) -> Result<(capstone::RegId, capstone::RegId, i32, u32, Arm64Shift, Arm64Extender), ()> { + ) -> Result< + ( + capstone::RegId, + capstone::RegId, + i32, + u32, + Arm64Shift, + Arm64Extender, + ), + (), + > { // We have to ignore these instructions. Simulating them with their side effects is // complex, to say the least. match instr.mnemonic().unwrap() {