Update frida (#1408)

* Update frida

* fix build

* aarch64

* fix aarch64 buid

* Fix CI

* move to git version of frida

* fix

* Frida frida frida
This commit is contained in:
Dominik Maier 2023-08-17 17:49:12 +02:00 committed by GitHub
parent b0179b4498
commit 35fa881ff0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 31 deletions

View File

@ -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 = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../libafl_bolts/" } libafl_bolts = { path = "../../libafl_bolts/" }
capstone = "0.11.0" 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_frida = { path = "../../libafl_frida", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] } libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libc = "0.2" libc = "0.2"

View File

@ -26,7 +26,7 @@ reqwest = { version = "0.11.4", features = ["blocking"] }
[dependencies] [dependencies]
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]} libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../libafl_bolts/" } 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_frida = { path = "../../libafl_frida", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] } libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libloading = "0.7" libloading = "0.7"

View File

@ -28,7 +28,7 @@ reqwest = { version = "0.11.4", features = ["blocking"] }
[dependencies] [dependencies]
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]} libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public", "frida_cli" ] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../libafl_bolts/" } 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_frida = { path = "../../libafl_frida", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] } libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] }
libloading = "0.7" libloading = "0.7"

View File

@ -28,8 +28,8 @@ nix = "0.26"
libc = "0.2" libc = "0.2"
hashbrown = "0.14" hashbrown = "0.14"
rangemap = "1.3" rangemap = "1.3"
frida-gum-sys = { version = "0.4.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.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" dynasmrt = "2"
capstone = "0.11.0" capstone = "0.11.0"
color-backtrace ={ version = "0.5", features = [ "resolve-modules" ] } color-backtrace ={ version = "0.5", features = [ "resolve-modules" ] }

View File

@ -16,7 +16,7 @@ use backtrace::Backtrace;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use capstone::{ use capstone::{
arch::{self, x86::X86OperandType, ArchOperand::X86Operand, BuildsCapstone}, arch::{self, x86::X86OperandType, ArchOperand::X86Operand, BuildsCapstone},
Capstone, Insn, RegAccessType, RegId, Capstone, RegAccessType, RegId,
}; };
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use capstone::{ use capstone::{
@ -25,7 +25,7 @@ use capstone::{
ArchOperand::Arm64Operand, ArchOperand::Arm64Operand,
BuildsCapstone, BuildsCapstone,
}, },
Capstone, Insn, Capstone,
}; };
use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -36,6 +36,8 @@ use frida_gum::{
instruction_writer::InstructionWriter, interceptor::Interceptor, stalker::StalkerOutput, Gum, instruction_writer::InstructionWriter, interceptor::Interceptor, stalker::StalkerOutput, Gum,
Module, ModuleDetails, ModuleMap, NativePointer, RangeDetails, Module, ModuleDetails, ModuleMap, NativePointer, RangeDetails,
}; };
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use frida_gum_sys::Insn;
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl_bolts::{cli::FuzzerOptions, AsSlice}; use libafl_bolts::{cli::FuzzerOptions, AsSlice};
#[cfg(unix)] #[cfg(unix)]
@ -48,6 +50,8 @@ use libc::{getrlimit64, rlimit64};
use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::mman::{mmap, MapFlags, ProtFlags};
use rangemap::RangeMap; use rangemap::RangeMap;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use crate::utils::frida_to_cs;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::utils::instruction_width; use crate::utils::instruction_width;
use crate::{ use crate::{
@ -1094,7 +1098,7 @@ impl AsanRuntime {
3, 3,
) )
.unwrap(); .unwrap();
let instructions = instructions.iter().collect::<Vec<&Insn>>(); let instructions = instructions.iter().collect::<Vec<&capstone::Insn>>();
let mut insn = instructions.first().unwrap(); let mut insn = instructions.first().unwrap();
if insn.mnemonic().unwrap() == "msr" && insn.op_str().unwrap() == "nzcv, x0" { if insn.mnemonic().unwrap() == "msr" && insn.op_str().unwrap() == "nzcv, x0" {
insn = instructions.get(2).unwrap(); insn = instructions.get(2).unwrap();
@ -2206,9 +2210,13 @@ impl AsanRuntime {
Arm64Shift, Arm64Shift,
Arm64Extender, 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 // We have to ignore these instructions. Simulating them with their side effects is
// complex, to say the least. // complex, to say the least.
match instr.mnemonic().unwrap() { match cs_instr.mnemonic().unwrap() {
"ldaxr" | "stlxr" | "ldxr" | "stxr" | "ldar" | "stlr" | "ldarb" | "ldarh" | "ldaxp" "ldaxr" | "stlxr" | "ldxr" | "stxr" | "ldar" | "stlr" | "ldarb" | "ldarh" | "ldaxp"
| "ldaxrb" | "ldaxrh" | "stlrb" | "stlrh" | "stlxp" | "stlxrb" | "stlxrh" | "ldxrb" | "ldaxrb" | "ldaxrh" | "stlrb" | "stlrh" | "stlxp" | "stlxrb" | "stlxrh" | "ldxrb"
| "ldxrh" | "stxrb" | "stxrh" => return None, | "ldxrh" | "stxrb" | "stxrh" => return None,
@ -2216,7 +2224,7 @@ impl AsanRuntime {
} }
let operands = capstone let operands = capstone
.insn_detail(instr) .insn_detail(cs_instr)
.unwrap() .unwrap()
.arch_detail() .arch_detail()
.operands(); .operands();
@ -2230,7 +2238,7 @@ impl AsanRuntime {
opmem.base(), opmem.base(),
opmem.index(), opmem.index(),
opmem.disp(), opmem.disp(),
instruction_width(instr, &operands), instruction_width(cs_instr, &operands),
arm64operand.shift, arm64operand.shift,
arm64operand.ext, arm64operand.ext,
)); ));
@ -2250,15 +2258,18 @@ impl AsanRuntime {
_address: u64, _address: u64,
instr: &Insn, instr: &Insn,
) -> Option<(RegId, u8, RegId, RegId, i32, i64)> { ) -> 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 let operands = capstone
.insn_detail(instr) .insn_detail(cs_instr)
.unwrap() .unwrap()
.arch_detail() .arch_detail()
.operands(); .operands();
// Ignore lea instruction // Ignore lea instruction
// put nop into the white-list so that instructions like // put nop into the white-list so that instructions like
// like `nop dword [rax + rax]` does not get caught. // like `nop dword [rax + rax]` does not get caught.
match instr.mnemonic().unwrap() { match cs_instr.mnemonic().unwrap() {
"lea" | "nop" => return None, "lea" | "nop" => return None,
_ => (), _ => (),
@ -2266,7 +2277,7 @@ impl AsanRuntime {
// This is a TODO! In this case, both the src and the dst are mem operand // This is a TODO! In this case, both the src and the dst are mem operand
// so we would need to return two operadns? // 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; return None;
} }
@ -2317,9 +2328,9 @@ impl AsanRuntime {
basereg: RegId, basereg: RegId,
indexreg: RegId, indexreg: RegId,
scale: i32, 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 writer = output.writer();
let true_rip = address; let true_rip = address;

View File

@ -24,9 +24,11 @@ use frida_gum::{
instruction_writer::{Aarch64Register, IndexMode, InstructionWriter}, instruction_writer::{Aarch64Register, IndexMode, InstructionWriter},
stalker::StalkerOutput, stalker::StalkerOutput,
}; };
#[cfg(target_arch = "aarch64")]
use frida_gum_sys::Insn;
#[cfg(all(feature = "cmplog", target_arch = "aarch64"))] #[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"))] #[cfg(all(feature = "cmplog", target_arch = "aarch64"))]
/// Speciial `CmpLog` Cases for `aarch64` /// Speciial `CmpLog` Cases for `aarch64`
@ -41,7 +43,7 @@ pub enum SpecialCmpLogCase {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use capstone::{ use capstone::{
arch::{arm64::Arm64OperandType, ArchOperand::Arm64Operand}, arch::{arm64::Arm64OperandType, ArchOperand::Arm64Operand},
Capstone, Insn, Capstone,
}; };
/// The [`frida_gum_sys::GUM_RED_ZONE_SIZE`] casted to [`i32`] /// The [`frida_gum_sys::GUM_RED_ZONE_SIZE`] casted to [`i32`]
@ -599,14 +601,18 @@ impl CmpLogRuntime {
CmplogOperandType, CmplogOperandType,
Option<SpecialCmpLogCase>, 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 // 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" "cmp" | "ands" | "subs" | "adds" | "negs" | "ngcs" | "sbcs" | "bics" | "cbz"
| "cbnz" | "tbz" | "tbnz" | "adcs" => (), | "cbnz" | "tbz" | "tbnz" | "adcs" => (),
_ => return None, _ => return None,
} }
let mut operands = capstone let mut operands = capstone
.insn_detail(instr) .insn_detail(cs_instr)
.unwrap() .unwrap()
.arch_detail() .arch_detail()
.operands(); .operands();
@ -615,20 +621,21 @@ impl CmpLogRuntime {
let special_case = [ let special_case = [
"cbz", "cbnz", "tbz", "tbnz", "subs", "adds", "ands", "sbcs", "bics", "adcs", "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 { if operands.len() != 2 && !special_case {
return None; return None;
} }
// handle special opcodes case which have 3 operands, but the 1st(dest) is not important to us // 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 //remove the dest operand from the list
operands.remove(0); operands.remove(0);
} }
// cbz marked as special since there is only 1 operand // cbz marked as special since there is only 1 operand
#[allow(clippy::cast_sign_loss)] #[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)] #[allow(clippy::cast_sign_loss, clippy::similar_names)]
let operand1 = if let Arm64Operand(arm64operand) = operands.first().unwrap() { let operand1 = if let Arm64Operand(arm64operand) = operands.first().unwrap() {
@ -639,7 +646,7 @@ impl CmpLogRuntime {
opmem.base(), opmem.base(),
opmem.index(), opmem.index(),
opmem.disp(), opmem.disp(),
instruction_width(instr, &operands), instruction_width(cs_instr, &operands),
)), )),
Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)), Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)),
_ => return None, _ => return None,
@ -659,7 +666,7 @@ impl CmpLogRuntime {
opmem.base(), opmem.base(),
opmem.index(), opmem.index(),
opmem.disp(), opmem.disp(),
instruction_width(instr, &operands), instruction_width(cs_instr, &operands),
)), )),
Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)), Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)),
_ => return None, _ => return None,
@ -669,7 +676,7 @@ impl CmpLogRuntime {
}; };
// tbz will need to have special handling at emit time(masking operand1 value with operand2) // 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), "tbz" => Some(SpecialCmpLogCase::Tbz),
"tbnz" => Some(SpecialCmpLogCase::Tbnz), "tbnz" => Some(SpecialCmpLogCase::Tbnz),
_ => None, _ => None,

