From e305c28da407014e3de6ad31dff494cf7888abca Mon Sep 17 00:00:00 2001 From: th0rex Date: Fri, 29 Sep 2017 13:16:11 +0200 Subject: [PATCH 1/8] Add wrapped formatter funcs These functions make it easier for the rust code to use the formatter hooks, since there is no more dealing with a `*mut *mut c_char` and all the pointers are already dereferenced, which means that the hook doesn't need any unsafe blocks (usually). This commit also fixes some minor bugs that were undetected until now (i.e. Hook::FuncPrintDecorator had the wrong type and transmuted it which could lead to crashes). The only thing left to do would be to decide whether we actually pass mutable reference to instances of ZydisDecodedInstruction and ZydisDecodedOperand. That would allow setting the user context, for which I don't really see a use case. --- examples/formatter_hooks.rs | 27 +++++++ src/formatter.rs | 155 +++++++++++++++++++++++++++++++++++- 2 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 examples/formatter_hooks.rs diff --git a/examples/formatter_hooks.rs b/examples/formatter_hooks.rs new file mode 100644 index 0000000..3b874bb --- /dev/null +++ b/examples/formatter_hooks.rs @@ -0,0 +1,27 @@ +extern crate zydis; +use zydis::gen::*; +use zydis::*; + +#[cfg_attr(rustfmt, rustfmt_skip)] +static CODE: &'static [u8] = &[ + 0x51, 0x8D, 0x45, 0xFF, 0x50, 0xFF, 0x75, 0x0C, 0xFF, 0x75, 0x08, + 0xFF, 0x15, 0xA0, 0xA5, 0x48, 0x76, 0x85, 0xC0, 0x0F, 0x88, 0xFC, + 0xDA, 0x02, 0x00u8, +]; + +fn print_mnemonic(formatter: &Formatter, buffer: &mut Buffer, instruction: &ZydisDecodedInstruction) -> ZydisResult<()> { + buffer.append("abc"); + Ok(()) +} + +fn main() { + let mut formatter = Formatter::new(ZYDIS_FORMATTER_STYLE_INTEL).unwrap(); + formatter.set_print_mnemonic(Box::new(print_mnemonic)).unwrap(); + + let decoder = Decoder::new(ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64).unwrap(); + + for (mut instruction, ip) in decoder.instruction_iterator(CODE, 0) { + let insn = formatter.format_instruction(&mut instruction, 200); + println!("0x{:016X} {}", ip, insn.unwrap()); + } +} diff --git a/src/formatter.rs b/src/formatter.rs index 62a91d4..bca6a09 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -4,7 +4,8 @@ use gen::*; use status::ZydisResult; use std::mem; use std::ffi::CStr; -use std::os::raw::c_void; +use std::os::raw::{c_char, c_void}; +use std::slice; #[derive(Clone)] @@ -20,7 +21,7 @@ pub enum Hook { FuncFormatOperandImm(ZydisFormatterFormatOperandFunc), FuncPrintOperandsize(ZydisFormatterFormatOperandFunc), FuncPrintSegment(ZydisFormatterFormatOperandFunc), - FuncPrintDecorator(ZydisFormatterFormatOperandFunc), + FuncPrintDecorator(ZydisFormatterFormatDecoratorFunc), FuncPrintDisplacement(ZydisFormatterFormatOperandFunc), FuncPrintImmediate(ZydisFormatterFormatOperandFunc), FuncPrintAddress(ZydisFormatterFormatAddressFunc), @@ -92,8 +93,136 @@ impl Hook { } } +pub struct Buffer { + raw: *mut *mut c_char, + buffer_length: usize, +} + +impl Buffer { + pub fn new(raw: *mut *mut c_char, buffer_length: usize) -> Self { + Self { + raw, + buffer_length, + } + } + + pub fn append(&mut self, s: &str) -> ZydisResult<()> { + let bytes = s.as_bytes(); + if bytes.len() + 1 >= self.buffer_length { + return Err(ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE); + } + + let slice = unsafe { slice::from_raw_parts_mut(*(self.raw) as *mut u8, self.buffer_length) }; + (&mut slice[..bytes.len()]).clone_from_slice(bytes); + slice[bytes.len()] = '\0' as u8; + unsafe { *self.raw = (*self.raw).offset(bytes.len() as _) }; + Ok(()) + } +} + +pub type WrappedNotifyFunc = Fn(&Formatter, &ZydisDecodedInstruction) -> ZydisResult<()>; +pub type WrappedFormatFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction) -> ZydisResult<()>; +pub type WrappedFormatOperandFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction, &ZydisDecodedOperand) -> ZydisResult<()>; +pub type WrappedFormatAddressFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction, &ZydisDecodedOperand, u64) -> ZydisResult<()>; +pub type WrappedFormatDecoratorFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction, &ZydisDecodedOperand, ZydisDecoratorType) -> ZydisResult<()>; + +macro_rules! wrapped_hook_setter{ + ($field_name:ident, $field_type:ty, $func_name:ident, $dispatch_func:ident, $constructor:expr) => { + pub fn $func_name(&mut self, new_func: Box<$field_type>) -> ZydisResult { + self.$field_name = Some(new_func); + self.set_raw_hook($constructor(Some($dispatch_func))) + } + } +} + +macro_rules! dispatch_wrapped_func{ + (notify $field_name:ident, $func_name:ident) => { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { + let formatter = &*(formatter as *const Formatter); + let r = match formatter.$field_name.as_ref().unwrap()(formatter, &*instruction) { + Ok(_) => ZYDIS_STATUS_SUCCESS, + Err(e) => e, + }; + r as _ + } + }; + (format $field_name:ident, $func_name:ident) => { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { + let formatter = &*(formatter as *const Formatter); + let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction) { + Ok(_) => ZYDIS_STATUS_SUCCESS, + Err(e) => e, + }; + r as _ + } + }; + (format_operand $field_name:ident, $func_name:ident) => { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction, operand: *mut ZydisDecodedOperand) -> ZydisStatus { + let formatter = &*(formatter as *const Formatter); + let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction, &*operand) { + Ok(_) => ZYDIS_STATUS_SUCCESS, + Err(e) => e, + }; + r as _ + } + }; + (format_decorator $field_name:ident, $func_name:ident) => { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction, operand: *mut ZydisDecodedOperand, decorator: ZydisDecoratorType) -> ZydisStatus { + let formatter = &*(formatter as *const Formatter); + let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction, &*operand, decorator) { + Ok(_) => ZYDIS_STATUS_SUCCESS, + Err(e) => e, + }; + r as _ + } + }; + (format_address $field_name:ident, $func_name:ident) => { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction, operand: *mut ZydisDecodedOperand, address: u64) -> ZydisStatus { + let formatter = &*(formatter as *const Formatter); + let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction, &*operand, address) { + Ok(_) => ZYDIS_STATUS_SUCCESS, + Err(e) => e, + }; + r as _ + } + } +} + +dispatch_wrapped_func!(notify pre, dispatch_pre); +dispatch_wrapped_func!(notify post, dispatch_post); +dispatch_wrapped_func!(format format_instruction, dispatch_format_instruction); +dispatch_wrapped_func!(format print_prefixes, dispatch_print_prefixes); +dispatch_wrapped_func!(format print_mnemonic, dispatch_print_mnemonic); +dispatch_wrapped_func!(format_operand format_operand_reg, dispatch_format_operand_reg); +dispatch_wrapped_func!(format_operand format_operand_mem, dispatch_format_operand_mem); +dispatch_wrapped_func!(format_operand format_operand_ptr, dispatch_format_operand_ptr); +dispatch_wrapped_func!(format_operand format_operand_imm, dispatch_format_operand_imm); +dispatch_wrapped_func!(format_operand print_operand_size, dispatch_print_operand_size); +dispatch_wrapped_func!(format_operand print_segment, dispatch_print_segment); +dispatch_wrapped_func!(format_decorator print_decorator, dispatch_print_decorator); +dispatch_wrapped_func!(format_address print_address, dispatch_print_address); +dispatch_wrapped_func!(format_operand print_displacement, dispatch_print_displacement); +dispatch_wrapped_func!(format_operand print_immediate, dispatch_print_immediate); + +#[repr(C)] // needed, since we cast a *const ZydisFormatter to a *const Formatter and the rust compiler +// could reorder the fields if this wasn't #[repr(C)]. pub struct Formatter { formatter: ZydisFormatter, + pre: Option>, + post: Option>, + format_instruction: Option>, + print_prefixes: Option>, + print_mnemonic: Option>, + format_operand_reg: Option>, + format_operand_mem: Option>, + format_operand_ptr: Option>, + format_operand_imm: Option>, + print_operand_size: Option>, + print_segment: Option>, + print_decorator: Option>, + print_address: Option>, + print_displacement: Option>, + print_immediate: Option>, } impl Formatter { @@ -116,7 +245,9 @@ impl Formatter { displacement_format as _, immediate_format as _, ), - Formatter { formatter } + Formatter { formatter, pre: None, post: None, format_instruction: None, print_prefixes: None, print_mnemonic: None, format_operand_reg: None, + format_operand_mem: None, format_operand_ptr: None, format_operand_imm: None, print_operand_size: None, print_segment: None, print_decorator: None, + print_address: None, print_displacement: None, print_immediate: None, } ) } } @@ -183,7 +314,7 @@ impl Formatter { } /// Sets a hook, allowing for customizations along the formatting process. - pub fn set_hook(&mut self, hook: Hook) -> ZydisResult { + pub fn set_raw_hook(&mut self, hook: Hook) -> ZydisResult { unsafe { let mut cb = hook.to_raw(); let hook_id = hook.to_id(); @@ -194,4 +325,20 @@ impl Formatter { ) } } + + wrapped_hook_setter!(pre, WrappedNotifyFunc, set_pre, dispatch_pre, Hook::FuncPre); + wrapped_hook_setter!(post, WrappedNotifyFunc, set_post, dispatch_post, Hook::FuncPost); + wrapped_hook_setter!(format_instruction, WrappedFormatFunc, set_format_instruction, dispatch_format_instruction, Hook::FuncFormatInstruction); + wrapped_hook_setter!(print_prefixes, WrappedFormatFunc, set_print_prefixes, dispatch_print_prefixes, Hook::FuncPrintPrefixes); + wrapped_hook_setter!(print_mnemonic, WrappedFormatFunc, set_print_mnemonic, dispatch_print_mnemonic, Hook::FuncPrintMnemonic); + wrapped_hook_setter!(format_operand_reg, WrappedFormatOperandFunc, set_format_operand_reg, dispatch_format_operand_reg, Hook::FuncFormatOperandReg); + wrapped_hook_setter!(format_operand_mem, WrappedFormatOperandFunc, set_format_operand_mem, dispatch_format_operand_mem, Hook::FuncFormatOperandMem); + wrapped_hook_setter!(format_operand_ptr, WrappedFormatOperandFunc, set_format_operand_ptr, dispatch_format_operand_ptr, Hook::FuncFormatOperandPtr); + wrapped_hook_setter!(format_operand_imm, WrappedFormatOperandFunc, set_format_operand_imm, dispatch_format_operand_imm, Hook::FuncFormatOperandImm); + wrapped_hook_setter!(print_operand_size, WrappedFormatOperandFunc, set_print_operand_size, dispatch_print_operand_size, Hook::FuncPrintOperandsize); + wrapped_hook_setter!(print_segment, WrappedFormatOperandFunc, set_print_segment, dispatch_print_segment, Hook::FuncPrintSegment); + wrapped_hook_setter!(print_decorator, WrappedFormatDecoratorFunc, set_print_decorator, dispatch_print_decorator, Hook::FuncPrintDecorator); + wrapped_hook_setter!(print_address, WrappedFormatAddressFunc, set_print_address, dispatch_print_address, Hook::FuncPrintAddress); + wrapped_hook_setter!(print_displacement, WrappedFormatOperandFunc, set_print_displacement, dispatch_print_displacement, Hook::FuncPrintDisplacement); + wrapped_hook_setter!(print_immediate, WrappedFormatOperandFunc, set_print_immediate, dispatch_print_immediate, Hook::FuncPrintImmediate); } From 3cc7a26a5c0ecb798e7a930af54209665e5dbed6 Mon Sep 17 00:00:00 2001 From: th0rex Date: Fri, 29 Sep 2017 13:19:55 +0200 Subject: [PATCH 2/8] Run cargo.exe fmt --- examples/formatter_hooks.rs | 10 +- examples/pattern.rs | 14 +-- src/formatter.rs | 221 +++++++++++++++++++++++++++++------- 3 files changed, 197 insertions(+), 48 deletions(-) diff --git a/examples/formatter_hooks.rs b/examples/formatter_hooks.rs index 3b874bb..b749d12 100644 --- a/examples/formatter_hooks.rs +++ b/examples/formatter_hooks.rs @@ -9,14 +9,20 @@ static CODE: &'static [u8] = &[ 0xDA, 0x02, 0x00u8, ]; -fn print_mnemonic(formatter: &Formatter, buffer: &mut Buffer, instruction: &ZydisDecodedInstruction) -> ZydisResult<()> { +fn print_mnemonic( + formatter: &Formatter, + buffer: &mut Buffer, + instruction: &ZydisDecodedInstruction, +) -> ZydisResult<()> { buffer.append("abc"); Ok(()) } fn main() { let mut formatter = Formatter::new(ZYDIS_FORMATTER_STYLE_INTEL).unwrap(); - formatter.set_print_mnemonic(Box::new(print_mnemonic)).unwrap(); + formatter + .set_print_mnemonic(Box::new(print_mnemonic)) + .unwrap(); let decoder = Decoder::new(ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64).unwrap(); diff --git a/examples/pattern.rs b/examples/pattern.rs index 549e9d4..998b09d 100644 --- a/examples/pattern.rs +++ b/examples/pattern.rs @@ -26,14 +26,12 @@ fn main() { // Obtain offsets for relevant operands, skip others. let (dyn_offs, dyn_len) = match op.type_ as ZydisOperandTypes { - ZYDIS_OPERAND_TYPE_MEMORY if op.mem.disp.hasDisplacement == 1 => ( - insn.raw.disp.offset, - insn.raw.disp.size, - ), - ZYDIS_OPERAND_TYPE_IMMEDIATE if op.imm.isRelative == 1 => ( - insn.raw.imm[op_idx].offset, - insn.raw.imm[op_idx].size, - ), + ZYDIS_OPERAND_TYPE_MEMORY if op.mem.disp.hasDisplacement == 1 => { + (insn.raw.disp.offset, insn.raw.disp.size) + } + ZYDIS_OPERAND_TYPE_IMMEDIATE if op.imm.isRelative == 1 => { + (insn.raw.imm[op_idx].offset, insn.raw.imm[op_idx].size) + } _ => continue, }; diff --git a/src/formatter.rs b/src/formatter.rs index bca6a09..54613a8 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -100,10 +100,7 @@ pub struct Buffer { impl Buffer { pub fn new(raw: *mut *mut c_char, buffer_length: usize) -> Self { - Self { - raw, - buffer_length, - } + Self { raw, buffer_length } } pub fn append(&mut self, s: &str) -> ZydisResult<()> { @@ -112,7 +109,8 @@ impl Buffer { return Err(ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE); } - let slice = unsafe { slice::from_raw_parts_mut(*(self.raw) as *mut u8, self.buffer_length) }; + let slice = + unsafe { slice::from_raw_parts_mut(*(self.raw) as *mut u8, self.buffer_length) }; (&mut slice[..bytes.len()]).clone_from_slice(bytes); slice[bytes.len()] = '\0' as u8; unsafe { *self.raw = (*self.raw).offset(bytes.len() as _) }; @@ -120,14 +118,34 @@ impl Buffer { } } -pub type WrappedNotifyFunc = Fn(&Formatter, &ZydisDecodedInstruction) -> ZydisResult<()>; -pub type WrappedFormatFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction) -> ZydisResult<()>; -pub type WrappedFormatOperandFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction, &ZydisDecodedOperand) -> ZydisResult<()>; -pub type WrappedFormatAddressFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction, &ZydisDecodedOperand, u64) -> ZydisResult<()>; -pub type WrappedFormatDecoratorFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction, &ZydisDecodedOperand, ZydisDecoratorType) -> ZydisResult<()>; +pub type WrappedNotifyFunc = Fn(&Formatter, &ZydisDecodedInstruction) + -> ZydisResult<()>; +pub type WrappedFormatFunc = Fn(&Formatter, &mut Buffer, &ZydisDecodedInstruction) + -> ZydisResult<()>; +pub type WrappedFormatOperandFunc = Fn( + &Formatter, + &mut Buffer, + &ZydisDecodedInstruction, + &ZydisDecodedOperand, +) -> ZydisResult<()>; +pub type WrappedFormatAddressFunc = Fn( + &Formatter, + &mut Buffer, + &ZydisDecodedInstruction, + &ZydisDecodedOperand, + u64, +) -> ZydisResult<()>; +pub type WrappedFormatDecoratorFunc = Fn( + &Formatter, + &mut Buffer, + &ZydisDecodedInstruction, + &ZydisDecodedOperand, + ZydisDecoratorType, +) -> ZydisResult<()>; macro_rules! wrapped_hook_setter{ - ($field_name:ident, $field_type:ty, $func_name:ident, $dispatch_func:ident, $constructor:expr) => { + ($field_name:ident, $field_type:ty, $func_name:ident, $dispatch_func:ident, $constructor:expr) + => { pub fn $func_name(&mut self, new_func: Box<$field_type>) -> ZydisResult { self.$field_name = Some(new_func); self.set_raw_hook($constructor(Some($dispatch_func))) @@ -137,7 +155,8 @@ macro_rules! wrapped_hook_setter{ macro_rules! dispatch_wrapped_func{ (notify $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, + instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); let r = match formatter.$field_name.as_ref().unwrap()(formatter, &*instruction) { Ok(_) => ZYDIS_STATUS_SUCCESS, @@ -147,9 +166,13 @@ macro_rules! dispatch_wrapped_func{ } }; (format $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction) { + let r = match formatter.$field_name.as_ref().unwrap()(formatter, + &mut Buffer::new(buffer, len), + &*instruction) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; @@ -157,9 +180,15 @@ macro_rules! dispatch_wrapped_func{ } }; (format_operand $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction, operand: *mut ZydisDecodedOperand) -> ZydisStatus { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction, + operand: *mut ZydisDecodedOperand) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction, &*operand) { + let r = match formatter.$field_name.as_ref().unwrap()(formatter, + &mut Buffer::new(buffer, len), + &*instruction, + &*operand) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; @@ -167,9 +196,17 @@ macro_rules! dispatch_wrapped_func{ } }; (format_decorator $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction, operand: *mut ZydisDecodedOperand, decorator: ZydisDecoratorType) -> ZydisStatus { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction, + operand: *mut ZydisDecodedOperand, + decorator: ZydisDecoratorType) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction, &*operand, decorator) { + let r = match formatter.$field_name.as_ref().unwrap()(formatter, + &mut Buffer::new(buffer, len), + &*instruction, + &*operand, + decorator) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; @@ -177,9 +214,17 @@ macro_rules! dispatch_wrapped_func{ } }; (format_address $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, len: usize, instruction: *mut ZydisDecodedInstruction, operand: *mut ZydisDecodedOperand, address: u64) -> ZydisStatus { + unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction, + operand: *mut ZydisDecodedOperand, + address: u64) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, &mut Buffer::new(buffer, len), &*instruction, &*operand, address) { + let r = match formatter.$field_name.as_ref().unwrap()(formatter, + &mut Buffer::new(buffer, len), + &*instruction, + &*operand, + address) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; @@ -204,7 +249,8 @@ dispatch_wrapped_func!(format_address print_address, dispatch_print_address); dispatch_wrapped_func!(format_operand print_displacement, dispatch_print_displacement); dispatch_wrapped_func!(format_operand print_immediate, dispatch_print_immediate); -#[repr(C)] // needed, since we cast a *const ZydisFormatter to a *const Formatter and the rust compiler +#[repr(C)] +// needed, since we cast a *const ZydisFormatter to a *const Formatter and the rust compiler // could reorder the fields if this wasn't #[repr(C)]. pub struct Formatter { formatter: ZydisFormatter, @@ -245,9 +291,24 @@ impl Formatter { displacement_format as _, immediate_format as _, ), - Formatter { formatter, pre: None, post: None, format_instruction: None, print_prefixes: None, print_mnemonic: None, format_operand_reg: None, - format_operand_mem: None, format_operand_ptr: None, format_operand_imm: None, print_operand_size: None, print_segment: None, print_decorator: None, - print_address: None, print_displacement: None, print_immediate: None, } + Formatter { + formatter, + pre: None, + post: None, + format_instruction: None, + print_prefixes: None, + print_mnemonic: None, + format_operand_reg: None, + format_operand_mem: None, + format_operand_ptr: None, + format_operand_imm: None, + print_operand_size: None, + print_segment: None, + print_decorator: None, + print_address: None, + print_displacement: None, + print_immediate: None, + } ) } } @@ -327,18 +388,102 @@ impl Formatter { } wrapped_hook_setter!(pre, WrappedNotifyFunc, set_pre, dispatch_pre, Hook::FuncPre); - wrapped_hook_setter!(post, WrappedNotifyFunc, set_post, dispatch_post, Hook::FuncPost); - wrapped_hook_setter!(format_instruction, WrappedFormatFunc, set_format_instruction, dispatch_format_instruction, Hook::FuncFormatInstruction); - wrapped_hook_setter!(print_prefixes, WrappedFormatFunc, set_print_prefixes, dispatch_print_prefixes, Hook::FuncPrintPrefixes); - wrapped_hook_setter!(print_mnemonic, WrappedFormatFunc, set_print_mnemonic, dispatch_print_mnemonic, Hook::FuncPrintMnemonic); - wrapped_hook_setter!(format_operand_reg, WrappedFormatOperandFunc, set_format_operand_reg, dispatch_format_operand_reg, Hook::FuncFormatOperandReg); - wrapped_hook_setter!(format_operand_mem, WrappedFormatOperandFunc, set_format_operand_mem, dispatch_format_operand_mem, Hook::FuncFormatOperandMem); - wrapped_hook_setter!(format_operand_ptr, WrappedFormatOperandFunc, set_format_operand_ptr, dispatch_format_operand_ptr, Hook::FuncFormatOperandPtr); - wrapped_hook_setter!(format_operand_imm, WrappedFormatOperandFunc, set_format_operand_imm, dispatch_format_operand_imm, Hook::FuncFormatOperandImm); - wrapped_hook_setter!(print_operand_size, WrappedFormatOperandFunc, set_print_operand_size, dispatch_print_operand_size, Hook::FuncPrintOperandsize); - wrapped_hook_setter!(print_segment, WrappedFormatOperandFunc, set_print_segment, dispatch_print_segment, Hook::FuncPrintSegment); - wrapped_hook_setter!(print_decorator, WrappedFormatDecoratorFunc, set_print_decorator, dispatch_print_decorator, Hook::FuncPrintDecorator); - wrapped_hook_setter!(print_address, WrappedFormatAddressFunc, set_print_address, dispatch_print_address, Hook::FuncPrintAddress); - wrapped_hook_setter!(print_displacement, WrappedFormatOperandFunc, set_print_displacement, dispatch_print_displacement, Hook::FuncPrintDisplacement); - wrapped_hook_setter!(print_immediate, WrappedFormatOperandFunc, set_print_immediate, dispatch_print_immediate, Hook::FuncPrintImmediate); + wrapped_hook_setter!( + post, + WrappedNotifyFunc, + set_post, + dispatch_post, + Hook::FuncPost + ); + wrapped_hook_setter!( + format_instruction, + WrappedFormatFunc, + set_format_instruction, + dispatch_format_instruction, + Hook::FuncFormatInstruction + ); + wrapped_hook_setter!( + print_prefixes, + WrappedFormatFunc, + set_print_prefixes, + dispatch_print_prefixes, + Hook::FuncPrintPrefixes + ); + wrapped_hook_setter!( + print_mnemonic, + WrappedFormatFunc, + set_print_mnemonic, + dispatch_print_mnemonic, + Hook::FuncPrintMnemonic + ); + wrapped_hook_setter!( + format_operand_reg, + WrappedFormatOperandFunc, + set_format_operand_reg, + dispatch_format_operand_reg, + Hook::FuncFormatOperandReg + ); + wrapped_hook_setter!( + format_operand_mem, + WrappedFormatOperandFunc, + set_format_operand_mem, + dispatch_format_operand_mem, + Hook::FuncFormatOperandMem + ); + wrapped_hook_setter!( + format_operand_ptr, + WrappedFormatOperandFunc, + set_format_operand_ptr, + dispatch_format_operand_ptr, + Hook::FuncFormatOperandPtr + ); + wrapped_hook_setter!( + format_operand_imm, + WrappedFormatOperandFunc, + set_format_operand_imm, + dispatch_format_operand_imm, + Hook::FuncFormatOperandImm + ); + wrapped_hook_setter!( + print_operand_size, + WrappedFormatOperandFunc, + set_print_operand_size, + dispatch_print_operand_size, + Hook::FuncPrintOperandsize + ); + wrapped_hook_setter!( + print_segment, + WrappedFormatOperandFunc, + set_print_segment, + dispatch_print_segment, + Hook::FuncPrintSegment + ); + wrapped_hook_setter!( + print_decorator, + WrappedFormatDecoratorFunc, + set_print_decorator, + dispatch_print_decorator, + Hook::FuncPrintDecorator + ); + wrapped_hook_setter!( + print_address, + WrappedFormatAddressFunc, + set_print_address, + dispatch_print_address, + Hook::FuncPrintAddress + ); + wrapped_hook_setter!( + print_displacement, + WrappedFormatOperandFunc, + set_print_displacement, + dispatch_print_displacement, + Hook::FuncPrintDisplacement + ); + wrapped_hook_setter!( + print_immediate, + WrappedFormatOperandFunc, + set_print_immediate, + dispatch_print_immediate, + Hook::FuncPrintImmediate + ); } From 9e7daf95adc2b844dbd2eecdd546b2033b3f01c9 Mon Sep 17 00:00:00 2001 From: th0rex Date: Fri, 29 Sep 2017 13:23:11 +0200 Subject: [PATCH 3/8] Add some comments to the Buffer struct, clarifying encoding --- src/formatter.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/formatter.rs b/src/formatter.rs index 54613a8..11aff3a 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -93,6 +93,7 @@ impl Hook { } } +/// Wraps the raw `*mut *mut c_char` of formatter hooks and makes it easier to use. pub struct Buffer { raw: *mut *mut c_char, buffer_length: usize, @@ -103,6 +104,12 @@ impl Buffer { Self { raw, buffer_length } } + /// Appends the given string `s` to this buffer. + /// + /// Warning: The actual rust `&str`ings are encoded in UTF-8 and they are not + /// converted to any other encoding. They're simply copied, byte for byte, to the + /// buffer. Therefor the buffer should be interpreted as UTF-8 when later being printed. + /// A `\0` is automatically added. pub fn append(&mut self, s: &str) -> ZydisResult<()> { let bytes = s.as_bytes(); if bytes.len() + 1 >= self.buffer_length { From c0f341925eb26fd19020978012f346fd92e46573 Mon Sep 17 00:00:00 2001 From: th0rex Date: Fri, 29 Sep 2017 13:45:03 +0200 Subject: [PATCH 4/8] Fix 2 doc tests -- seems like bindgen chose a different type for the fields now so we needed to update the casts --- src/decoder.rs | 2 +- src/mnemonic.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/decoder.rs b/src/decoder.rs index 246cdbb..435281f 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -51,7 +51,7 @@ impl Decoder { /// zydis::gen::ZYDIS_ADDRESS_WIDTH_64 /// ).unwrap(); /// let info = decoder.decode(INT3, 0x00400000).unwrap().unwrap(); - /// assert_eq!(info.mnemonic as u32, zydis::gen::ZYDIS_MNEMONIC_INT3); + /// assert_eq!(info.mnemonic as i32, zydis::gen::ZYDIS_MNEMONIC_INT3); /// ``` pub fn decode( &self, diff --git a/src/mnemonic.rs b/src/mnemonic.rs index 2c1e5c9..095d074 100644 --- a/src/mnemonic.rs +++ b/src/mnemonic.rs @@ -2,7 +2,6 @@ use gen::*; use std::ffi::CStr; -use std::os::raw::c_uint; /// Extensions for `ZydisMnemonic` pub trait ZydisMnemonicMethods { @@ -17,7 +16,7 @@ pub trait ZydisMnemonicMethods { fn get_string(self) -> Option<&'static str>; } -impl ZydisMnemonicMethods for c_uint { +impl ZydisMnemonicMethods for i32 { fn get_string(self) -> Option<&'static str> { unsafe { check_string!(ZydisMnemonicGetString(self as _)) } } From a53a9e0b4aef03155d6df8fdcecde8e4a1ce3814 Mon Sep 17 00:00:00 2001 From: th0rex Date: Fri, 29 Sep 2017 13:46:05 +0200 Subject: [PATCH 5/8] Use the Result returned from `buffer.append` and fix unused variable warnings --- examples/formatter_hooks.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/formatter_hooks.rs b/examples/formatter_hooks.rs index b749d12..b9cbcea 100644 --- a/examples/formatter_hooks.rs +++ b/examples/formatter_hooks.rs @@ -10,12 +10,11 @@ static CODE: &'static [u8] = &[ ]; fn print_mnemonic( - formatter: &Formatter, + _formatter: &Formatter, buffer: &mut Buffer, - instruction: &ZydisDecodedInstruction, + _instruction: &ZydisDecodedInstruction, ) -> ZydisResult<()> { - buffer.append("abc"); - Ok(()) + buffer.append("abc") } fn main() { From ef98a747bad3d674d349298119cf5feff88cac70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Fri, 29 Sep 2017 18:06:26 +0200 Subject: [PATCH 6/8] Adjusted indentation in formatter.rs macros --- src/formatter.rs | 92 +++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/src/formatter.rs b/src/formatter.rs index 11aff3a..3cfe139 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -162,8 +162,10 @@ macro_rules! wrapped_hook_setter{ macro_rules! dispatch_wrapped_func{ (notify $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, - instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { + unsafe extern "C" fn $func_name( + formatter: *const ZydisFormatter, + instruction: *mut ZydisDecodedInstruction, + ) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); let r = match formatter.$field_name.as_ref().unwrap()(formatter, &*instruction) { Ok(_) => ZYDIS_STATUS_SUCCESS, @@ -173,13 +175,18 @@ macro_rules! dispatch_wrapped_func{ } }; (format $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, - len: usize, - instruction: *mut ZydisDecodedInstruction) -> ZydisStatus { + unsafe extern "C" fn $func_name( + formatter: *const ZydisFormatter, + buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction + ) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, - &mut Buffer::new(buffer, len), - &*instruction) { + let r = match formatter.$field_name.as_ref().unwrap()( + formatter, + &mut Buffer::new(buffer, len), + &*instruction, + ) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; @@ -187,15 +194,20 @@ macro_rules! dispatch_wrapped_func{ } }; (format_operand $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, - len: usize, - instruction: *mut ZydisDecodedInstruction, - operand: *mut ZydisDecodedOperand) -> ZydisStatus { + unsafe extern "C" fn $func_name( + formatter: *const ZydisFormatter, + buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction, + operand: *mut ZydisDecodedOperand, + ) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, - &mut Buffer::new(buffer, len), - &*instruction, - &*operand) { + let r = match formatter.$field_name.as_ref().unwrap()( + formatter, + &mut Buffer::new(buffer, len), + &*instruction, + &*operand, + ) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; @@ -203,17 +215,21 @@ macro_rules! dispatch_wrapped_func{ } }; (format_decorator $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, - len: usize, - instruction: *mut ZydisDecodedInstruction, - operand: *mut ZydisDecodedOperand, - decorator: ZydisDecoratorType) -> ZydisStatus { + unsafe extern "C" fn $func_name( + formatter: *const ZydisFormatter, buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction, + operand: *mut ZydisDecodedOperand, + decorator: ZydisDecoratorType + ) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, - &mut Buffer::new(buffer, len), - &*instruction, - &*operand, - decorator) { + let r = match formatter.$field_name.as_ref().unwrap()( + formatter, + &mut Buffer::new(buffer, len), + &*instruction, + &*operand, + decorator, + ) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; @@ -221,17 +237,21 @@ macro_rules! dispatch_wrapped_func{ } }; (format_address $field_name:ident, $func_name:ident) => { - unsafe extern "C" fn $func_name(formatter: *const ZydisFormatter, buffer: *mut *mut c_char, - len: usize, - instruction: *mut ZydisDecodedInstruction, - operand: *mut ZydisDecodedOperand, - address: u64) -> ZydisStatus { + unsafe extern "C" fn $func_name( + formatter: *const ZydisFormatter, buffer: *mut *mut c_char, + len: usize, + instruction: *mut ZydisDecodedInstruction, + operand: *mut ZydisDecodedOperand, + address: u64, + ) -> ZydisStatus { let formatter = &*(formatter as *const Formatter); - let r = match formatter.$field_name.as_ref().unwrap()(formatter, - &mut Buffer::new(buffer, len), - &*instruction, - &*operand, - address) { + let r = match formatter.$field_name.as_ref().unwrap()( + formatter, + &mut Buffer::new(buffer, len), + &*instruction, + &*operand, + address, + ) { Ok(_) => ZYDIS_STATUS_SUCCESS, Err(e) => e, }; From 46f6ccd1aead459278b9f1ac10bd7d84d2cc161d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Fri, 29 Sep 2017 18:08:31 +0200 Subject: [PATCH 7/8] Updated `zydis-c` to latest `develop` revision --- build.rs | 1 + src/utils.rs | 4 ++-- zydis-c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build.rs b/build.rs index ae00ef5..d1cbed4 100644 --- a/build.rs +++ b/build.rs @@ -35,6 +35,7 @@ fn build_library() { format!("{}/Encoder.c", ZYDIS_SRC_PATH), format!("{}/EncoderData.c", ZYDIS_SRC_PATH), format!("{}/Formatter.c", ZYDIS_SRC_PATH), + format!("{}/FormatHelper.c", ZYDIS_SRC_PATH), format!("{}/Mnemonic.c", ZYDIS_SRC_PATH), format!("{}/Register.c", ZYDIS_SRC_PATH), format!("{}/SharedData.c", ZYDIS_SRC_PATH), diff --git a/src/utils.rs b/src/utils.rs index 43e8492..fa97d37 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,7 +10,7 @@ impl ZydisDecodedInstruction { unsafe { let mut address = 0u64; check!( - ZydisUtilsCalcAbsoluteTargetAddress(self, operand, &mut address), + ZydisCalcAbsoluteAddress(self, operand, &mut address), address ) } @@ -22,7 +22,7 @@ impl ZydisDecodedInstruction { ) -> ZydisResult { unsafe { let mut code = uninitialized(); - check!(ZydisGetCPUFlagsByAction(self, action, &mut code), code) + check!(ZydisGetAccessedFlagsByAction(self, action, &mut code), code) } } } diff --git a/zydis-c b/zydis-c index fafa93d..ded9d0e 160000 --- a/zydis-c +++ b/zydis-c @@ -1 +1 @@ -Subproject commit fafa93d40ba6c09727b34c54e176ff983da1a540 +Subproject commit ded9d0e513a7a10e9e2636df6167d783cbe4b14d From fa5db421ecfa8505bfcfb80a579f7bcf5a0cb8b6 Mon Sep 17 00:00:00 2001 From: th0rex Date: Sat, 30 Sep 2017 12:41:27 +0200 Subject: [PATCH 8/8] Revert changing the backing type of mnemonics. This makes the code compile on stable but not on some nightly versions. --- src/decoder.rs | 2 +- src/mnemonic.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/decoder.rs b/src/decoder.rs index 435281f..246cdbb 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -51,7 +51,7 @@ impl Decoder { /// zydis::gen::ZYDIS_ADDRESS_WIDTH_64 /// ).unwrap(); /// let info = decoder.decode(INT3, 0x00400000).unwrap().unwrap(); - /// assert_eq!(info.mnemonic as i32, zydis::gen::ZYDIS_MNEMONIC_INT3); + /// assert_eq!(info.mnemonic as u32, zydis::gen::ZYDIS_MNEMONIC_INT3); /// ``` pub fn decode( &self, diff --git a/src/mnemonic.rs b/src/mnemonic.rs index 095d074..2c1e5c9 100644 --- a/src/mnemonic.rs +++ b/src/mnemonic.rs @@ -2,6 +2,7 @@ use gen::*; use std::ffi::CStr; +use std::os::raw::c_uint; /// Extensions for `ZydisMnemonic` pub trait ZydisMnemonicMethods { @@ -16,7 +17,7 @@ pub trait ZydisMnemonicMethods { fn get_string(self) -> Option<&'static str>; } -impl ZydisMnemonicMethods for i32 { +impl ZydisMnemonicMethods for c_uint { fn get_string(self) -> Option<&'static str> { unsafe { check_string!(ZydisMnemonicGetString(self as _)) } }