Remove capstone from frida [x86_64] (#1720)

* init

* more

* just fixing stuff
This commit is contained in:
Dongjia "toka" Zhang 2023-12-16 02:39:11 +09:00 committed by GitHub
parent ee447468c6
commit a0a4dd60bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 328 additions and 269 deletions

View File

@ -20,7 +20,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -21,7 +21,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''
@ -34,7 +34,7 @@ windows_alias = "unsupported"
[tasks.lib_unix]
script_runner="@shell"
script='''
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes --disable-dependency-tracking
cd ..
make -C libpng-1.6.37
'''

View File

@ -38,7 +38,7 @@ You can also fuzz libpng-1.6.37 on windows with frida mode
### To build it with visual studio
1. Install clang for windows (make sure you add LLVM to the system path!)
[https://github.com/llvm/llvm-project/releases/tag/llvmorg-12.0.1](https://github.com/llvm/llvm-project/releases/tag/llvmorg-12.0.1)
2. Download libpng-1.6.37[https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz] and zlib [https://zlib.net/fossils/zlib-1.2.11.tar.gz] into this directory, and rename `zlib-1.2.11` directory to `zlib`.
2. Download libpng-1.6.37[https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz] and zlib [https://zlib.net/fossils/zlib-1.2.11.tar.gz] into this directory, and rename `zlib-1.2.11` directory to `zlib`.
3. Build libpng1.6.37
- Open libpng-1.6.37/projects/vstudio/vstudio.sln

View File

@ -465,7 +465,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
.run_client(&mut run_client)
.cores(&options.cores)
.broker_port(options.broker_port)
.stdout_file(Some(&options.stdout))
// .stdout_file(Some(&options.stdout))
.remote_broker_addr(options.remote_broker_addr)
.build()
.launch()

View File

@ -21,7 +21,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = [ "./libpng-1.6.37" ] }
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -21,7 +21,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = [ "./libpng-1.6.37" ] }
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
curl https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz --output libpng-1.6.37.tar.xz
curl https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz --output libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -26,7 +26,7 @@ The compiler wrappers, `libafl_cc` and `libafl_cxx`, will end up in `./target/re
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -19,7 +19,7 @@ In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(li
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
curl https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz --output libpng-1.6.37.tar.xz
curl https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz --output libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -19,7 +19,7 @@ The compiler wrappers, `libafl_cc` and `libafl_cxx`, will end up in `./target/re
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -19,7 +19,7 @@ In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(li
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
curl https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz --output libpng-1.6.37.tar.xz
curl https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz --output libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -26,7 +26,7 @@ The compiler wrappers, `libafl_cc` and libafl_cxx`, will end up in `./target/rel
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -19,7 +19,7 @@ In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(li
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -26,7 +26,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -19,7 +19,7 @@ In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(li
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -19,7 +19,7 @@ In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(li
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
curl https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz --output libpng-1.6.37.tar.xz
curl https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz --output libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -26,7 +26,7 @@ The compiler wrappers, `libafl_cc` and `libafl_cxx`, will end up in `./target/re
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```

View File

@ -25,7 +25,7 @@ The compiler wrappers, `libafl_cc` and `libafl_cxx`, will end up in `./target/re
Then download libpng, and unpack the archive:
```bash
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
```
Run `patch libpng-1.6.37/png.c diff.patch` before compiling the libpng

View File

@ -25,7 +25,7 @@ windows_alias = "unsupported"
condition = { files_not_exist = ["./libpng-1.6.37"]}
script_runner="@shell"
script='''
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf libpng-1.6.37.tar.xz
'''

View File

@ -146,7 +146,7 @@ script_runner="@shell"
script='''
wget \
-O "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/deps/libpng-1.6.37.tar.xz" \
https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar \
-xvf "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/deps/libpng-1.6.37.tar.xz" \

View File

@ -146,7 +146,7 @@ script_runner="@shell"
script='''
wget \
-O "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/deps/libpng-1.6.37.tar.xz" \
https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar \
-xvf "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/deps/libpng-1.6.37.tar.xz" \

View File

@ -146,7 +146,7 @@ script_runner="@shell"
script='''
wget \
-O "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/deps/libpng-1.6.37.tar.xz" \
https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar \
-xvf "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/deps/libpng-1.6.37.tar.xz" \

View File

@ -1,17 +1,19 @@
use std::error::Error;
#[rustversion::nightly]
#[allow(clippy::unnecessary_wraps)]
fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-cfg=nightly");
#[cfg(feature = "unicode")]
{
build_unicode_property_map()?;
// build_unicode_property_map()?;
}
Ok(())
}
#[rustversion::not(nightly)]
#[allow(clippy::unnecessary_wraps)]
fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rerun-if-changed=build.rs");
assert!(
@ -20,7 +22,7 @@ fn main() -> Result<(), Box<dyn Error>> {
);
#[cfg(feature = "unicode")]
{
build_unicode_property_map()?;
// build_unicode_property_map()?;
}
Ok(())
}

View File

@ -28,6 +28,13 @@ serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"]
[build-dependencies]
cc = { version = "1.0", features = ["parallel"] }
[target.'cfg(target_arch = "aarch64")'.dependencies]
capstone = "0.11.0"
[target.'cfg(target_arch = "x86_64")'.dependencies]
yaxpeax-x86 = { git = "https://github.com/tokatoka/yaxpeax-x86/" } # replace this with origin later
yaxpeax-arch = "0.2.7"
[dependencies]
libafl = { path = "../libafl", default-features = false, version = "0.11.1", features = [
"std",
@ -60,7 +67,6 @@ frida-gum = { version = "0.13.2", features = [
"module-names",
] }
dynasmrt = "2"
capstone = "0.11.0"
color-backtrace = { version = "0.6", features = ["resolve-modules"] }
termcolor = "1.1.3"
serde = "1.0"

View File

@ -13,11 +13,6 @@ use core::{
use std::{ffi::c_void, num::NonZeroUsize, ptr::write_volatile, rc::Rc};
use backtrace::Backtrace;
#[cfg(target_arch = "x86_64")]
use capstone::{
arch::{self, x86::X86OperandType, ArchOperand::X86Operand, BuildsCapstone},
Capstone, RegAccessType, RegId,
};
#[cfg(target_arch = "aarch64")]
use capstone::{
arch::{
@ -49,16 +44,20 @@ use libc::{getrlimit, rlimit};
use libc::{getrlimit64, rlimit64};
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
use rangemap::RangeMap;
#[cfg(target_arch = "x86_64")]
use yaxpeax_x86::amd64::{InstDecoder, Instruction, Opcode};
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use crate::utils::frida_to_cs;
#[cfg(target_arch = "aarch64")]
use crate::utils::instruction_width;
#[cfg(target_arch = "x86_64")]
use crate::utils::operand_details;
use crate::{
alloc::Allocator,
asan::errors::{AsanError, AsanErrors, AsanReadWriteError, ASAN_ERRORS},
helper::{FridaRuntime, SkipRange},
utils::writer_register,
utils::{disas_count, AccessType},
};
extern "C" {
@ -922,32 +921,30 @@ impl AsanRuntime {
let fault_address = self.regs[17];
let actual_pc = self.regs[18];
let cs = Capstone::new()
.x86()
.mode(arch::x86::ArchMode::Mode64)
.detail(true)
.build()
.expect("Failed to create Capstone object");
let decoder = InstDecoder::minimal();
let instructions = cs
.disasm_count(
unsafe { std::slice::from_raw_parts(actual_pc as *mut u8, 24) },
actual_pc as u64,
3,
)
.expect("Failed to disassmeble");
let instructions: Vec<Instruction> = disas_count(
&decoder,
unsafe { std::slice::from_raw_parts(actual_pc as *mut u8, 24) },
3,
);
let insn = instructions.as_ref().first().unwrap(); // This is the very instruction that has triggered fault
let insn = instructions[0]; // This is the very instruction that has triggered fault
log::info!("{insn:#?}");
let operands = cs.insn_detail(insn).unwrap().arch_detail().operands();
let operand_count = insn.operand_count();
let mut access_type: Option<RegAccessType> = None;
let mut regs: Option<(RegId, RegId, i64)> = None;
for operand in operands {
if let X86Operand(x86operand) = operand {
if let X86OperandType::Mem(mem) = x86operand.op_type {
access_type = x86operand.access;
regs = Some((mem.base(), mem.index(), mem.disp()));
let mut access_type: Option<AccessType> = None;
let mut regs: Option<(X86Register, X86Register, i32)> = None;
for operand_idx in 0..operand_count {
let operand = insn.operand(operand_idx);
if operand.is_memory() {
access_type = if operand_idx == 0 {
Some(AccessType::Read)
} else {
Some(AccessType::Write)
};
if let Some((basereg, indexreg, _, disp)) = operand_details(&operand) {
regs = Some((basereg, indexreg, disp));
}
}
}
@ -956,22 +953,24 @@ impl AsanRuntime {
let (stack_start, stack_end) = Self::current_stack();
if let Some(r) = regs {
let (base_idx, size) = self.register_idx(r.0); // safe to unwrap
let (index_idx, _) = self.register_idx(r.1);
let base = self.register_idx(r.0); // safe to unwrap
let index = self.register_idx(r.1);
let disp = r.2;
// from capstone register id to self.regs's index
let base_value = match base_idx {
Some(base) => match size {
Some(sz) => {
if sz == 64 {
Some(self.regs[base as usize])
} else {
Some(self.regs[base as usize] & 0xffffffff)
}
}
_ => None,
},
let (base_idx, base_value) = match base {
Some((idx, size)) => {
let value = if size == 64 {
Some(self.regs[idx as usize])
} else {
Some(self.regs[idx as usize] & 0xffffffff)
};
(Some(idx), value)
}
_ => (None, None),
};
let index_idx = match index {
Some((idx, _)) => Some(idx),
_ => None,
};
@ -980,13 +979,13 @@ impl AsanRuntime {
let error = if fault_address >= stack_start && fault_address < stack_end {
match access_type {
Some(typ) => match typ {
RegAccessType::ReadOnly => AsanError::StackOobRead((
AccessType::Read => AsanError::StackOobRead((
self.regs,
actual_pc,
(base_idx, index_idx, disp as usize, fault_address),
backtrace,
)),
_ => AsanError::StackOobWrite((
AccessType::Write => AsanError::StackOobWrite((
self.regs,
actual_pc,
(base_idx, index_idx, disp as usize, fault_address),
@ -1015,14 +1014,14 @@ impl AsanRuntime {
backtrace,
};
match typ {
RegAccessType::ReadOnly => {
AccessType::Read => {
if metadata.freed {
AsanError::ReadAfterFree(asan_readwrite_error)
} else {
AsanError::OobRead(asan_readwrite_error)
}
}
_ => {
AccessType::Write => {
if metadata.freed {
AsanError::WriteAfterFree(asan_readwrite_error)
} else {
@ -1245,43 +1244,43 @@ impl AsanRuntime {
#[cfg(target_arch = "x86_64")]
#[allow(clippy::unused_self)]
fn register_idx(&self, capid: RegId) -> (Option<u16>, Option<u16>) {
match capid.0 {
19 => (Some(0), Some(32)),
22 => (Some(2), Some(32)),
24 => (Some(3), Some(32)),
21 => (Some(1), Some(32)),
30 => (Some(5), Some(32)),
20 => (Some(4), Some(32)),
29 => (Some(6), Some(32)),
23 => (Some(7), Some(32)),
226 => (Some(8), Some(32)),
227 => (Some(9), Some(32)),
228 => (Some(10), Some(32)),
229 => (Some(11), Some(32)),
230 => (Some(12), Some(32)),
231 => (Some(13), Some(32)),
232 => (Some(14), Some(32)),
233 => (Some(15), Some(32)),
26 => (Some(18), Some(32)),
35 => (Some(0), Some(64)),
38 => (Some(2), Some(64)),
40 => (Some(3), Some(64)),
37 => (Some(1), Some(64)),
44 => (Some(5), Some(64)),
36 => (Some(4), Some(64)),
43 => (Some(6), Some(64)),
39 => (Some(7), Some(64)),
106 => (Some(8), Some(64)),
107 => (Some(9), Some(64)),
108 => (Some(10), Some(64)),
109 => (Some(11), Some(64)),
110 => (Some(12), Some(64)),
111 => (Some(13), Some(64)),
112 => (Some(14), Some(64)),
113 => (Some(15), Some(64)),
41 => (Some(18), Some(64)),
_ => (None, None),
fn register_idx(&self, reg: X86Register) -> Option<(u16, u16)> {
match reg {
X86Register::Eax => Some((0, 32)),
X86Register::Ecx => Some((2, 32)),
X86Register::Edx => Some((3, 32)),
X86Register::Ebx => Some((1, 32)),
X86Register::Esp => Some((5, 32)),
X86Register::Ebp => Some((4, 32)),
X86Register::Esi => Some((6, 32)),
X86Register::Edi => Some((7, 32)),
X86Register::R8d => Some((8, 32)),
X86Register::R9d => Some((9, 32)),
X86Register::R10d => Some((10, 32)),
X86Register::R11d => Some((11, 32)),
X86Register::R12d => Some((12, 32)),
X86Register::R13d => Some((13, 32)),
X86Register::R14d => Some((14, 32)),
X86Register::R15d => Some((15, 32)),
X86Register::Eip => Some((18, 32)),
X86Register::Rax => Some((0, 4)),
X86Register::Rcx => Some((2, 4)),
X86Register::Rdx => Some((3, 4)),
X86Register::Rbx => Some((1, 4)),
X86Register::Rsp => Some((5, 4)),
X86Register::Rbp => Some((4, 4)),
X86Register::Rsi => Some((6, 4)),
X86Register::Rdi => Some((7, 4)),
X86Register::R8 => Some((8, 64)),
X86Register::R9 => Some((9, 64)),
X86Register::R10 => Some((10, 64)),
X86Register::R11 => Some((11, 64)),
X86Register::R12 => Some((12, 64)),
X86Register::R13 => Some((13, 64)),
X86Register::R14 => Some((14, 64)),
X86Register::R15 => Some((15, 64)),
X86Register::Rip => Some((18, 64)),
_ => None,
}
}
@ -2248,60 +2247,46 @@ impl AsanRuntime {
#[must_use]
#[allow(clippy::result_unit_err)]
pub fn asan_is_interesting_instruction(
capstone: &Capstone,
decoder: InstDecoder,
_address: u64,
instr: &Insn,
) -> Option<(RegId, u8, RegId, RegId, i32, i64)> {
) -> Option<(u8, X86Register, X86Register, u8, i32)> {
// 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(cs_instr)
.unwrap()
.arch_detail()
.operands();
let cs_instr = frida_to_cs(decoder, instr);
let mut operands = vec![];
for operand_idx in 0..cs_instr.operand_count() {
operands.push(cs_instr.operand(operand_idx));
}
// Ignore lea instruction
// put nop into the white-list so that instructions like
// like `nop dword [rax + rax]` does not get caught.
match cs_instr.mnemonic().unwrap() {
"lea" | "nop" => return None,
match cs_instr.opcode() {
Opcode::LEA | Opcode::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 cs_instr.mnemonic().unwrap().starts_with("rep") {
if cs_instr.prefixes.rep_any() {
return None;
}
for operand in operands {
if let X86Operand(x86operand) = operand {
if let X86OperandType::Mem(opmem) = x86operand.op_type {
/*
log::trace!(
"insn: {:#?} {:#?} width: {}, segment: {:#?}, base: {:#?}, index: {:#?}, scale: {}, disp: {}",
insn_id,
instr,
x86operand.size,
opmem.segment(),
opmem.base(),
opmem.index(),
opmem.scale(),
opmem.disp(),
);
*/
if opmem.segment() == RegId(0) {
return Some((
opmem.segment(),
x86operand.size,
opmem.base(),
opmem.index(),
opmem.scale(),
opmem.disp(),
));
}
}
if operand.is_memory() {
// log::trace!("{:#?}", operand)
// if we reach this point
// because in x64 there's no mem to mem inst, just return the first memory operand
if let Some((basereg, indexreg, scale, disp)) = operand_details(&operand) {
let memsz = cs_instr.mem_size().unwrap().bytes_size().unwrap(); // this won't fail if it is mem access inst
// println!("{:#?} {:#?} {:#?}", cs_instr, cs_instr.to_string(), operand);
// println!("{:#?}", (memsz, basereg, indexreg, scale, disp));
return Some((memsz, basereg, indexreg, scale, disp));
} // else {} // perhaps avx instructions?
}
}
@ -2317,29 +2302,26 @@ impl AsanRuntime {
&mut self,
address: u64,
output: &StalkerOutput,
_segment: RegId,
width: u8,
basereg: RegId,
indexreg: RegId,
scale: i32,
disp: isize,
basereg: X86Register,
indexreg: X86Register,
scale: u8,
disp: i32,
) {
let redzone_size = isize::try_from(frida_gum_sys::GUM_RED_ZONE_SIZE).unwrap();
let writer = output.writer();
let true_rip = address;
let basereg = if basereg.0 == 0 {
let basereg: Option<X86Register> = if basereg == X86Register::None {
None
} else {
let reg = writer_register(basereg);
Some(reg)
Some(basereg)
};
let indexreg = if indexreg.0 == 0 {
let indexreg = if indexreg == X86Register::None {
None
} else {
let reg = writer_register(indexreg);
Some(reg)
Some(indexreg)
};
let scale = match scale {
@ -2447,7 +2429,7 @@ impl AsanRuntime {
// Finally set Rdi to base + index * scale + disp
writer.put_add_reg_reg(X86Register::Rdi, X86Register::Rsi);
writer.put_lea_reg_reg_offset(X86Register::Rdi, X86Register::Rdi, disp);
writer.put_lea_reg_reg_offset(X86Register::Rdi, X86Register::Rdi, disp as isize);
writer.put_mov_reg_address(X86Register::Rsi, true_rip); // load true_rip into rsi in case we need them in handle_trap
writer.put_push_reg(X86Register::Rsi); // save true_rip

View File

@ -2,7 +2,6 @@
use std::{fmt::Debug, io::Write, marker::PhantomData};
use backtrace::Backtrace;
use capstone::{arch::BuildsCapstone, Capstone};
use color_backtrace::{default_output_stream, BacktracePrinter, Verbosity};
#[cfg(target_arch = "aarch64")]
use frida_gum::interceptor::Interceptor;
@ -20,10 +19,16 @@ use libafl::{
use libafl_bolts::{ownedref::OwnedPtr, Named, SerdeAny};
use serde::{Deserialize, Serialize};
use termcolor::{Color, ColorSpec, WriteColor};
#[cfg(target_arch = "x86_64")]
use yaxpeax_arch::LengthedInstruction;
#[cfg(target_arch = "x86_64")]
use yaxpeax_x86::amd64::InstDecoder;
#[cfg(target_arch = "x86_64")]
use crate::asan::asan_rt::ASAN_SAVE_REGISTER_NAMES;
use crate::{alloc::AllocationMetadata, asan::asan_rt::ASAN_SAVE_REGISTER_COUNT};
use crate::{
alloc::AllocationMetadata, asan::asan_rt::ASAN_SAVE_REGISTER_COUNT, utils::disas_count,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct AsanReadWriteError {
@ -241,25 +246,18 @@ impl AsanErrors {
.unwrap();
#[cfg(target_arch = "x86_64")]
let mut cs = Capstone::new()
.x86()
.mode(capstone::arch::x86::ArchMode::Mode64)
.detail(true)
.build()
.expect("Failed to create Capstone object");
cs.set_skipdata(true).expect("failed to set skipdata");
let decoder = InstDecoder::minimal();
let start_pc = error.pc - 4 * 5;
for insn in &*cs
.disasm_count(
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
start_pc as u64,
11,
)
.expect("failed to disassemble instructions")
{
if insn.address() as usize == error.pc {
let insts = disas_count(
&decoder,
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 15 * 11) },
11,
);
let mut inst_address = start_pc;
for insn in insts {
if inst_address == error.pc {
output
.set_color(ColorSpec::new().set_fg(Some(Color::Red)))
.unwrap();
@ -268,6 +266,8 @@ impl AsanErrors {
} else {
writeln!(output, "\t {insn}").unwrap();
}
inst_address += insn.len().to_const() as usize;
}
backtrace_printer
.print_trace(&error.backtrace, output)
@ -496,25 +496,18 @@ impl AsanErrors {
.unwrap();
#[cfg(target_arch = "x86_64")]
let mut cs = Capstone::new()
.x86()
.mode(capstone::arch::x86::ArchMode::Mode64)
.detail(true)
.build()
.expect("Failed to create Capstone object");
cs.set_skipdata(true).expect("failed to set skipdata");
let decoder = InstDecoder::minimal();
let start_pc = pc;
for insn in &*cs
.disasm_count(
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
start_pc as u64,
11,
)
.expect("failed to disassemble instructions")
{
if insn.address() as usize == pc {
let insts = disas_count(
&decoder,
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 15 * 11) },
11,
);
let mut inst_address = start_pc;
for insn in insts {
if inst_address == pc {
output
.set_color(ColorSpec::new().set_fg(Some(Color::Red)))
.unwrap();
@ -523,6 +516,8 @@ impl AsanErrors {
} else {
writeln!(output, "\t {insn}").unwrap();
}
inst_address += insn.len().to_const() as usize;
}
backtrace_printer.print_trace(&backtrace, output).unwrap();
}

View File

@ -6,7 +6,7 @@ use std::{
rc::Rc,
};
#[cfg(any(target_arch = "aarch64", all(target_arch = "x86_64", unix)))]
#[cfg(target_arch = "aarch64")]
use capstone::{
arch::{self, BuildsCapstone},
Capstone,
@ -27,6 +27,8 @@ use libafl_targets::drcov::DrCovBasicBlock;
#[cfg(unix)]
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
use rangemap::RangeMap;
#[cfg(target_arch = "x86_64")]
use yaxpeax_x86::amd64::InstDecoder;
#[cfg(all(feature = "cmplog", target_arch = "aarch64"))]
use crate::cmplog_rt::CmpLogRuntime;
@ -450,13 +452,9 @@ where
.detail(true)
.build()
.expect("Failed to create Capstone object");
#[cfg(all(target_arch = "x86_64", unix))]
let capstone = Capstone::new()
.x86()
.mode(arch::x86::ArchMode::Mode64)
.detail(true)
.build()
.expect("Failed to create Capstone object");
#[cfg(target_arch = "x86_64")]
let decoder = InstDecoder::minimal();
Transformer::from_callback(gum, move |basic_block, output| {
Self::transform(
@ -464,8 +462,10 @@ where
&output,
&ranges,
&runtimes,
#[cfg(any(target_arch = "aarch64", all(target_arch = "x86_64", unix)))]
#[cfg(target_arch = "aarch64")]
&capstone,
#[cfg(target_arch = "x86_64")]
decoder,
);
})
}
@ -475,7 +475,7 @@ where
output: &StalkerOutput,
ranges: &Rc<RefCell<RangeMap<usize, (u16, String)>>>,
runtimes: &Rc<RefCell<RT>>,
#[cfg(any(target_arch = "aarch64", all(target_arch = "x86_64", unix)))] capstone: &Capstone,
decoder: InstDecoder,
) {
let mut first = true;
let mut basic_block_start = 0;
@ -508,23 +508,16 @@ where
#[cfg(unix)]
let res = if let Some(_rt) = runtimes.match_first_type_mut::<AsanRuntime>() {
AsanRuntime::asan_is_interesting_instruction(capstone, address, instr)
AsanRuntime::asan_is_interesting_instruction(decoder, address, instr)
} else {
None
};
#[cfg(all(target_arch = "x86_64", unix))]
if let Some((segment, width, basereg, indexreg, scale, disp)) = res {
if let Some(details) = res {
if let Some(rt) = runtimes.match_first_type_mut::<AsanRuntime>() {
rt.emit_shadow_check(
address,
output,
segment,
width,
basereg,
indexreg,
scale,
disp.try_into().unwrap(),
address, output, details.0, details.1, details.2, details.3, details.4,
);
}
}

View File

@ -1,4 +1,4 @@
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
#[cfg(target_arch = "aarch64")]
use capstone::Capstone;
#[cfg(target_arch = "aarch64")]
use capstone::{
@ -13,6 +13,11 @@ use frida_gum::instruction_writer::X86Register;
use frida_gum_sys;
#[cfg(target_arch = "aarch64")]
use num_traits::cast::FromPrimitive;
#[cfg(target_arch = "x86_64")]
use yaxpeax_arch::LengthedInstruction;
use yaxpeax_x86::amd64::Operand;
#[cfg(target_arch = "x86_64")]
use yaxpeax_x86::amd64::{InstDecoder, Instruction, RegSpec};
/// Determine the width of the specified instruction
#[cfg(target_arch = "aarch64")]
@ -89,6 +94,44 @@ pub fn writer_register(reg: capstone::RegId) -> Aarch64Register {
Aarch64Register::from_u32(u32::from(regint)).unwrap()
}
/// Translate from `RegSpec` to `X86Register`
const X86_64_REGS: [(RegSpec, X86Register); 34] = [
(RegSpec::eax(), X86Register::Eax),
(RegSpec::ecx(), X86Register::Ecx),
(RegSpec::edx(), X86Register::Edx),
(RegSpec::ebx(), X86Register::Ebx),
(RegSpec::esp(), X86Register::Esp),
(RegSpec::ebp(), X86Register::Ebp),
(RegSpec::esi(), X86Register::Esi),
(RegSpec::edi(), X86Register::Edi),
(RegSpec::r8d(), X86Register::R8d),
(RegSpec::r9d(), X86Register::R9d),
(RegSpec::r10d(), X86Register::R10d),
(RegSpec::r11d(), X86Register::R11d),
(RegSpec::r12d(), X86Register::R12d),
(RegSpec::r13d(), X86Register::R13d),
(RegSpec::r14d(), X86Register::R14d),
(RegSpec::r15d(), X86Register::R15d),
(RegSpec::eip(), X86Register::Eip),
(RegSpec::rax(), X86Register::Rax),
(RegSpec::rcx(), X86Register::Rcx),
(RegSpec::rdx(), X86Register::Rdx),
(RegSpec::rbx(), X86Register::Rbx),
(RegSpec::rsp(), X86Register::Rsp),
(RegSpec::rbp(), X86Register::Rbp),
(RegSpec::rsi(), X86Register::Rsi),
(RegSpec::rdi(), X86Register::Rdi),
(RegSpec::r8(), X86Register::R8),
(RegSpec::r9(), X86Register::R9),
(RegSpec::r10(), X86Register::R10),
(RegSpec::r11(), X86Register::R11),
(RegSpec::r12(), X86Register::R12),
(RegSpec::r13(), X86Register::R13),
(RegSpec::r14(), X86Register::R14),
(RegSpec::r15(), X86Register::R15),
(RegSpec::rip(), X86Register::Rip),
];
/// The writer registers
/// frida registers: <https://docs.rs/frida-gum/0.4.0/frida_gum/instruction_writer/enum.X86Register.html>
/// capstone registers: <https://docs.rs/capstone-sys/0.14.0/capstone_sys/x86_reg/index.html>
@ -96,55 +139,93 @@ pub fn writer_register(reg: capstone::RegId) -> Aarch64Register {
#[must_use]
#[inline]
#[allow(clippy::unused_self)]
pub fn writer_register(reg: capstone::RegId) -> X86Register {
let regint: u16 = reg.0;
match regint {
19 => X86Register::Eax,
22 => X86Register::Ecx,
24 => X86Register::Edx,
21 => X86Register::Ebx,
30 => X86Register::Esp,
20 => X86Register::Ebp,
29 => X86Register::Esi,
23 => X86Register::Edi,
226 => X86Register::R8d,
227 => X86Register::R9d,
228 => X86Register::R10d,
229 => X86Register::R11d,
230 => X86Register::R12d,
231 => X86Register::R13d,
232 => X86Register::R14d,
233 => X86Register::R15d,
26 => X86Register::Eip,
35 => X86Register::Rax,
38 => X86Register::Rcx,
40 => X86Register::Rdx,
37 => X86Register::Rbx,
44 => X86Register::Rsp,
36 => X86Register::Rbp,
43 => X86Register::Rsi,
39 => X86Register::Rdi,
106 => X86Register::R8,
107 => X86Register::R9,
108 => X86Register::R10,
109 => X86Register::R11,
110 => X86Register::R12,
111 => X86Register::R13,
112 => X86Register::R14,
113 => X86Register::R15,
41 => X86Register::Rip,
_ => X86Register::None, // Ignore Xax..Xip
pub fn writer_register(reg: RegSpec) -> X86Register {
for (reg1, reg2) in &X86_64_REGS {
// println!("reg1:{:#?} reg2:{:#?}", reg1, reg);
if *reg1 == reg {
return *reg2;
}
}
X86Register::None
}
/// 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()
pub(crate) fn frida_to_cs(decoder: InstDecoder, frida_insn: &frida_gum_sys::Insn) -> Instruction {
decoder.decode_slice(frida_insn.bytes()).unwrap()
}
#[cfg(target_arch = "x86_64")]
/// Get the base, idx, scale, disp for each operand
pub fn operand_details(operand: &Operand) -> Option<(X86Register, X86Register, u8, i32)> {
match operand {
Operand::RegDeref(base) => {
let base = writer_register(*base);
Some((base, X86Register::None, 0, 0))
}
Operand::RegDisp(base, disp) => {
let base = writer_register(*base);
Some((base, X86Register::None, 0, *disp))
}
Operand::RegScale(base, scale) => {
let base = writer_register(*base);
Some((base, X86Register::None, *scale, 0))
}
Operand::RegIndexBase(base, index) => {
let base = writer_register(*base);
let index = writer_register(*index);
Some((base, index, 0, 0))
}
Operand::RegIndexBaseDisp(base, index, disp) => {
let base = writer_register(*base);
let index = writer_register(*index);
Some((base, index, 0, *disp))
}
Operand::RegScaleDisp(base, scale, disp) => {
let base = writer_register(*base);
Some((base, X86Register::None, *scale, *disp))
}
Operand::RegIndexBaseScale(base, index, scale) => {
let base = writer_register(*base);
let index = writer_register(*index);
Some((base, index, *scale, 0))
}
Operand::RegIndexBaseScaleDisp(base, index, scale, disp) => {
let base = writer_register(*base);
let index = writer_register(*index);
Some((base, index, *scale, *disp))
}
_ => None,
}
}
#[derive(Debug, Clone, Copy)]
#[cfg(target_arch = "x86_64")]
/// What kind of memory access this instruction has
pub enum AccessType {
/// Read-access
Read,
/// Write-access
Write,
}
#[cfg(target_arch = "x86_64")]
/// Disassemble "count" number of instructions
pub fn disas_count(decoder: &InstDecoder, data: &[u8], count: usize) -> Vec<Instruction> {
let mut counter = count;
let mut ret = vec![];
let mut start = 0;
loop {
if counter == 0 {
break ret;
}
let Ok(inst) = decoder.decode_slice(&data[start..]) else {
break ret;
};
start += inst.len().to_const() as usize;
ret.push(inst);
counter -= 1;
}
}

View File

@ -46,7 +46,7 @@ fi
echo "[*] Checking QEMU-Nyx ..."
if [ ! -f "QEMU-Nyx/x86_64-softmmu/qemu-system-x86_64" ]; then
cd QEMU-Nyx/ || return
./compile_qemu_nyx.sh static || exit 1
./compile_qemu_nyx.sh lto || exit 1
cd ..
fi