View File

@ -298,8 +298,14 @@ where
if let Some((segment, width, basereg, indexreg, scale, disp)) = res { if let Some((segment, width, basereg, indexreg, scale, disp)) = res {
if let Some(rt) = runtimes.match_first_type_mut::<AsanRuntime>() { if let Some(rt) = runtimes.match_first_type_mut::<AsanRuntime>() {
rt.emit_shadow_check( rt.emit_shadow_check(
address, &output, segment, width, basereg, indexreg, scale, address,
disp, &output,
segment,
width,
basereg,
indexreg,
scale,
disp.try_into().unwrap(),
); );
} }
} }
@ -325,9 +331,7 @@ where
if let Some(rt) = runtimes.match_first_type_mut::<CmpLogRuntime>() { if let Some(rt) = runtimes.match_first_type_mut::<CmpLogRuntime>() {
if let Some((op1, op2, special_case)) = if let Some((op1, op2, special_case)) =
CmpLogRuntime::cmplog_is_interesting_instruction( CmpLogRuntime::cmplog_is_interesting_instruction(
&helper.capstone, &capstone, address, instr,
address,
instr,
) )
{ {
//emit code that saves the relevant data in runtime(passes it to x0, x1) //emit code that saves the relevant data in runtime(passes it to x0, x1)

View File

@ -1,3 +1,5 @@
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use capstone::Capstone;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use capstone::{ use capstone::{
arch::{self, arm64::Arm64OperandType, ArchOperand::Arm64Operand}, arch::{self, arm64::Arm64OperandType, ArchOperand::Arm64Operand},
@ -7,6 +9,8 @@ use capstone::{
use frida_gum::instruction_writer::Aarch64Register; use frida_gum::instruction_writer::Aarch64Register;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use frida_gum::instruction_writer::X86Register; use frida_gum::instruction_writer::X86Register;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use frida_gum_sys;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use num_traits::cast::FromPrimitive; use num_traits::cast::FromPrimitive;
@ -132,3 +136,15 @@ pub fn writer_register(reg: capstone::RegId) -> X86Register {
_ => X86Register::None, // Ignore Xax..Xip _ => 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()
}