From 35e4f3d7c9ad57a087bfba1a7837fac4a250eb99 Mon Sep 17 00:00:00 2001 From: denis Date: Mon, 20 Sep 2021 08:59:58 -0400 Subject: [PATCH 1/8] first iteration of recursive --- capstone-rs/Cargo.toml | 1 + capstone-rs/examples/recursive.rs | 97 +++++++++++++++++++++++++++++++ capstone-rs/src/capstone.rs | 33 +++++++++++ 3 files changed, 131 insertions(+) create mode 100644 capstone-rs/examples/recursive.rs diff --git a/capstone-rs/Cargo.toml b/capstone-rs/Cargo.toml index 37d4bc23..7cdd58ae 100644 --- a/capstone-rs/Cargo.toml +++ b/capstone-rs/Cargo.toml @@ -22,6 +22,7 @@ libc = { version = "0.2", default-features = false } macho = "0.*" criterion = "0.3" rayon = "1.1" +object = "0.26.2" [[bench]] name = "my_benchmark" diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs new file mode 100644 index 00000000..8775faab --- /dev/null +++ b/capstone-rs/examples/recursive.rs @@ -0,0 +1,97 @@ +use std::collections::{HashMap, VecDeque}; +use std::env; +use std::fs; +use std::process; + +use capstone; +use capstone::prelude::*; +use capstone::Insn; +use object::{Object, ObjectSection}; + +fn main() { + let cs = if let Ok(cs) = Capstone::new() + .x86() + .mode(arch::x86::ArchMode::Mode64) + .detail(true) + .build() + { + cs + } else { + eprintln!("failed to create capstone handle"); + process::exit(-1); + }; + + let args: Vec<_> = env::args().collect(); + if args.len() != 2 { + eprintln!("Usage: {} ", args[0]); + process::exit(-1); + } + + let buf = if let Ok(bd) = fs::read(&args[1]) { + bd + } else { + eprintln!("cannot read file"); + process::exit(-1); + }; + + let obj = if let Ok(od) = object::File::parse(&*buf) { + od + } else { + eprintln!("cannot parse file"); + process::exit(-1); + }; + + let (sec_addr, sec_text) = if let Some(section) = obj.section_by_name(".text") { + if let Ok(data) = section.data() { + (section.address(), data) + } else { + eprintln!("cannot get data from .text section"); + process::exit(1); + } + } else { + eprintln!("no section .text found"); + process::exit(2); + }; + + println!( + ".text section addr: {:#02x?} size: {:#02x?}", + sec_addr, + sec_text.len() + ); + + let mut addr_queue: VecDeque = VecDeque::new(); + let mut addr_seen: HashMap = HashMap::new(); + + let cs_ins = cs.malloc(); + assert!(!cs_ins.is_null()); + + addr_queue.push_back(obj.entry()); + + while !addr_queue.is_empty() { + let mut addr = addr_queue.pop_front().unwrap(); + if let Some(_) = addr_seen.get(&addr) { + continue; + } + addr_seen.insert(addr, true); + + println!("addr: {:#02x?}", addr); + + let mut offset = (addr - sec_addr) as usize; + loop { + let (ret, o, a) = cs.disasm_iter(&sec_text, offset, addr, cs_ins); + if !ret { + break; + } + offset = o; + addr = a; + + let ins = unsafe { Insn::from_raw(cs_ins) }; + println!("{}", ins); + if ins.id() == InsnId(arch::x86::X86Insn::X86_INS_HLT as u32) { + break; + } + } + } + + cs.free(cs_ins); +} diff --git a/capstone-rs/src/capstone.rs b/capstone-rs/src/capstone.rs index 19af21ee..3094d299 100644 --- a/capstone-rs/src/capstone.rs +++ b/capstone-rs/src/capstone.rs @@ -165,6 +165,39 @@ impl Capstone { } } + pub fn malloc<'a>(&'a self) -> *mut cs_insn { + unsafe { cs_malloc(self.csh()) } + } + + pub fn free<'a>(&'a self, insn: *mut cs_insn) { + unsafe { + cs_free(insn, 1); + } + } + + pub fn disasm_iter<'a>( + &'a self, + code: &[u8], + offset: usize, + addr: u64, + insns: *mut cs_insn, + ) -> (bool, usize, u64) { + let code_len = code.len(); + let code_ptr = &mut code[offset..].as_ptr(); + let mut c = code_len - offset; + let mut a = addr; + let ret = unsafe { + cs_disasm_iter( + self.csh(), // capstone handle + code_ptr, // double pointer to code to disassemble; automatically incremented + &mut c, // number of bytes left to disassemble; automatically decremented + &mut a, // automatically incremented address + insns, // pointer to cs_insn object + ) + }; + (ret, code_len - c, a) // ret: true|false code disassembled or not, next offset, next addr + } + /// Disassemble all instructions in buffer /// /// ``` From 82a632a194feff4c2db3f887690c2ca3ff081821 Mon Sep 17 00:00:00 2001 From: denis Date: Mon, 20 Sep 2021 23:07:35 -0400 Subject: [PATCH 2/8] better api for recursive disasm --- capstone-rs/examples/recursive.rs | 65 +++++++++---------- capstone-rs/src/capstone.rs | 100 +++++++++++++++++++++--------- 2 files changed, 101 insertions(+), 64 deletions(-) diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs index 8775faab..f2f395ed 100644 --- a/capstone-rs/examples/recursive.rs +++ b/capstone-rs/examples/recursive.rs @@ -3,24 +3,13 @@ use std::env; use std::fs; use std::process; +use object::{Object, ObjectSection}; + use capstone; use capstone::prelude::*; -use capstone::Insn; -use object::{Object, ObjectSection}; +use capstone::arch::x86::X86Insn; fn main() { - let cs = if let Ok(cs) = Capstone::new() - .x86() - .mode(arch::x86::ArchMode::Mode64) - .detail(true) - .build() - { - cs - } else { - eprintln!("failed to create capstone handle"); - process::exit(-1); - }; - let args: Vec<_> = env::args().collect(); if args.len() != 2 { eprintln!("Usage: {} ", args[0]); @@ -62,13 +51,23 @@ fn main() { let mut addr_queue: VecDeque = VecDeque::new(); let mut addr_seen: HashMap = HashMap::new(); - let cs_ins = cs.malloc(); - assert!(!cs_ins.is_null()); - addr_queue.push_back(obj.entry()); + let cs = if let Ok(cs) = Capstone::new() + .x86() + .mode(arch::x86::ArchMode::Mode64) + .detail(true) + .build() + { + cs + } else { + eprintln!("failed to create capstone handle"); + process::exit(-1); + }; + + let mut disasm = cs.get_disasm_iter(); while !addr_queue.is_empty() { - let mut addr = addr_queue.pop_front().unwrap(); + let addr = addr_queue.pop_front().unwrap(); if let Some(_) = addr_seen.get(&addr) { continue; } @@ -76,22 +75,20 @@ fn main() { println!("addr: {:#02x?}", addr); - let mut offset = (addr - sec_addr) as usize; - loop { - let (ret, o, a) = cs.disasm_iter(&sec_text, offset, addr, cs_ins); - if !ret { - break; - } - offset = o; - addr = a; - - let ins = unsafe { Insn::from_raw(cs_ins) }; - println!("{}", ins); - if ins.id() == InsnId(arch::x86::X86Insn::X86_INS_HLT as u32) { - break; - } + let offset = (addr - sec_addr) as usize; + let mut cur_insn = disasm.disasm_iter(&sec_text, offset, addr); + while let Ok(insn) = cur_insn { + if insn.id() == InsnId(X86Insn::X86_INS_INVALID as u32){ + break; + } + println!("{}", insn); + if insn.id() == InsnId(X86Insn::X86_INS_HLT as u32) { + break; + } + // other logic here can add more targets to the addr_queue + // ... + + cur_insn = disasm.disasm_iter_continue(&sec_text); } } - - cs.free(cs_ins); } diff --git a/capstone-rs/src/capstone.rs b/capstone-rs/src/capstone.rs index 3094d299..1c7a6ed3 100644 --- a/capstone-rs/src/capstone.rs +++ b/capstone-rs/src/capstone.rs @@ -165,39 +165,18 @@ impl Capstone { } } - pub fn malloc<'a>(&'a self) -> *mut cs_insn { - unsafe { cs_malloc(self.csh()) } - } - - pub fn free<'a>(&'a self, insn: *mut cs_insn) { - unsafe { - cs_free(insn, 1); + /// Creates an instance of DisasmIter structure + /// + pub fn get_disasm_iter<'a>(&'a self) -> DisasmIter<'a> { + DisasmIter { + insn: unsafe { cs_malloc(self.csh()) }, + csh: self.csh, + _covariant: PhantomData, + offset: 0, + addr: 0, } } - pub fn disasm_iter<'a>( - &'a self, - code: &[u8], - offset: usize, - addr: u64, - insns: *mut cs_insn, - ) -> (bool, usize, u64) { - let code_len = code.len(); - let code_ptr = &mut code[offset..].as_ptr(); - let mut c = code_len - offset; - let mut a = addr; - let ret = unsafe { - cs_disasm_iter( - self.csh(), // capstone handle - code_ptr, // double pointer to code to disassemble; automatically incremented - &mut c, // number of bytes left to disassemble; automatically decremented - &mut a, // automatically incremented address - insns, // pointer to cs_insn object - ) - }; - (ret, code_len - c, a) // ret: true|false code disassembled or not, next offset, next addr - } - /// Disassemble all instructions in buffer /// /// ``` @@ -456,3 +435,64 @@ impl Drop for Capstone { unsafe { cs_close(&mut self.csh()) }; } } + +/// Structure to handle iterative disassembly +/// +/// Create with a capstone instance `get_disasm_iter()` +/// +pub struct DisasmIter<'a> { + insn: *mut cs_insn, // space for current instruction to be processed + csh: *mut c_void, // reference to the the capstone handle required by disasm_iter + offset: usize, + addr: u64, + _covariant: PhantomData<&'a ()>, // used to make sure DIasmIter lifetime doesn't exceed Capstone's lifetime +} + +impl<'a> Drop for DisasmIter<'a> { + fn drop(&mut self) { + unsafe { cs_free(self.insn, 1) }; + } +} + +impl<'a> DisasmIter<'a> { + /// Used to continue to the next instruction without jumping + /// + /// usage shown in examples/recursive.rs + pub fn disasm_iter_continue(&mut self, code: &[u8]) -> CsResult { + self.disasm_iter(code, self.offset, self.addr) + } + + /// Used to start the iterative disassembly + /// + /// usage shown in examples/recursive.rs + pub fn disasm_iter(&mut self, code: &[u8], offset: usize, addr: u64) -> CsResult { + let code_len = code.len(); + let code_ptr = &mut code[offset..].as_ptr(); + let mut c = code_len - offset; + let mut a = addr; + let ret = unsafe { + cs_disasm_iter( + self.csh as csh, // capstone handle + code_ptr, // double pointer to code to disassemble; automatically incremented + &mut c, // number of bytes left to disassemble; automatically decremented + &mut a, // automatically incremented address + self.insn, // pointer to cs_insn object + ) + }; + if ret { + self.offset = code_len - c; + self.addr = a; + let insn = unsafe {Insn::from_raw(self.insn)}; + Ok(insn) + } else { + Err(Error::CustomError("not disasm")) + } + } + + pub fn offset(&self) -> usize { + self.offset + } + pub fn addr(&self) -> u64 { + self.addr + } +} From dc4f0b791bf15c7b1e6f231716362a5b5e914d8e Mon Sep 17 00:00:00 2001 From: denis Date: Mon, 20 Sep 2021 23:09:33 -0400 Subject: [PATCH 3/8] I always forget fmt --- capstone-rs/examples/recursive.rs | 24 ++++++++--------- capstone-rs/src/capstone.rs | 44 +++++++++++++++---------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs index f2f395ed..31467955 100644 --- a/capstone-rs/examples/recursive.rs +++ b/capstone-rs/examples/recursive.rs @@ -6,8 +6,8 @@ use std::process; use object::{Object, ObjectSection}; use capstone; -use capstone::prelude::*; use capstone::arch::x86::X86Insn; +use capstone::prelude::*; fn main() { let args: Vec<_> = env::args().collect(); @@ -76,18 +76,18 @@ fn main() { println!("addr: {:#02x?}", addr); let offset = (addr - sec_addr) as usize; - let mut cur_insn = disasm.disasm_iter(&sec_text, offset, addr); + let mut cur_insn = disasm.disasm_iter(&sec_text, offset, addr); while let Ok(insn) = cur_insn { - if insn.id() == InsnId(X86Insn::X86_INS_INVALID as u32){ - break; - } - println!("{}", insn); - if insn.id() == InsnId(X86Insn::X86_INS_HLT as u32) { - break; - } - // other logic here can add more targets to the addr_queue - // ... - + if insn.id() == InsnId(X86Insn::X86_INS_INVALID as u32) { + break; + } + println!("{}", insn); + if insn.id() == InsnId(X86Insn::X86_INS_HLT as u32) { + break; + } + // other logic here can add more targets to the addr_queue + // ... + cur_insn = disasm.disasm_iter_continue(&sec_text); } } diff --git a/capstone-rs/src/capstone.rs b/capstone-rs/src/capstone.rs index 1c7a6ed3..de41242f 100644 --- a/capstone-rs/src/capstone.rs +++ b/capstone-rs/src/capstone.rs @@ -165,8 +165,8 @@ impl Capstone { } } - /// Creates an instance of DisasmIter structure - /// + /// Creates an instance of DisasmIter structure + /// pub fn get_disasm_iter<'a>(&'a self) -> DisasmIter<'a> { DisasmIter { insn: unsafe { cs_malloc(self.csh()) }, @@ -441,8 +441,8 @@ impl Drop for Capstone { /// Create with a capstone instance `get_disasm_iter()` /// pub struct DisasmIter<'a> { - insn: *mut cs_insn, // space for current instruction to be processed - csh: *mut c_void, // reference to the the capstone handle required by disasm_iter + insn: *mut cs_insn, // space for current instruction to be processed + csh: *mut c_void, // reference to the the capstone handle required by disasm_iter offset: usize, addr: u64, _covariant: PhantomData<&'a ()>, // used to make sure DIasmIter lifetime doesn't exceed Capstone's lifetime @@ -455,16 +455,16 @@ impl<'a> Drop for DisasmIter<'a> { } impl<'a> DisasmIter<'a> { - /// Used to continue to the next instruction without jumping - /// - /// usage shown in examples/recursive.rs - pub fn disasm_iter_continue(&mut self, code: &[u8]) -> CsResult { - self.disasm_iter(code, self.offset, self.addr) - } - - /// Used to start the iterative disassembly - /// - /// usage shown in examples/recursive.rs + /// Used to continue to the next instruction without jumping + /// + /// usage shown in examples/recursive.rs + pub fn disasm_iter_continue(&mut self, code: &[u8]) -> CsResult { + self.disasm_iter(code, self.offset, self.addr) + } + + /// Used to start the iterative disassembly + /// + /// usage shown in examples/recursive.rs pub fn disasm_iter(&mut self, code: &[u8], offset: usize, addr: u64) -> CsResult { let code_len = code.len(); let code_ptr = &mut code[offset..].as_ptr(); @@ -480,9 +480,9 @@ impl<'a> DisasmIter<'a> { ) }; if ret { - self.offset = code_len - c; - self.addr = a; - let insn = unsafe {Insn::from_raw(self.insn)}; + self.offset = code_len - c; + self.addr = a; + let insn = unsafe { Insn::from_raw(self.insn) }; Ok(insn) } else { Err(Error::CustomError("not disasm")) @@ -490,9 +490,9 @@ impl<'a> DisasmIter<'a> { } pub fn offset(&self) -> usize { - self.offset - } - pub fn addr(&self) -> u64 { - self.addr - } + self.offset + } + pub fn addr(&self) -> u64 { + self.addr + } } From 017614f2269d02a793c15c7c998862a34737b5c2 Mon Sep 17 00:00:00 2001 From: denis Date: Tue, 21 Sep 2021 00:09:55 -0400 Subject: [PATCH 4/8] better example --- capstone-rs/examples/recursive.rs | 47 +++++++++++++------------------ 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs index 31467955..4b594179 100644 --- a/capstone-rs/examples/recursive.rs +++ b/capstone-rs/examples/recursive.rs @@ -3,7 +3,7 @@ use std::env; use std::fs; use std::process; -use object::{Object, ObjectSection}; +use object::{Object, ObjectSection, SectionKind}; use capstone; use capstone::arch::x86::X86Insn; @@ -30,28 +30,16 @@ fn main() { process::exit(-1); }; - let (sec_addr, sec_text) = if let Some(section) = obj.section_by_name(".text") { - if let Ok(data) = section.data() { - (section.address(), data) - } else { - eprintln!("cannot get data from .text section"); - process::exit(1); - } - } else { - eprintln!("no section .text found"); - process::exit(2); - }; - - println!( - ".text section addr: {:#02x?} size: {:#02x?}", - sec_addr, - sec_text.len() - ); - let mut addr_queue: VecDeque = VecDeque::new(); let mut addr_seen: HashMap = HashMap::new(); - addr_queue.push_back(obj.entry()); + for section in obj.sections() { + if section.kind() == SectionKind::Text { + println!("{:x?} ", section); + addr_queue.push_back(section.address()); + } + } + let cs = if let Ok(cs) = Capstone::new() .x86() .mode(arch::x86::ArchMode::Mode64) @@ -73,22 +61,27 @@ fn main() { } addr_seen.insert(addr, true); - println!("addr: {:#02x?}", addr); + println!("---> addr: {:#02x?}", addr); - let offset = (addr - sec_addr) as usize; - let mut cur_insn = disasm.disasm_iter(&sec_text, offset, addr); + let offset = addr as usize; + let mut cur_insn = disasm.disasm_iter(&buf, offset, addr); while let Ok(insn) = cur_insn { if insn.id() == InsnId(X86Insn::X86_INS_INVALID as u32) { break; } println!("{}", insn); - if insn.id() == InsnId(X86Insn::X86_INS_HLT as u32) { - break; + match X86Insn::from(insn.id().0) { + X86Insn::X86_INS_HLT => break, + X86Insn::X86_INS_CALL => break, + X86Insn::X86_INS_JMP => break, + X86Insn::X86_INS_RET => break, + _ => {} } - // other logic here can add more targets to the addr_queue + + // add logic here to add more targets to the addr_queue // ... - cur_insn = disasm.disasm_iter_continue(&sec_text); + cur_insn = disasm.disasm_iter_continue(&buf); } } } From 1b3d22a1981afac9d25be522d7010d8c83391d4b Mon Sep 17 00:00:00 2001 From: denis Date: Tue, 21 Sep 2021 21:33:45 -0400 Subject: [PATCH 5/8] applying changes based on the feedback --- capstone-rs/examples/recursive.rs | 63 ++++++++++++++++++------------- capstone-rs/src/capstone.rs | 18 +++++---- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs index 4b594179..39b56ac6 100644 --- a/capstone-rs/examples/recursive.rs +++ b/capstone-rs/examples/recursive.rs @@ -1,4 +1,7 @@ -use std::collections::{HashMap, VecDeque}; +//! This example shows how to do recursive disassemble +//! The example is written specificly for X86 ELF binary format +//! +use std::collections::{HashSet, VecDeque}; use std::env; use std::fs; use std::process; @@ -6,8 +9,8 @@ use std::process; use object::{Object, ObjectSection, SectionKind}; use capstone; -use capstone::arch::x86::X86Insn; use capstone::prelude::*; +use capstone::InsnGroupType; fn main() { let args: Vec<_> = env::args().collect(); @@ -16,22 +19,12 @@ fn main() { process::exit(-1); } - let buf = if let Ok(bd) = fs::read(&args[1]) { - bd - } else { - eprintln!("cannot read file"); - process::exit(-1); - }; + let buf = fs::read(&args[1]).expect("cannot read file"); - let obj = if let Ok(od) = object::File::parse(&*buf) { - od - } else { - eprintln!("cannot parse file"); - process::exit(-1); - }; + let obj = object::File::parse(&*buf).expect("cannot parse file"); let mut addr_queue: VecDeque = VecDeque::new(); - let mut addr_seen: HashMap = HashMap::new(); + let mut addr_seen: HashSet = HashSet::new(); for section in obj.sections() { if section.kind() == SectionKind::Text { @@ -54,28 +47,24 @@ fn main() { let mut disasm = cs.get_disasm_iter(); - while !addr_queue.is_empty() { - let addr = addr_queue.pop_front().unwrap(); - if let Some(_) = addr_seen.get(&addr) { + while let Some(addr) = addr_queue.pop_front(){ + if addr_seen.contains(&addr) { continue; } - addr_seen.insert(addr, true); + addr_seen.insert(addr); println!("---> addr: {:#02x?}", addr); let offset = addr as usize; let mut cur_insn = disasm.disasm_iter(&buf, offset, addr); while let Ok(insn) = cur_insn { - if insn.id() == InsnId(X86Insn::X86_INS_INVALID as u32) { + let insn_detail: InsnDetail = cs.insn_detail(&insn).unwrap(); + if is_invalid_insn(&insn_detail) { break; } println!("{}", insn); - match X86Insn::from(insn.id().0) { - X86Insn::X86_INS_HLT => break, - X86Insn::X86_INS_CALL => break, - X86Insn::X86_INS_JMP => break, - X86Insn::X86_INS_RET => break, - _ => {} + if is_unconditional_cflow_insn(&insn_detail) { + break; } // add logic here to add more targets to the addr_queue @@ -85,3 +74,25 @@ fn main() { } } } + +fn is_invalid_insn(insn_detail: &InsnDetail) -> bool { + for insn_grp in insn_detail.groups() { + if insn_grp.0 as u32 == InsnGroupType::CS_GRP_INVALID { + return true; + } + } + false +} + +fn is_unconditional_cflow_insn(insn_detail: &InsnDetail) -> bool { + for insn_grp in insn_detail.groups() { + match insn_grp.0 as u32 { + InsnGroupType::CS_GRP_JUMP | + InsnGroupType::CS_GRP_CALL | + InsnGroupType::CS_GRP_RET => return true, + _ => {} + } + } + false +} + diff --git a/capstone-rs/src/capstone.rs b/capstone-rs/src/capstone.rs index de41242f..c919b49b 100644 --- a/capstone-rs/src/capstone.rs +++ b/capstone-rs/src/capstone.rs @@ -168,8 +168,12 @@ impl Capstone { /// Creates an instance of DisasmIter structure /// pub fn get_disasm_iter<'a>(&'a self) -> DisasmIter<'a> { + let insn = unsafe { cs_malloc(self.csh()) }; + if let Err(e) = self.error_result() { + panic!("{}",e); + } DisasmIter { - insn: unsafe { cs_malloc(self.csh()) }, + insn: insn, csh: self.csh, _covariant: PhantomData, offset: 0, @@ -468,20 +472,20 @@ impl<'a> DisasmIter<'a> { pub fn disasm_iter(&mut self, code: &[u8], offset: usize, addr: u64) -> CsResult { let code_len = code.len(); let code_ptr = &mut code[offset..].as_ptr(); - let mut c = code_len - offset; - let mut a = addr; + let mut count = code_len - offset; + let mut local_addr = addr; let ret = unsafe { cs_disasm_iter( self.csh as csh, // capstone handle code_ptr, // double pointer to code to disassemble; automatically incremented - &mut c, // number of bytes left to disassemble; automatically decremented - &mut a, // automatically incremented address + &mut count, // number of bytes left to disassemble; automatically decremented + &mut local_addr, // automatically incremented address self.insn, // pointer to cs_insn object ) }; if ret { - self.offset = code_len - c; - self.addr = a; + self.offset = code_len - count; + self.addr = local_addr; let insn = unsafe { Insn::from_raw(self.insn) }; Ok(insn) } else { From f1ac14a348bf694e86a6abc2a18e6b7d20f2a328 Mon Sep 17 00:00:00 2001 From: denis Date: Tue, 21 Sep 2021 21:35:47 -0400 Subject: [PATCH 6/8] I really have an issue with this :D --- capstone-rs/examples/recursive.rs | 9 ++++----- capstone-rs/src/capstone.rs | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs index 39b56ac6..5fa9abf8 100644 --- a/capstone-rs/examples/recursive.rs +++ b/capstone-rs/examples/recursive.rs @@ -47,7 +47,7 @@ fn main() { let mut disasm = cs.get_disasm_iter(); - while let Some(addr) = addr_queue.pop_front(){ + while let Some(addr) = addr_queue.pop_front() { if addr_seen.contains(&addr) { continue; } @@ -87,12 +87,11 @@ fn is_invalid_insn(insn_detail: &InsnDetail) -> bool { fn is_unconditional_cflow_insn(insn_detail: &InsnDetail) -> bool { for insn_grp in insn_detail.groups() { match insn_grp.0 as u32 { - InsnGroupType::CS_GRP_JUMP | - InsnGroupType::CS_GRP_CALL | - InsnGroupType::CS_GRP_RET => return true, + InsnGroupType::CS_GRP_JUMP | InsnGroupType::CS_GRP_CALL | InsnGroupType::CS_GRP_RET => { + return true + } _ => {} } } false } - diff --git a/capstone-rs/src/capstone.rs b/capstone-rs/src/capstone.rs index c919b49b..02e71b6c 100644 --- a/capstone-rs/src/capstone.rs +++ b/capstone-rs/src/capstone.rs @@ -170,7 +170,7 @@ impl Capstone { pub fn get_disasm_iter<'a>(&'a self) -> DisasmIter<'a> { let insn = unsafe { cs_malloc(self.csh()) }; if let Err(e) = self.error_result() { - panic!("{}",e); + panic!("{}", e); } DisasmIter { insn: insn, @@ -478,8 +478,8 @@ impl<'a> DisasmIter<'a> { cs_disasm_iter( self.csh as csh, // capstone handle code_ptr, // double pointer to code to disassemble; automatically incremented - &mut count, // number of bytes left to disassemble; automatically decremented - &mut local_addr, // automatically incremented address + &mut count, // number of bytes left to disassemble; automatically decremented + &mut local_addr, // automatically incremented address self.insn, // pointer to cs_insn object ) }; From 3afaf140f4646cfb1e644e53da23f9ecd3d27a63 Mon Sep 17 00:00:00 2001 From: denis Date: Tue, 21 Sep 2021 22:17:13 -0400 Subject: [PATCH 7/8] helper function + fmt --- capstone-rs/examples/recursive.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs index 5fa9abf8..568ae190 100644 --- a/capstone-rs/examples/recursive.rs +++ b/capstone-rs/examples/recursive.rs @@ -33,17 +33,12 @@ fn main() { } } - let cs = if let Ok(cs) = Capstone::new() + let cs = Capstone::new() .x86() .mode(arch::x86::ArchMode::Mode64) .detail(true) .build() - { - cs - } else { - eprintln!("failed to create capstone handle"); - process::exit(-1); - }; + .expect("failed to create capstone handle"); let mut disasm = cs.get_disasm_iter(); @@ -63,7 +58,7 @@ fn main() { break; } println!("{}", insn); - if is_unconditional_cflow_insn(&insn_detail) { + if is_cflow_insn(&insn_detail) { break; } @@ -84,14 +79,21 @@ fn is_invalid_insn(insn_detail: &InsnDetail) -> bool { false } -fn is_unconditional_cflow_insn(insn_detail: &InsnDetail) -> bool { +fn is_cflow_insn(insn_detail: &InsnDetail) -> bool { for insn_grp in insn_detail.groups() { - match insn_grp.0 as u32 { - InsnGroupType::CS_GRP_JUMP | InsnGroupType::CS_GRP_CALL | InsnGroupType::CS_GRP_RET => { - return true - } - _ => {} + if is_cflow_group(insn_grp) { + return true; } } false } + +fn is_cflow_group(insn_group: &InsnGroupId) -> bool { + match insn_group.0 as u32 { + InsnGroupType::CS_GRP_JUMP + | InsnGroupType::CS_GRP_CALL + | InsnGroupType::CS_GRP_RET + | InsnGroupType::CS_GRP_IRET => true, + _ => false, + } +} From 06dbfb6dc479f9d27ac03e05ca53939d0d79c80f Mon Sep 17 00:00:00 2001 From: denis Date: Wed, 22 Sep 2021 21:40:55 -0400 Subject: [PATCH 8/8] panic on null for malloc --- capstone-rs/examples/recursive.rs | 3 ++- capstone-rs/src/capstone.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/capstone-rs/examples/recursive.rs b/capstone-rs/examples/recursive.rs index 568ae190..4f61d813 100644 --- a/capstone-rs/examples/recursive.rs +++ b/capstone-rs/examples/recursive.rs @@ -1,5 +1,6 @@ //! This example shows how to do recursive disassemble -//! The example is written specificly for X86 ELF binary format +//! The example is written specificly for X86 ELF binary format with PIE enabled +//! If PIE is disabled `gcc -no-pie ...` offset needs to be properly calculated //! use std::collections::{HashSet, VecDeque}; use std::env; diff --git a/capstone-rs/src/capstone.rs b/capstone-rs/src/capstone.rs index 02e71b6c..a7b852a5 100644 --- a/capstone-rs/src/capstone.rs +++ b/capstone-rs/src/capstone.rs @@ -169,8 +169,8 @@ impl Capstone { /// pub fn get_disasm_iter<'a>(&'a self) -> DisasmIter<'a> { let insn = unsafe { cs_malloc(self.csh()) }; - if let Err(e) = self.error_result() { - panic!("{}", e); + if insn.is_null() { + panic!("cs_malloc() failed"); } DisasmIter { insn: insn,