Merge branch 'main' into cmplog_instrumentation
This commit is contained in:
commit
370c652838
@ -23,7 +23,7 @@ which = "4.1"
|
|||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.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.1", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] }
|
frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] }
|
||||||
libafl_frida = { path = "../../libafl_frida", version = "0.3.2" }
|
libafl_frida = { path = "../../libafl_frida", version = "0.3.2" }
|
||||||
libafl_targets = { path = "../../libafl_targets", version = "0.3.2" , features = ["sancov_cmplog"] }
|
libafl_targets = { path = "../../libafl_targets", version = "0.3.2" , features = ["sancov_cmplog"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
@ -244,7 +244,6 @@ pub fn main() {
|
|||||||
.value_of("modules_to_instrument")
|
.value_of("modules_to_instrument")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.split(':')
|
.split(':')
|
||||||
.map(|module_name| std::fs::canonicalize(module_name).unwrap())
|
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
//modules_to_instrument,
|
//modules_to_instrument,
|
||||||
&[PathBuf::from("./corpus")],
|
&[PathBuf::from("./corpus")],
|
||||||
@ -280,7 +279,7 @@ fn fuzz(
|
|||||||
unsafe fn fuzz(
|
unsafe fn fuzz(
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
symbol_name: &str,
|
symbol_name: &str,
|
||||||
modules_to_instrument: &[PathBuf],
|
modules_to_instrument: &[&str],
|
||||||
corpus_dirs: &[PathBuf],
|
corpus_dirs: &[PathBuf],
|
||||||
objective_dir: &Path,
|
objective_dir: &Path,
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
|
@ -18,7 +18,7 @@ rustc_version = "0.3.3"
|
|||||||
criterion = "0.3" # Benchmarking
|
criterion = "0.3" # Benchmarking
|
||||||
ahash = "0.6.1" # another hash
|
ahash = "0.6.1" # another hash
|
||||||
fxhash = "0.2.1" # yet another hash
|
fxhash = "0.2.1" # yet another hash
|
||||||
xxhash-rust = { version = "0.8.0", features = ["const_xxh3", "xxh3"] } # xxh3 hashing for rust
|
xxhash-rust = { version = "0.8.2", features = ["xxh3"] } # xxh3 hashing for rust
|
||||||
serde_json = "1.0.60"
|
serde_json = "1.0.60"
|
||||||
num_cpus = "1.0" # cpu count, for llmp example
|
num_cpus = "1.0" # cpu count, for llmp example
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.2"
|
|||||||
tuple_list = "0.1.2"
|
tuple_list = "0.1.2"
|
||||||
hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
|
hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
|
||||||
num = "0.4.0"
|
num = "0.4.0"
|
||||||
xxhash-rust = { version = "0.8.0", features = ["xxh3", "const_xxh3"] } # xxh3 hashing for rust
|
xxhash-rust = { version = "0.8.2", features = ["xxh3"] } # xxh3 hashing for rust
|
||||||
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
||||||
erased-serde = "0.3.12"
|
erased-serde = "0.3.12"
|
||||||
postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat
|
postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat
|
||||||
|
@ -90,75 +90,6 @@ pub fn startable_self() -> Result<Command, Error> {
|
|||||||
Ok(startable)
|
Ok(startable)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows one to walk the mappings in /proc/self/maps, caling a callback function for each
|
|
||||||
/// mapping.
|
|
||||||
/// If the callback returns true, we stop the walk.
|
|
||||||
#[cfg(all(feature = "std", any(target_os = "linux", target_os = "android")))]
|
|
||||||
pub fn walk_self_maps(visitor: &mut dyn FnMut(usize, usize, String, String) -> bool) {
|
|
||||||
use regex::Regex;
|
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
let re = Regex::new(r"^(?P<start>[0-9a-f]{8,16})-(?P<end>[0-9a-f]{8,16}) (?P<perm>[-rwxp]{4}) (?P<offset>[0-9a-f]{8}) [0-9a-f]+:[0-9a-f]+ [0-9]+\s+(?P<path>.*)$")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mapsfile = File::open("/proc/self/maps").expect("Unable to open /proc/self/maps");
|
|
||||||
|
|
||||||
for line in BufReader::new(mapsfile).lines() {
|
|
||||||
let line = line.unwrap();
|
|
||||||
if let Some(caps) = re.captures(&line) {
|
|
||||||
if visitor(
|
|
||||||
usize::from_str_radix(caps.name("start").unwrap().as_str(), 16).unwrap(),
|
|
||||||
usize::from_str_radix(caps.name("end").unwrap().as_str(), 16).unwrap(),
|
|
||||||
caps.name("perm").unwrap().as_str().to_string(),
|
|
||||||
caps.name("path").unwrap().as_str().to_string(),
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the start and end address, permissions and path of the mapping containing a particular address
|
|
||||||
#[cfg(all(feature = "std", any(target_os = "linux", target_os = "android")))]
|
|
||||||
pub fn find_mapping_for_address(address: usize) -> Result<(usize, usize, String, String), Error> {
|
|
||||||
let mut result = (0, 0, "".to_string(), "".to_string());
|
|
||||||
walk_self_maps(&mut |start, end, permissions, path| {
|
|
||||||
if start <= address && address < end {
|
|
||||||
result = (start, end, permissions, path);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if result.0 == 0 {
|
|
||||||
Err(Error::Unknown(
|
|
||||||
"Couldn't find a mapping for this address".to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the start and end address of the mapping containing with a particular path
|
|
||||||
#[cfg(all(feature = "std", any(target_os = "linux", target_os = "android")))]
|
|
||||||
#[must_use]
|
|
||||||
pub fn find_mapping_for_path(libpath: &str) -> (usize, usize) {
|
|
||||||
let mut libstart = 0;
|
|
||||||
let mut libend = 0;
|
|
||||||
walk_self_maps(&mut |start, end, _permissions, path| {
|
|
||||||
if libpath == path {
|
|
||||||
if libstart == 0 {
|
|
||||||
libstart = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
libend = end;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
});
|
|
||||||
|
|
||||||
(libstart, libend)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// "Safe" wrapper around dup2
|
/// "Safe" wrapper around dup2
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
pub fn dup2(fd: i32, device: i32) -> Result<(), Error> {
|
pub fn dup2(fd: i32, device: i32) -> Result<(), Error> {
|
||||||
|
@ -4,7 +4,7 @@ pub use tuple_list::{tuple_list, tuple_list_type, TupleList};
|
|||||||
|
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
|
|
||||||
use xxhash_rust::const_xxh3::xxh3_64;
|
use xxhash_rust::xxh3::xxh3_64;
|
||||||
|
|
||||||
#[cfg(feature = "RUSTC_IS_NIGHTLY")]
|
#[cfg(feature = "RUSTC_IS_NIGHTLY")]
|
||||||
/// From https://stackoverflow.com/a/60138532/7658998
|
/// From https://stackoverflow.com/a/60138532/7658998
|
||||||
|
@ -19,7 +19,7 @@ use std::net::{SocketAddr, ToSocketAddrs};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{
|
bolts::{
|
||||||
llmp::{self, Flags, LlmpClientDescription, LlmpSender, Tag},
|
llmp::{self, Flags, LlmpClientDescription, LlmpConnection, LlmpSender, Tag},
|
||||||
shmem::ShMemProvider,
|
shmem::ShMemProvider,
|
||||||
},
|
},
|
||||||
events::{BrokerEventResult, Event, EventFirer, EventManager, EventProcessor, EventRestarter},
|
events::{BrokerEventResult, Event, EventFirer, EventManager, EventProcessor, EventRestarter},
|
||||||
@ -273,6 +273,16 @@ where
|
|||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
SP: ShMemProvider + 'static,
|
SP: ShMemProvider + 'static,
|
||||||
{
|
{
|
||||||
|
/// Create a manager from a raw llmp client
|
||||||
|
pub fn new(llmp: llmp::LlmpClient<SP>) -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
|
llmp,
|
||||||
|
#[cfg(feature = "llmp_compression")]
|
||||||
|
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Create llmp on a port
|
/// Create llmp on a port
|
||||||
/// If the port is not yet bound, it will act as broker
|
/// If the port is not yet bound, it will act as broker
|
||||||
/// Else, it will act as client.
|
/// Else, it will act as client.
|
||||||
@ -715,13 +725,25 @@ where
|
|||||||
)
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
|
let broker_things = |mut broker: LlmpEventBroker<I, SP, ST>, remote_broker_addr| {
|
||||||
|
if let Some(remote_broker_addr) = remote_broker_addr {
|
||||||
|
println!("B2b: Connecting to {:?}", &remote_broker_addr);
|
||||||
|
broker.connect_b2b(remote_broker_addr)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
broker.broker_loop()
|
||||||
|
};
|
||||||
|
|
||||||
// We get here if we are on Unix, or we are a broker on Windows.
|
// We get here if we are on Unix, or we are a broker on Windows.
|
||||||
let core_id = match self.kind {
|
let (mgr, core_id) = match self.kind {
|
||||||
ManagerKind::Broker | ManagerKind::Any => {
|
ManagerKind::Any => {
|
||||||
let mut broker = LlmpEventBroker::<I, SP, ST>::new_on_port(
|
let connection =
|
||||||
self.shmem_provider.clone(),
|
LlmpConnection::on_port(self.shmem_provider.clone(), self.broker_port)?;
|
||||||
|
match connection {
|
||||||
|
LlmpConnection::IsBroker { broker } => {
|
||||||
|
let event_broker = LlmpEventBroker::<I, SP, ST>::new(
|
||||||
|
broker,
|
||||||
self.stats.take().unwrap(),
|
self.stats.take().unwrap(),
|
||||||
self.broker_port,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Yep, broker. Just loop here.
|
// Yep, broker. Just loop here.
|
||||||
@ -729,23 +751,38 @@ where
|
|||||||
"Doing broker things. Run this tool again to start fuzzing in a client."
|
"Doing broker things. Run this tool again to start fuzzing in a client."
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(remote_broker_addr) = self.remote_broker_addr {
|
broker_things(event_broker, self.remote_broker_addr)?;
|
||||||
println!("B2b: Connecting to {:?}", &remote_broker_addr);
|
|
||||||
broker.connect_b2b(remote_broker_addr)?;
|
|
||||||
};
|
|
||||||
|
|
||||||
broker.broker_loop()?;
|
|
||||||
return Err(Error::ShuttingDown);
|
return Err(Error::ShuttingDown);
|
||||||
}
|
}
|
||||||
ManagerKind::Client { cpu_core } => cpu_core,
|
LlmpConnection::IsClient { client } => {
|
||||||
};
|
let mgr = LlmpEventManager::<I, OT, S, SP>::new(client)?;
|
||||||
|
(mgr, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ManagerKind::Broker => {
|
||||||
|
let event_broker = LlmpEventBroker::<I, SP, ST>::new_on_port(
|
||||||
|
self.shmem_provider.clone(),
|
||||||
|
self.stats.take().unwrap(),
|
||||||
|
self.broker_port,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
broker_things(event_broker, self.remote_broker_addr)?;
|
||||||
|
|
||||||
|
return Err(Error::ShuttingDown);
|
||||||
|
}
|
||||||
|
ManagerKind::Client { cpu_core } => {
|
||||||
// We are a client
|
// We are a client
|
||||||
let mgr = LlmpEventManager::<I, OT, S, SP>::new_on_port(
|
let mgr = LlmpEventManager::<I, OT, S, SP>::new_on_port(
|
||||||
self.shmem_provider.clone(),
|
self.shmem_provider.clone(),
|
||||||
self.broker_port,
|
self.broker_port,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
(mgr, cpu_core)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(core_id) = core_id {
|
if let Some(core_id) = core_id {
|
||||||
println!("Setting core affinity to {:?}", core_id);
|
println!("Setting core affinity to {:?}", core_id);
|
||||||
core_affinity::set_for_current(core_id);
|
core_affinity::set_for_current(core_id);
|
||||||
|
@ -450,21 +450,11 @@ mod unix_signal_handler {
|
|||||||
target_arch = "aarch64"
|
target_arch = "aarch64"
|
||||||
))]
|
))]
|
||||||
{
|
{
|
||||||
use crate::bolts::os::find_mapping_for_address;
|
|
||||||
println!("{:━^100}", " CRASH ");
|
println!("{:━^100}", " CRASH ");
|
||||||
println!(
|
println!(
|
||||||
"Received signal {} at 0x{:016x}, fault address: 0x{:016x}",
|
"Received signal {} at 0x{:016x}, fault address: 0x{:016x}",
|
||||||
_signal, _context.uc_mcontext.pc, _context.uc_mcontext.fault_address
|
_signal, _context.uc_mcontext.pc, _context.uc_mcontext.fault_address
|
||||||
);
|
);
|
||||||
if let Ok((start, _, _, path)) =
|
|
||||||
find_mapping_for_address(_context.uc_mcontext.pc as usize)
|
|
||||||
{
|
|
||||||
println!(
|
|
||||||
"pc is at offset 0x{:08x} in {}",
|
|
||||||
_context.uc_mcontext.pc as usize - start,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{:━^100}", " REGISTERS ");
|
println!("{:━^100}", " REGISTERS ");
|
||||||
for reg in 0..31 {
|
for reg in 0..31 {
|
||||||
|
@ -108,26 +108,54 @@ where
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compose [`Feedback`]`s` with an `AND` operation
|
pub struct CombinedFeedback<A, B, I, S, FL>
|
||||||
pub struct AndFeedback<A, B, I, S>
|
|
||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// The first [`Feedback`] to `AND`.
|
|
||||||
pub first: A,
|
pub first: A,
|
||||||
/// The second [`Feedback`] to `AND`.
|
|
||||||
pub second: B,
|
pub second: B,
|
||||||
/// The name
|
|
||||||
name: String,
|
name: String,
|
||||||
phantom: PhantomData<(I, S)>,
|
phantom: PhantomData<(I, S, FL)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, I, S> Feedback<I, S> for AndFeedback<A, B, I, S>
|
impl<A, B, I, S, FL> Named for CombinedFeedback<A, B, I, S, FL>
|
||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.name.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, I, S, FL> CombinedFeedback<A, B, I, S, FL>
|
||||||
|
where
|
||||||
|
A: Feedback<I, S>,
|
||||||
|
B: Feedback<I, S>,
|
||||||
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
pub fn new(first: A, second: B) -> Self {
|
||||||
|
let name = format!("{} ({},{})", FL::name(), first.name(), second.name());
|
||||||
|
Self {
|
||||||
|
first,
|
||||||
|
second,
|
||||||
|
name,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, I, S, FL> Feedback<I, S> for CombinedFeedback<A, B, I, S, FL>
|
||||||
|
where
|
||||||
|
A: Feedback<I, S>,
|
||||||
|
B: Feedback<I, S>,
|
||||||
|
FL: FeedbackLogic<A, B, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
@ -142,14 +170,15 @@ where
|
|||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
let a = self
|
FL::is_pair_interesting(
|
||||||
.first
|
&mut self.first,
|
||||||
.is_interesting(state, manager, input, observers, exit_kind)?;
|
&mut self.second,
|
||||||
let b = a
|
state,
|
||||||
&& self
|
manager,
|
||||||
.second
|
input,
|
||||||
.is_interesting(state, manager, input, observers, exit_kind)?;
|
observers,
|
||||||
Ok(b)
|
exit_kind,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
@ -167,27 +196,17 @@ where
|
|||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
// Execute this feedback
|
FL::is_pair_interesting_with_perf(
|
||||||
let a = self.first.is_interesting_with_perf(
|
&mut self.first,
|
||||||
|
&mut self.second,
|
||||||
state,
|
state,
|
||||||
manager,
|
manager,
|
||||||
input,
|
input,
|
||||||
observers,
|
observers,
|
||||||
&exit_kind,
|
exit_kind,
|
||||||
feedback_stats,
|
feedback_stats,
|
||||||
feedback_index,
|
feedback_index,
|
||||||
)?;
|
)
|
||||||
let b = a
|
|
||||||
&& self.second.is_interesting_with_perf(
|
|
||||||
state,
|
|
||||||
manager,
|
|
||||||
input,
|
|
||||||
observers,
|
|
||||||
&exit_kind,
|
|
||||||
feedback_stats,
|
|
||||||
feedback_index + 1,
|
|
||||||
)?;
|
|
||||||
Ok(b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -203,60 +222,62 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, I, S> Named for AndFeedback<A, B, I, S>
|
pub trait FeedbackLogic<A, B, I, S>: 'static
|
||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
#[inline]
|
fn name() -> &'static str;
|
||||||
fn name(&self) -> &str {
|
|
||||||
&self.name
|
fn is_pair_interesting<EM, OT>(
|
||||||
}
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple;
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
fn is_pair_interesting_with_perf<EM, OT>(
|
||||||
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
||||||
|
feedback_index: usize,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, I, S> AndFeedback<A, B, I, S>
|
pub struct LogicEagerOr {}
|
||||||
where
|
pub struct LogicFastOr {}
|
||||||
A: Feedback<I, S>,
|
pub struct LogicEagerAnd {}
|
||||||
B: Feedback<I, S>,
|
pub struct LogicFastAnd {}
|
||||||
I: Input,
|
|
||||||
{
|
|
||||||
/// Creates a new [`AndFeedback`], resulting in the `AND` of two feedbacks.
|
|
||||||
pub fn new(first: A, second: B) -> Self {
|
|
||||||
let name = format!("And({}, {})", first.name(), second.name());
|
|
||||||
Self {
|
|
||||||
first,
|
|
||||||
second,
|
|
||||||
name,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compose feedbacks with an OR operation
|
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicEagerOr
|
||||||
pub struct OrFeedback<A, B, I, S>
|
|
||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// The first [`Feedback`]
|
fn name() -> &'static str {
|
||||||
pub first: A,
|
"Eager OR"
|
||||||
/// The second [`Feedback`], `OR`ed with the first.
|
}
|
||||||
pub second: B,
|
|
||||||
/// The name
|
|
||||||
name: String,
|
|
||||||
phantom: PhantomData<(I, S)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, I, S> Feedback<I, S> for OrFeedback<A, B, I, S>
|
fn is_pair_interesting<EM, OT>(
|
||||||
where
|
first: &mut A,
|
||||||
A: Feedback<I, S>,
|
second: &mut B,
|
||||||
B: Feedback<I, S>,
|
|
||||||
I: Input,
|
|
||||||
{
|
|
||||||
fn is_interesting<EM, OT>(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
@ -267,19 +288,15 @@ where
|
|||||||
EM: EventFirer<I, S>,
|
EM: EventFirer<I, S>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
let a = self
|
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
|
||||||
.first
|
let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
|
||||||
.is_interesting(state, manager, input, observers, exit_kind)?;
|
Ok(a || b)
|
||||||
let b = a
|
|
||||||
|| self
|
|
||||||
.second
|
|
||||||
.is_interesting(state, manager, input, observers, exit_kind)?;
|
|
||||||
Ok(b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_interesting_with_perf<EM, OT>(
|
fn is_pair_interesting_with_perf<EM, OT>(
|
||||||
&mut self,
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
@ -293,7 +310,7 @@ where
|
|||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
// Execute this feedback
|
// Execute this feedback
|
||||||
let a = self.first.is_interesting_with_perf(
|
let a = first.is_interesting_with_perf(
|
||||||
state,
|
state,
|
||||||
manager,
|
manager,
|
||||||
input,
|
input,
|
||||||
@ -302,8 +319,8 @@ where
|
|||||||
feedback_stats,
|
feedback_stats,
|
||||||
feedback_index,
|
feedback_index,
|
||||||
)?;
|
)?;
|
||||||
let b = a
|
|
||||||
|| self.second.is_interesting_with_perf(
|
let b = second.is_interesting_with_perf(
|
||||||
state,
|
state,
|
||||||
manager,
|
manager,
|
||||||
input,
|
input,
|
||||||
@ -312,52 +329,244 @@ where
|
|||||||
feedback_stats,
|
feedback_stats,
|
||||||
feedback_index + 1,
|
feedback_index + 1,
|
||||||
)?;
|
)?;
|
||||||
Ok(b)
|
Ok(a || b)
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn append_metadata(&mut self, state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> {
|
|
||||||
self.first.append_metadata(state, testcase)?;
|
|
||||||
self.second.append_metadata(state, testcase)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
|
|
||||||
self.first.discard_metadata(state, input)?;
|
|
||||||
self.second.discard_metadata(state, input)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, I, S> Named for OrFeedback<A, B, I, S>
|
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicFastOr
|
||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
#[inline]
|
fn name() -> &'static str {
|
||||||
fn name(&self) -> &str {
|
"Fast OR"
|
||||||
&self.name
|
}
|
||||||
|
|
||||||
|
fn is_pair_interesting<EM, OT>(
|
||||||
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
|
||||||
|
if a {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
second.is_interesting(state, manager, input, observers, exit_kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
fn is_pair_interesting_with_perf<EM, OT>(
|
||||||
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
||||||
|
feedback_index: usize,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
// Execute this feedback
|
||||||
|
let a = first.is_interesting_with_perf(
|
||||||
|
state,
|
||||||
|
manager,
|
||||||
|
input,
|
||||||
|
observers,
|
||||||
|
&exit_kind,
|
||||||
|
feedback_stats,
|
||||||
|
feedback_index,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if a {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
second.is_interesting_with_perf(
|
||||||
|
state,
|
||||||
|
manager,
|
||||||
|
input,
|
||||||
|
observers,
|
||||||
|
&exit_kind,
|
||||||
|
feedback_stats,
|
||||||
|
feedback_index + 1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, I, S> OrFeedback<A, B, I, S>
|
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicEagerAnd
|
||||||
where
|
where
|
||||||
A: Feedback<I, S>,
|
A: Feedback<I, S>,
|
||||||
B: Feedback<I, S>,
|
B: Feedback<I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Creates a new [`OrFeedback`] for two feedbacks.
|
fn name() -> &'static str {
|
||||||
pub fn new(first: A, second: B) -> Self {
|
"Eager AND"
|
||||||
let name = format!("Or({}, {})", first.name(), second.name());
|
|
||||||
Self {
|
|
||||||
first,
|
|
||||||
second,
|
|
||||||
name,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_pair_interesting<EM, OT>(
|
||||||
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
|
||||||
|
let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
|
||||||
|
Ok(a && b)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
fn is_pair_interesting_with_perf<EM, OT>(
|
||||||
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
||||||
|
feedback_index: usize,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
// Execute this feedback
|
||||||
|
let a = first.is_interesting_with_perf(
|
||||||
|
state,
|
||||||
|
manager,
|
||||||
|
input,
|
||||||
|
observers,
|
||||||
|
&exit_kind,
|
||||||
|
feedback_stats,
|
||||||
|
feedback_index,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let b = second.is_interesting_with_perf(
|
||||||
|
state,
|
||||||
|
manager,
|
||||||
|
input,
|
||||||
|
observers,
|
||||||
|
&exit_kind,
|
||||||
|
feedback_stats,
|
||||||
|
feedback_index + 1,
|
||||||
|
)?;
|
||||||
|
Ok(a && b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicFastAnd
|
||||||
|
where
|
||||||
|
A: Feedback<I, S>,
|
||||||
|
B: Feedback<I, S>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"Fast AND"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_pair_interesting<EM, OT>(
|
||||||
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
|
||||||
|
if a == false {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
second.is_interesting(state, manager, input, observers, exit_kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
fn is_pair_interesting_with_perf<EM, OT>(
|
||||||
|
first: &mut A,
|
||||||
|
second: &mut B,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
exit_kind: &ExitKind,
|
||||||
|
feedback_stats: &mut [u64; NUM_FEEDBACKS],
|
||||||
|
feedback_index: usize,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
// Execute this feedback
|
||||||
|
let a = first.is_interesting_with_perf(
|
||||||
|
state,
|
||||||
|
manager,
|
||||||
|
input,
|
||||||
|
observers,
|
||||||
|
&exit_kind,
|
||||||
|
feedback_stats,
|
||||||
|
feedback_index,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if a == false {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
second.is_interesting_with_perf(
|
||||||
|
state,
|
||||||
|
manager,
|
||||||
|
input,
|
||||||
|
observers,
|
||||||
|
&exit_kind,
|
||||||
|
feedback_stats,
|
||||||
|
feedback_index + 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Combine two feedbacks with an eager AND operation,
|
||||||
|
/// will call all feedbacks functions even if not necessery to conclude the result
|
||||||
|
pub type EagerAndFeedback<A, B, I, S> = CombinedFeedback<A, B, I, S, LogicEagerAnd>;
|
||||||
|
|
||||||
|
/// Combine two feedbacks with an fast AND operation,
|
||||||
|
/// might skip calling feedbacks functions if not necessery to conclude the result
|
||||||
|
pub type FastAndFeedback<A, B, I, S> = CombinedFeedback<A, B, I, S, LogicFastAnd>;
|
||||||
|
|
||||||
|
/// Combine two feedbacks with an eager OR operation,
|
||||||
|
/// will call all feedbacks functions even if not necessery to conclude the result
|
||||||
|
pub type EagerOrFeedback<A, B, I, S> = CombinedFeedback<A, B, I, S, LogicEagerOr>;
|
||||||
|
|
||||||
|
/// Combine two feedbacks with an fast OR operation,
|
||||||
|
/// might skip calling feedbacks functions if not necessery to conclude the result
|
||||||
|
/// This means any feedback that is not first might be skipped, use caution when using with
|
||||||
|
/// `TimeFeedback`
|
||||||
|
pub type FastOrFeedback<A, B, I, S> = CombinedFeedback<A, B, I, S, LogicFastOr>;
|
||||||
|
|
||||||
/// Compose feedbacks with an OR operation
|
/// Compose feedbacks with an OR operation
|
||||||
pub struct NotFeedback<A, I, S>
|
pub struct NotFeedback<A, I, S>
|
||||||
where
|
where
|
||||||
@ -438,7 +647,18 @@ macro_rules! feedback_and {
|
|||||||
|
|
||||||
( $head:expr, $($tail:expr), +) => {
|
( $head:expr, $($tail:expr), +) => {
|
||||||
// recursive call
|
// recursive call
|
||||||
$crate::feedbacks::AndFeedback::new($head , feedback_and!($($tail),+))
|
$crate::feedbacks::EagerAndFeedback::new($head , feedback_and!($($tail),+))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/// Variadic macro to create a chain of (fast) AndFeedback
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! feedback_and_fast {
|
||||||
|
( $last:expr ) => { $last };
|
||||||
|
|
||||||
|
( $head:expr, $($tail:expr), +) => {
|
||||||
|
// recursive call
|
||||||
|
$crate::feedbacks::FastAndFeedback::new($head , feedback_and_fast!($($tail),+))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,7 +669,17 @@ macro_rules! feedback_or {
|
|||||||
|
|
||||||
( $head:expr, $($tail:expr), +) => {
|
( $head:expr, $($tail:expr), +) => {
|
||||||
// recursive call
|
// recursive call
|
||||||
$crate::feedbacks::OrFeedback::new($head , feedback_or!($($tail),+))
|
$crate::feedbacks::EagerOrFeedback::new($head , feedback_or!($($tail),+))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! feedback_or_fast {
|
||||||
|
( $last:expr ) => { $last };
|
||||||
|
|
||||||
|
( $head:expr, $($tail:expr), +) => {
|
||||||
|
// recursive call
|
||||||
|
$crate::feedbacks::FastOrFeedback::new($head , feedback_or_fast!($($tail),+))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,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.1", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] }
|
frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] }
|
||||||
core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity_rs" }
|
core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity_rs" }
|
||||||
regex = "1.4"
|
regex = "1.4"
|
||||||
dynasmrt = "1.0.1"
|
dynasmrt = "1.0.1"
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
use frida_gum::{PageProtection, RangeDetails};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
use libafl::bolts::os::walk_self_maps;
|
|
||||||
use nix::{
|
use nix::{
|
||||||
libc::memset,
|
libc::memset,
|
||||||
sys::mman::{mmap, MapFlags, ProtFlags},
|
sys::mman::{mmap, MapFlags, ProtFlags},
|
||||||
@ -220,19 +219,18 @@ impl Allocator {
|
|||||||
metadata
|
metadata
|
||||||
} else {
|
} else {
|
||||||
if !ptr.is_null() {
|
if !ptr.is_null() {
|
||||||
AsanErrors::get_mut().report_error(
|
AsanErrors::get_mut()
|
||||||
AsanError::UnallocatedFree((ptr as usize, Backtrace::new())),
|
.report_error(AsanError::UnallocatedFree((ptr as usize, Backtrace::new())));
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if metadata.freed {
|
if metadata.freed {
|
||||||
AsanErrors::get_mut().report_error(
|
AsanErrors::get_mut().report_error(AsanError::DoubleFree((
|
||||||
AsanError::DoubleFree((ptr as usize, metadata.clone(), Backtrace::new())),
|
ptr as usize,
|
||||||
None,
|
metadata.clone(),
|
||||||
);
|
Backtrace::new(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
let shadow_mapping_start = map_to_shadow!(self, ptr as usize);
|
let shadow_mapping_start = map_to_shadow!(self, ptr as usize);
|
||||||
|
|
||||||
@ -389,21 +387,23 @@ impl Allocator {
|
|||||||
for metadata in self.allocations.values() {
|
for metadata in self.allocations.values() {
|
||||||
if !metadata.freed {
|
if !metadata.freed {
|
||||||
AsanErrors::get_mut()
|
AsanErrors::get_mut()
|
||||||
.report_error(AsanError::Leak((metadata.address, metadata.clone())), None);
|
.report_error(AsanError::Leak((metadata.address, metadata.clone())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unpoison all the memory that is currently mapped with read/write permissions.
|
/// Unpoison all the memory that is currently mapped with read/write permissions.
|
||||||
pub fn unpoison_all_existing_memory(&mut self) {
|
pub fn unpoison_all_existing_memory(&mut self) {
|
||||||
walk_self_maps(&mut |start, end, permissions, _path| {
|
RangeDetails::enumerate_with_prot(PageProtection::NoAccess, &mut |range: &RangeDetails| {
|
||||||
if permissions.as_bytes()[0] == b'r' || permissions.as_bytes()[1] == b'w' {
|
if range.protection() as u32 & PageProtection::ReadWrite as u32 != 0 {
|
||||||
|
let start = range.memory_range().base_address().0 as usize;
|
||||||
|
let end = start + range.memory_range().size();
|
||||||
if self.pre_allocated_shadow && start == 1 << self.shadow_bit {
|
if self.pre_allocated_shadow && start == 1 << self.shadow_bit {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
self.map_shadow_for_region(start, end, true);
|
self.map_shadow_for_region(start, end, true);
|
||||||
}
|
}
|
||||||
false
|
true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,7 @@ use capstone::{arch::BuildsCapstone, Capstone};
|
|||||||
use color_backtrace::{default_output_stream, BacktracePrinter, Verbosity};
|
use color_backtrace::{default_output_stream, BacktracePrinter, Verbosity};
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use frida_gum::interceptor::Interceptor;
|
use frida_gum::interceptor::Interceptor;
|
||||||
|
use frida_gum::ModuleDetails;
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
use libafl::bolts::os::find_mapping_for_address;
|
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::{ownedref::OwnedPtr, tuples::Named},
|
bolts::{ownedref::OwnedPtr, tuples::Named},
|
||||||
@ -18,7 +16,6 @@ use libafl::{
|
|||||||
state::HasMetadata,
|
state::HasMetadata,
|
||||||
Error, SerdeAny,
|
Error, SerdeAny,
|
||||||
};
|
};
|
||||||
use rangemap::RangeMap;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use termcolor::{Color, ColorSpec, WriteColor};
|
use termcolor::{Color, ColorSpec, WriteColor};
|
||||||
@ -111,11 +108,7 @@ impl AsanErrors {
|
|||||||
|
|
||||||
/// Report an error
|
/// Report an error
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub(crate) fn report_error(
|
pub(crate) fn report_error(&mut self, error: AsanError) {
|
||||||
&mut self,
|
|
||||||
error: AsanError,
|
|
||||||
instrumented_ranges: Option<&RangeMap<usize, String>>,
|
|
||||||
) {
|
|
||||||
self.errors.push(error.clone());
|
self.errors.push(error.clone());
|
||||||
|
|
||||||
let mut out_stream = default_output_stream();
|
let mut out_stream = default_output_stream();
|
||||||
@ -144,13 +137,13 @@ impl AsanErrors {
|
|||||||
| AsanError::WriteAfterFree(mut error) => {
|
| AsanError::WriteAfterFree(mut error) => {
|
||||||
let (basereg, indexreg, _displacement, fault_address) = error.fault;
|
let (basereg, indexreg, _displacement, fault_address) = error.fault;
|
||||||
|
|
||||||
if let Some((range, path)) = instrumented_ranges.unwrap().get_key_value(&error.pc) {
|
if let Some(module_details) = ModuleDetails::with_address(error.pc as u64) {
|
||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
" at 0x{:x} ({}@0x{:04x}), faulting address 0x{:x}",
|
" at 0x{:x} ({}@0x{:04x}), faulting address 0x{:x}",
|
||||||
error.pc,
|
error.pc,
|
||||||
path,
|
module_details.path(),
|
||||||
error.pc - range.start,
|
error.pc - module_details.range().base_address().0 as usize,
|
||||||
fault_address
|
fault_address
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -267,17 +260,17 @@ impl AsanErrors {
|
|||||||
{
|
{
|
||||||
let invocation = Interceptor::current_invocation();
|
let invocation = Interceptor::current_invocation();
|
||||||
let cpu_context = invocation.cpu_context();
|
let cpu_context = invocation.cpu_context();
|
||||||
if let Some((range, path)) = instrumented_ranges.unwrap().get_key_value(&pc) {
|
if let Some(module_details) = ModuleDetails::with_address(pc as u64) {
|
||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
" at 0x{:x} ({}@0x{:04x})",
|
" at 0x{:x} ({}@0x{:04x})",
|
||||||
pc,
|
pc,
|
||||||
path,
|
module_details.path(),
|
||||||
pc - range.start,
|
pc - module_details.range().base_address().0 as usize,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
writeln!(output, " at 0x{:x}", pc,).unwrap();
|
writeln!(output, " at 0x{:x}", pc).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::non_ascii_literal)]
|
#[allow(clippy::non_ascii_literal)]
|
||||||
@ -364,13 +357,13 @@ impl AsanErrors {
|
|||||||
| AsanError::StackOobWrite((registers, pc, fault, backtrace)) => {
|
| AsanError::StackOobWrite((registers, pc, fault, backtrace)) => {
|
||||||
let (basereg, indexreg, _displacement, fault_address) = fault;
|
let (basereg, indexreg, _displacement, fault_address) = fault;
|
||||||
|
|
||||||
if let Ok((start, _, _, path)) = find_mapping_for_address(pc) {
|
if let Some(module_details) = ModuleDetails::with_address(pc as u64) {
|
||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
" at 0x{:x} ({}:0x{:04x}), faulting address 0x{:x}",
|
" at 0x{:x} ({}:0x{:04x}), faulting address 0x{:x}",
|
||||||
pc,
|
pc,
|
||||||
path,
|
module_details.path(),
|
||||||
pc - start,
|
pc - module_details.range().base_address().0 as usize,
|
||||||
fault_address
|
fault_address
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3,9 +3,6 @@ use std::hash::Hasher;
|
|||||||
|
|
||||||
use libafl::inputs::{HasTargetBytes, Input};
|
use libafl::inputs::{HasTargetBytes, Input};
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
use libafl::bolts::os::find_mapping_for_path;
|
|
||||||
|
|
||||||
use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter};
|
use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter};
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
@ -26,14 +23,13 @@ use frida_gum::instruction_writer::{Aarch64Register, IndexMode};
|
|||||||
use frida_gum::{
|
use frida_gum::{
|
||||||
instruction_writer::InstructionWriter,
|
instruction_writer::InstructionWriter,
|
||||||
stalker::{StalkerOutput, Transformer},
|
stalker::{StalkerOutput, Transformer},
|
||||||
CpuContext,
|
CpuContext, ModuleDetails, ModuleMap,
|
||||||
};
|
};
|
||||||
use frida_gum::{Gum, Module, PageProtection};
|
use frida_gum::{Gum, Module, PageProtection};
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
use num_traits::cast::FromPrimitive;
|
use num_traits::cast::FromPrimitive;
|
||||||
|
|
||||||
use rangemap::RangeMap;
|
use rangemap::RangeMap;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
|
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
|
||||||
|
|
||||||
@ -66,7 +62,7 @@ pub trait FridaHelper<'a> {
|
|||||||
/// pointer to the frida coverage map
|
/// pointer to the frida coverage map
|
||||||
fn map_ptr(&mut self) -> *mut u8;
|
fn map_ptr(&mut self) -> *mut u8;
|
||||||
|
|
||||||
fn ranges(&self) -> &RangeMap<usize, (u16, &str)>;
|
fn ranges(&self) -> &RangeMap<usize, (u16, String)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (Default) map size for frida coverage reporting
|
/// (Default) map size for frida coverage reporting
|
||||||
@ -85,7 +81,8 @@ pub struct FridaInstrumentationHelper<'a> {
|
|||||||
capstone: Capstone,
|
capstone: Capstone,
|
||||||
asan_runtime: AsanRuntime,
|
asan_runtime: AsanRuntime,
|
||||||
cmplog_runtime: CmpLogRuntime,
|
cmplog_runtime: CmpLogRuntime,
|
||||||
ranges: RangeMap<usize, (u16, &'a str)>,
|
ranges: RangeMap<usize, (u16, String)>,
|
||||||
|
module_map: ModuleMap,
|
||||||
options: &'a FridaOptions,
|
options: &'a FridaOptions,
|
||||||
drcov_basic_blocks: Vec<DrCovBasicBlock>,
|
drcov_basic_blocks: Vec<DrCovBasicBlock>,
|
||||||
}
|
}
|
||||||
@ -133,7 +130,7 @@ impl<'a> FridaHelper<'a> for FridaInstrumentationHelper<'a> {
|
|||||||
self.map.as_mut_ptr()
|
self.map.as_mut_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ranges(&self) -> &RangeMap<usize, (u16, &str)> {
|
fn ranges(&self) -> &RangeMap<usize, (u16, String)> {
|
||||||
&self.ranges
|
&self.ranges
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +225,7 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
gum: &'a Gum,
|
gum: &'a Gum,
|
||||||
options: &'a FridaOptions,
|
options: &'a FridaOptions,
|
||||||
_harness_module_name: &str,
|
_harness_module_name: &str,
|
||||||
modules_to_instrument: &'a [PathBuf],
|
modules_to_instrument: &'a [&str],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// workaround frida's frida-gum-allocate-near bug:
|
// workaround frida's frida-gum-allocate-near bug:
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -271,31 +268,23 @@ impl<'a> FridaInstrumentationHelper<'a> {
|
|||||||
asan_runtime: AsanRuntime::new(options.clone()),
|
asan_runtime: AsanRuntime::new(options.clone()),
|
||||||
cmplog_runtime: CmpLogRuntime::new(),
|
cmplog_runtime: CmpLogRuntime::new(),
|
||||||
ranges: RangeMap::new(),
|
ranges: RangeMap::new(),
|
||||||
|
module_map: ModuleMap::new_from_names(modules_to_instrument),
|
||||||
options,
|
options,
|
||||||
drcov_basic_blocks: vec![],
|
drcov_basic_blocks: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
if helper.options().stalker_enabled() {
|
if helper.options().stalker_enabled() {
|
||||||
for (id, module_name) in modules_to_instrument.iter().enumerate() {
|
for (i, module) in helper.module_map.values().iter().enumerate() {
|
||||||
let (lib_start, lib_end) = find_mapping_for_path(module_name.to_str().unwrap());
|
let range = module.range();
|
||||||
println!(
|
let start = range.base_address().0 as usize;
|
||||||
"including range {:x}-{:x} for {:?}",
|
helper
|
||||||
lib_start, lib_end, module_name
|
.ranges
|
||||||
);
|
.insert(start..(start + range.size()), (i as u16, module.path()));
|
||||||
helper.ranges.insert(
|
|
||||||
lib_start..lib_end,
|
|
||||||
(id as u16, module_name.to_str().unwrap()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(suppressed_specifiers) = helper.options().dont_instrument_locations() {
|
if let Some(suppressed_specifiers) = helper.options().dont_instrument_locations() {
|
||||||
for (module_name, offset) in suppressed_specifiers {
|
for (module_name, offset) in suppressed_specifiers {
|
||||||
let (lib_start, _) = find_mapping_for_path(
|
let module_details = ModuleDetails::with_name(module_name).unwrap();
|
||||||
std::fs::canonicalize(&module_name)
|
let lib_start = module_details.range().base_address().0 as usize;
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
println!("removing address: {:#x}", lib_start + offset);
|
println!("removing address: {:#x}", lib_start + offset);
|
||||||
helper
|
helper
|
||||||
.ranges
|
.ranges
|
||||||
|
@ -18,7 +18,7 @@ pub struct DrCovBasicBlock {
|
|||||||
/// A writer for `DrCov` files
|
/// A writer for `DrCov` files
|
||||||
pub struct DrCovWriter<'a> {
|
pub struct DrCovWriter<'a> {
|
||||||
writer: BufWriter<File>,
|
writer: BufWriter<File>,
|
||||||
module_mapping: &'a RangeMap<usize, (u16, &'a str)>,
|
module_mapping: &'a RangeMap<usize, (u16, String)>,
|
||||||
basic_blocks: &'a mut Vec<DrCovBasicBlock>,
|
basic_blocks: &'a mut Vec<DrCovBasicBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ impl<'a> DrCovWriter<'a> {
|
|||||||
/// Create a new [`DrCovWriter`]
|
/// Create a new [`DrCovWriter`]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
path: &str,
|
path: &str,
|
||||||
module_mapping: &'a RangeMap<usize, (u16, &str)>,
|
module_mapping: &'a RangeMap<usize, (u16, String)>,
|
||||||
basic_blocks: &'a mut Vec<DrCovBasicBlock>,
|
basic_blocks: &'a mut Vec<DrCovBasicBlock>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -58,7 +58,7 @@ impl<'a> DrCovWriter<'a> {
|
|||||||
.write_all(b"DRCOV VERSION: 2\nDRCOV FLAVOR: libafl\n")
|
.write_all(b"DRCOV VERSION: 2\nDRCOV FLAVOR: libafl\n")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let modules: Vec<(&std::ops::Range<usize>, &(u16, &str))> =
|
let modules: Vec<(&std::ops::Range<usize>, &(u16, String))> =
|
||||||
self.module_mapping.iter().collect();
|
self.module_mapping.iter().collect();
|
||||||
self.writer
|
self.writer
|
||||||
.write_all(format!("Module Table: version 2, count {}\n", modules.len()).as_bytes())
|
.write_all(format!("Module Table: version 2, count {}\n", modules.len()).as_bytes())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user