Skip to content

Commit

Permalink
Update frida (#1408)
Browse files Browse the repository at this point in the history
* Update frida

* fix build

* aarch64

* fix aarch64 buid

* Fix CI

* move to git version of frida

* fix

* Frida frida frida
  • Loading branch information
domenukk authored and addisoncrump committed Aug 22, 2023
1 parent b0a6629 commit 15fb9b4
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 31 deletions.
2 changes: 1 addition & 1 deletion fuzzers/frida_executable_libpng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ reqwest = { version = "0.11.4", features = ["blocking"] }
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../libafl_bolts/" }
capstone = "0.11.0"
frida-gum = { version = "0.8.1", features = [ "auto-download", "event-sink", "invocation-listener"] }
frida-gum = { version = "0.13.2", features = [ "auto-download", "event-sink", "invocation-listener"] }
libafl_frida = { path = "../../libafl_frida", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libc = "0.2"
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/frida_gdiplus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ reqwest = { version = "0.11.4", features = ["blocking"] }
[dependencies]
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../libafl_bolts/" }
frida-gum = { version = "0.8.1", features = [ "auto-download", "event-sink", "invocation-listener"] }
frida-gum = { version = "0.13.2", features = [ "auto-download", "event-sink", "invocation-listener"] }
libafl_frida = { path = "../../libafl_frida", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libloading = "0.7"
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/frida_libpng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ reqwest = { version = "0.11.4", features = ["blocking"] }
[dependencies]
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../libafl_bolts/" }
frida-gum = { version = "0.8.1", features = [ "auto-download", "event-sink", "invocation-listener"] }
frida-gum = { version = "0.13.2", features = [ "auto-download", "event-sink", "invocation-listener"] }
libafl_frida = { path = "../../libafl_frida", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libloading = "0.7"
Expand Down
4 changes: 2 additions & 2 deletions libafl_frida/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ nix = "0.26"
libc = "0.2"
hashbrown = "0.14"
rangemap = "1.3"
frida-gum-sys = { version = "0.4.1", features = [ "auto-download", "event-sink", "invocation-listener"] }
frida-gum = { version = "0.8.1", features = [ "auto-download", "event-sink", "invocation-listener"] }
frida-gum-sys = { version = "0.8.1", features = [ "auto-download", "event-sink", "invocation-listener"] }
frida-gum = { version = "0.13.2", features = [ "auto-download", "event-sink", "invocation-listener", "module-names"] }
dynasmrt = "2"
capstone = "0.11.0"
color-backtrace ={ version = "0.5", features = [ "resolve-modules" ] }
Expand Down
33 changes: 22 additions & 11 deletions libafl_frida/src/asan/asan_rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use backtrace::Backtrace;
#[cfg(target_arch = "x86_64")]
use capstone::{
arch::{self, x86::X86OperandType, ArchOperand::X86Operand, BuildsCapstone},
Capstone, Insn, RegAccessType, RegId,
Capstone, RegAccessType, RegId,
};
#[cfg(target_arch = "aarch64")]
use capstone::{
Expand All @@ -25,7 +25,7 @@ use capstone::{
ArchOperand::Arm64Operand,
BuildsCapstone,
},
Capstone, Insn,
Capstone,
};
use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};
#[cfg(target_arch = "x86_64")]
Expand All @@ -36,6 +36,8 @@ use frida_gum::{
instruction_writer::InstructionWriter, interceptor::Interceptor, stalker::StalkerOutput, Gum,
Module, ModuleDetails, ModuleMap, NativePointer, RangeDetails,
};
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use frida_gum_sys::Insn;
use hashbrown::HashMap;
use libafl_bolts::{cli::FuzzerOptions, AsSlice};
#[cfg(unix)]
Expand All @@ -48,6 +50,8 @@ use libc::{getrlimit64, rlimit64};
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
use rangemap::RangeMap;

#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use crate::utils::frida_to_cs;
#[cfg(target_arch = "aarch64")]
use crate::utils::instruction_width;
use crate::{
Expand Down Expand Up @@ -1094,7 +1098,7 @@ impl AsanRuntime {
3,
)
.unwrap();
let instructions = instructions.iter().collect::<Vec<&Insn>>();
let instructions = instructions.iter().collect::<Vec<&capstone::Insn>>();
let mut insn = instructions.first().unwrap();
if insn.mnemonic().unwrap() == "msr" && insn.op_str().unwrap() == "nzcv, x0" {
insn = instructions.get(2).unwrap();
Expand Down Expand Up @@ -2206,17 +2210,21 @@ impl AsanRuntime {
Arm64Shift,
Arm64Extender,
)> {
// We need to re-decode frida-internal capstone values to upstream capstone
let cs_instr = frida_to_cs(capstone, instr);
let cs_instr = cs_instr.first().unwrap();

// We have to ignore these instructions. Simulating them with their side effects is
// complex, to say the least.
match instr.mnemonic().unwrap() {
match cs_instr.mnemonic().unwrap() {
"ldaxr" | "stlxr" | "ldxr" | "stxr" | "ldar" | "stlr" | "ldarb" | "ldarh" | "ldaxp"
| "ldaxrb" | "ldaxrh" | "stlrb" | "stlrh" | "stlxp" | "stlxrb" | "stlxrh" | "ldxrb"
| "ldxrh" | "stxrb" | "stxrh" => return None,
_ => (),
}

let operands = capstone
.insn_detail(instr)
.insn_detail(cs_instr)
.unwrap()
.arch_detail()
.operands();
Expand All @@ -2230,7 +2238,7 @@ impl AsanRuntime {
opmem.base(),
opmem.index(),
opmem.disp(),
instruction_width(instr, &operands),
instruction_width(cs_instr, &operands),
arm64operand.shift,
arm64operand.ext,
));
Expand All @@ -2250,23 +2258,26 @@ impl AsanRuntime {
_address: u64,
instr: &Insn,
) -> Option<(RegId, u8, RegId, RegId, i32, i64)> {
// We need to re-decode frida-internal capstone values to upstream capstone
let cs_instr = frida_to_cs(capstone, instr);
let cs_instr = cs_instr.first().unwrap();
let operands = capstone
.insn_detail(instr)
.insn_detail(cs_instr)
.unwrap()
.arch_detail()
.operands();
// Ignore lea instruction
// put nop into the white-list so that instructions like
// like `nop dword [rax + rax]` does not get caught.
match instr.mnemonic().unwrap() {
match cs_instr.mnemonic().unwrap() {
"lea" | "nop" => return None,

_ => (),
}

// This is a TODO! In this case, both the src and the dst are mem operand
// so we would need to return two operadns?
if instr.mnemonic().unwrap().starts_with("rep") {
if cs_instr.mnemonic().unwrap().starts_with("rep") {
return None;
}

Expand Down Expand Up @@ -2317,9 +2328,9 @@ impl AsanRuntime {
basereg: RegId,
indexreg: RegId,
scale: i32,
disp: i64,
disp: isize,
) {
let redzone_size = i64::from(frida_gum_sys::GUM_RED_ZONE_SIZE);
let redzone_size = isize::try_from(frida_gum_sys::GUM_RED_ZONE_SIZE).unwrap();
let writer = output.writer();
let true_rip = address;

Expand Down
27 changes: 17 additions & 10 deletions libafl_frida/src/cmplog_rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ use frida_gum::{
instruction_writer::{Aarch64Register, IndexMode, InstructionWriter},
stalker::StalkerOutput,
};
#[cfg(target_arch = "aarch64")]
use frida_gum_sys::Insn;

#[cfg(all(feature = "cmplog", target_arch = "aarch64"))]
use crate::utils::{instruction_width, writer_register};
use crate::utils::{frida_to_cs, instruction_width, writer_register};

#[cfg(all(feature = "cmplog", target_arch = "aarch64"))]
/// Speciial `CmpLog` Cases for `aarch64`
Expand All @@ -41,7 +43,7 @@ pub enum SpecialCmpLogCase {
#[cfg(target_arch = "aarch64")]
use capstone::{
arch::{arm64::Arm64OperandType, ArchOperand::Arm64Operand},
Capstone, Insn,
Capstone,
};

/// The [`frida_gum_sys::GUM_RED_ZONE_SIZE`] casted to [`i32`]
Expand Down Expand Up @@ -599,14 +601,18 @@ impl CmpLogRuntime {
CmplogOperandType,
Option<SpecialCmpLogCase>,
)> {
// We need to re-decode frida-internal capstone values to upstream capstone
let cs_instr = frida_to_cs(capstone, instr);
let cs_instr = cs_instr.first().unwrap();

// We only care for compare instructions - aka instructions which set the flags
match instr.mnemonic().unwrap() {
match cs_instr.mnemonic().unwrap() {
"cmp" | "ands" | "subs" | "adds" | "negs" | "ngcs" | "sbcs" | "bics" | "cbz"
| "cbnz" | "tbz" | "tbnz" | "adcs" => (),
_ => return None,
}
let mut operands = capstone
.insn_detail(instr)
.insn_detail(cs_instr)
.unwrap()
.arch_detail()
.operands();
Expand All @@ -615,20 +621,21 @@ impl CmpLogRuntime {
let special_case = [
"cbz", "cbnz", "tbz", "tbnz", "subs", "adds", "ands", "sbcs", "bics", "adcs",
]
.contains(&instr.mnemonic().unwrap());
.contains(&cs_instr.mnemonic().unwrap());
if operands.len() != 2 && !special_case {
return None;
}

// handle special opcodes case which have 3 operands, but the 1st(dest) is not important to us
if ["subs", "adds", "ands", "sbcs", "bics", "adcs"].contains(&instr.mnemonic().unwrap()) {
if ["subs", "adds", "ands", "sbcs", "bics", "adcs"].contains(&cs_instr.mnemonic().unwrap())
{
//remove the dest operand from the list
operands.remove(0);
}

// cbz marked as special since there is only 1 operand
#[allow(clippy::cast_sign_loss)]
let special_case = matches!(instr.mnemonic().unwrap(), "cbz" | "cbnz");
let special_case = matches!(cs_instr.mnemonic().unwrap(), "cbz" | "cbnz");

#[allow(clippy::cast_sign_loss, clippy::similar_names)]
let operand1 = if let Arm64Operand(arm64operand) = operands.first().unwrap() {
Expand All @@ -639,7 +646,7 @@ impl CmpLogRuntime {
opmem.base(),
opmem.index(),
opmem.disp(),
instruction_width(instr, &operands),
instruction_width(cs_instr, &operands),
)),
Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)),
_ => return None,
Expand All @@ -659,7 +666,7 @@ impl CmpLogRuntime {
opmem.base(),
opmem.index(),
opmem.disp(),
instruction_width(instr, &operands),
instruction_width(cs_instr, &operands),
)),
Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)),
_ => return None,
Expand All @@ -669,7 +676,7 @@ impl CmpLogRuntime {
};

// tbz will need to have special handling at emit time(masking operand1 value with operand2)
let special_case = match instr.mnemonic().unwrap() {
let special_case = match cs_instr.mnemonic().unwrap() {
"tbz" => Some(SpecialCmpLogCase::Tbz),
"tbnz" => Some(SpecialCmpLogCase::Tbnz),
_ => None,
Expand Down
14 changes: 9 additions & 5 deletions libafl_frida/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,14 @@ where
if let Some((segment, width, basereg, indexreg, scale, disp)) = res {
if let Some(rt) = runtimes.match_first_type_mut::<AsanRuntime>() {
rt.emit_shadow_check(
address, &output, segment, width, basereg, indexreg, scale,
disp,
address,
&output,
segment,
width,
basereg,
indexreg,
scale,
disp.try_into().unwrap(),
);
}
}
Expand All @@ -325,9 +331,7 @@ where
if let Some(rt) = runtimes.match_first_type_mut::<CmpLogRuntime>() {
if let Some((op1, op2, special_case)) =
CmpLogRuntime::cmplog_is_interesting_instruction(
&helper.capstone,
address,
instr,
&capstone, address, instr,
)
{
//emit code that saves the relevant data in runtime(passes it to x0, x1)
Expand Down
16 changes: 16 additions & 0 deletions libafl_frida/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use capstone::Capstone;
#[cfg(target_arch = "aarch64")]
use capstone::{
arch::{self, arm64::Arm64OperandType, ArchOperand::Arm64Operand},
Expand All @@ -7,6 +9,8 @@ use capstone::{
use frida_gum::instruction_writer::Aarch64Register;
#[cfg(target_arch = "x86_64")]
use frida_gum::instruction_writer::X86Register;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use frida_gum_sys;
#[cfg(target_arch = "aarch64")]
use num_traits::cast::FromPrimitive;

Expand Down Expand Up @@ -132,3 +136,15 @@ pub fn writer_register(reg: capstone::RegId) -> X86Register {
_ => X86Register::None, // Ignore Xax..Xip
}
}

/// Translates a frida instruction to a capstone instruction.
/// Returns a [`capstone::Instructions`] with a single [`capstone::Insn`] inside.
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
pub(crate) fn frida_to_cs<'a>(
capstone: &'a Capstone,
frida_insn: &frida_gum_sys::Insn,
) -> capstone::Instructions<'a> {
capstone
.disasm_count(frida_insn.bytes(), frida_insn.address(), 1)
.unwrap()
}

0 comments on commit 15fb9b4

Please sign in to comment.