From e5baca6c314b276681c6ecfeb4e514351592b7e1 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 20 Feb 2025 01:33:44 +0200 Subject: [PATCH] start tracing call instructions --- Cargo.lock | 10 +++ crates/vestal/Cargo.toml | 1 + crates/vestal/src/main.rs | 182 ++++++++++++++++---------------------- crates/vestal/src/util.rs | 2 +- 4 files changed, 89 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d6f24a..a2d7891 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,6 +313,15 @@ dependencies = [ "cc", ] +[[package]] +name = "iced-x86" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b" +dependencies = [ + "lazy_static", +] + [[package]] name = "indexmap" version = "2.7.1" @@ -675,6 +684,7 @@ dependencies = [ "clap", "exe", "hexy", + "iced-x86", "object", "pretty-hex", "syscalls", diff --git a/crates/vestal/Cargo.toml b/crates/vestal/Cargo.toml index e53c7ee..55dcfb5 100644 --- a/crates/vestal/Cargo.toml +++ b/crates/vestal/Cargo.toml @@ -10,6 +10,7 @@ object = { version = "0.36.7", features = [ "read_core", "write_core", "elf", "p hexy = "0.1.4" pretty-hex = "0.4.1" exe = "0.5.6" +iced-x86 = "1.21.0" #elf = "0.7.4" #goblin = "0.9.3" #lancelot = "0.9.7" diff --git a/crates/vestal/src/main.rs b/crates/vestal/src/main.rs index 5583ac8..3794bff 100644 --- a/crates/vestal/src/main.rs +++ b/crates/vestal/src/main.rs @@ -38,32 +38,69 @@ struct Vestal { //path_to_exports: HashMap, Vec>, //path_to_imports: HashMap, Vec>, } -#[derive(Debug)] -struct Export { - id: u32, - name: Option>, - target: Target, -} -impl Export { - fn name_string (&self) -> Option { - String::from_utf8(self.name.as_ref()?.to_vec()).ok() - } - fn addr (&self) -> u32 { - if let Target::Addr(addr) = self.target { - addr - } else { - panic!("no addr") - } - } -} -#[derive(Debug)] -enum Target { - Addr(u32), - Name(Arc<[u8]>, Arc<[u8]>), -} -#[derive(Debug)] -struct Import {} impl Vestal { + fn run_main (&self, path: &PathBuf) -> Usually<()> { + let data = self.path_to_data.get(path); + let len = data.as_ref().unwrap().len(); + let data = data.as_ref().unwrap(); + println!(); + println!("{:?}", data[0..256].hex_dump()); + println!(); + for (dll_path, dll) in self.path_to_pe.iter() { + let ep_rva = dll.get_entrypoint()?; + let ep_off = dll.rva_to_offset(ep_rva)?; + println!("\n\n{:p} 0x{:x?} {:x?} {:x?}\n{dll_path:?}\n", + dll.as_ptr(), + dll.get_image_base()?, + ep_rva, + ep_off); + if dll_path.as_ref() == path { + let buf = dll.get_buffer(); + //println!("{:?}\n", &buf[0..128]); + //println!("{:?}\n", &buf[0x000c8900..0x000c8900+128].hex_dump()); + //println!("{:?}", &buf[0x000c9500..0x000c9500+128].hex_dump()); + let section = dll.get_section_by_name(".text")?; + let section_ptr = section.pointer_to_raw_data.0 as usize; + let section_len = section.size_of_raw_data as usize; + //println!("{section:?}"); + //println!("{:?}\n", &buf[section_ptr..section_ptr+128].hex_dump()); + //println!("{:?}", &buf[ep_off.0 as usize..ep_off.0 as usize+128].hex_dump()); + let section_data = &buf[section_ptr..section_ptr+section_len]; + println!("0x{:x}", section_data.len()); + let mut decoder = iced_x86::Decoder::with_ip(64, section_data, 0, 0); + while decoder.can_decode() { + let position = decoder.position(); + let instruction = decoder.decode(); + let opcodes = §ion_data[position..position+instruction.len()].iter().map(|x|format!("{x:>02x}")).collect::>().join(" "); + //println!("0x{position:08x} {opcodes:32} {instruction}"); + if instruction.is_call_far() { + //println!("0x{:08x} {}", decoder.position(), instruction); + } else if instruction.is_call_far_indirect() { + //println!("0x{:08x} {}", decoder.position(), instruction); + } else if instruction.is_call_near() { + //println!("0x{:08x} {}", decoder.position(), instruction); + } else if instruction.is_call_near_indirect() { + println!("0x{:08x} {opcodes:32} {instruction}", position+section_ptr); + //println!("0x{:08x} {}", decoder.position(), instruction); + return Ok(()) + } + } + } + } + //let exports = self.path_to_exports.get(path).expect("no exports"); + //for export in exports.iter() { + //if export.name_string() == Some("VSTPluginMain".to_string()) { + //println!("{export:?}"); + //println!("{}", export.name_string().unwrap()); + //let addr = (export.addr() as usize); + //println!(); + //println!(); + //return Ok(()) + //} + //} + //panic!("no main"); + Ok(()) + } fn resolve (&self, name: &str) -> Usually> { for base in self.search_paths.iter() { let mut path = base.clone(); @@ -77,28 +114,36 @@ impl Vestal { fn load (&mut self, path: &PathBuf) -> Usually<()> { if !self.paths_visited.contains(path) { let path = Arc::new(path.clone()); - println!("(load {path:?})"); + println!("\n(load {path:?})"); self.paths_visited.insert(path.clone()); let data = self.load_bang_data(&path)?; let dll = self.load_pe(&path, &data)?; let imports = self.load_imports(&path, &dll); let exports = self.load_exports(&path, &dll); - println!("(entrypoint {:?})", dll.get_entrypoint()?); } Ok(()) } fn load_imports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> { + let mut import_map = HashMap::new(); let directory = ImportDirectory::parse(dll)?; for descriptor in directory.descriptors { - print!(" (module {} ", descriptor.get_name(dll)?.as_str()?); + let dep = descriptor.get_name(dll)?.as_str()?; + let resolved = self.resolve(&dep)?.expect("no path for {name}"); + print!("\n (module\n {dep:?}\n {:?}", &resolved); + let mut imports = Vec::new(); for import in descriptor.get_imports(dll)? { match import { - ImportData::Ordinal(x) => print!("\n (ordi 0x{x:>04x})"), - ImportData::ImportByName(n) => print!("\n (name {n})"), + ImportData::Ordinal(x) => print!("\n (import-ordinal 0x{x:>04x})"), + ImportData::ImportByName(n) => print!("\n (import-by-name {n:?})"), } + imports.push(import); } + import_map.insert(dep, (resolved, imports)); println!(")") } + for (name, (path, imports)) in import_map.iter() { + self.load(path)?; + } Ok(()) } fn load_exports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> { @@ -108,10 +153,10 @@ impl Vestal { let (bang, data) = slice_shebang(read(path.as_path())?.as_slice()); self.path_to_bang.insert(path.clone(), bang.clone()); if bang.len() > 0 { - println!("(bang {path:?} {:x})", bang.len()) + println!(" (bang {path:?} {:x})", bang.len()) } self.path_to_data.insert(path.clone(), data.clone()); - println!("(buffer {:p} 0x{:08x} {path:?})", data.as_ptr(), data.len()); + println!(" (buffer {:p} 0x{:08x} {path:?})", data.as_ptr(), data.len()); Ok(data) } fn load_pe (&mut self, path: &Arc, data: &Arc<[u8]>) -> Usually> { @@ -119,77 +164,4 @@ impl Vestal { self.path_to_pe.insert(path.clone(), pe.clone()); Ok(pe) } - fn inspect (&self) { - //for (path, exports) in self.path_to_exports.iter() { - ////println!("(exports {path:?}\n {exports:?})") - //} - //for (path, imports) in self.path_to_imports.iter() { - ////print!("(imports {path:?}"); - ////for import in imports.iter() { - ////print!("\n {import:?}"); - ////} - ////println!(")"); - //} - } - fn run_main (&self, path: &PathBuf) -> Usually<()> { - let data = self.path_to_data.get(path); - let len = data.as_ref().unwrap().len(); - let data = data.as_ref().unwrap(); - println!(); - println!("{:?}", data[0..256].hex_dump()); - println!(); - //let exports = self.path_to_exports.get(path).expect("no exports"); - //for export in exports.iter() { - //if export.name_string() == Some("VSTPluginMain".to_string()) { - //println!("{export:?}"); - //println!("{}", export.name_string().unwrap()); - //let addr = (export.addr() as usize); - //println!(); - //println!("{:?}", data[addr..addr+512].hex_dump()); - //println!(); - //return Ok(()) - //} - //} - //panic!("no main"); - Ok(()) - } } - - //if let Some(exports) = dll.export_table()? { - //let mut collected = vec![]; - //for export_ref in exports.exports()?.iter() { - //collected.push(Export { - //id: export_ref.ordinal, - //name: export_ref.name.map(|name|name.into()), - //target: match export_ref.target { - //ExportTarget::Address(addr) => - //Target::Addr(addr), - //ExportTarget::ForwardByName(dll, name) => - //Target::Name(dll.into(), name.into()), - //_ => - //todo!("unsupported export target {:?}", &export_ref.target) - //} - //}); - //} - //self.path_to_exports.insert(path.clone(), collected); - //} - //if let Some(imports) = dll.import_table()? { - //let mut collected = vec![]; - //for import in imports.descriptors()? { - //let name = imports.name(import?.name.get(LittleEndian))?.to_vec(); - //let name = String::from_utf8(name.to_vec())?; - //let name = name.to_lowercase(); - //if let Some(path) = self.resolve(&name)? { - //if !self.paths_visited.contains(&path) { - ////println!("(import {name:?})"); - //self.load(&path)?; - //} - //} else { - //panic!("not found: {name:?}"); - //} - //} - //self.path_to_imports.insert(path.clone(), collected); - //} - //} - //Ok(()) - //} diff --git a/crates/vestal/src/util.rs b/crates/vestal/src/util.rs index c07d32e..9392e1b 100644 --- a/crates/vestal/src/util.rs +++ b/crates/vestal/src/util.rs @@ -11,7 +11,7 @@ pub(crate) use ::object::endian::LittleEndian; //pub(crate) use ::object::read::pe::{PeFile, ExportTarget}; pub(crate) use ::object::write::elf::Writer as ElfWriter; pub(crate) use ::pretty_hex::*; -pub(crate) use ::exe::{PE, VecPE, PtrPE, types::*, headers::*}; +pub(crate) use ::exe::{Buffer, PE, VecPE, PtrPE, types::*, headers::*}; pub(crate) type Usually = Result>; /// You can manually patch DLLs by prepending /// a `#!/usr/bin/env vestal` line to them.