diff --git a/crates/vestal/src/load.rs b/crates/vestal/src/load.rs index 95f2a64..1bff67b 100644 --- a/crates/vestal/src/load.rs +++ b/crates/vestal/src/load.rs @@ -33,7 +33,7 @@ impl Vestal { let ilt = descriptor.get_original_first_thunk(dll)?; let lookups = descriptor.get_lookup_thunks(dll)?; let resolved = Arc::new(self.resolve(&dep)?.expect("no path for {name}")); - print!("\n (module {BOLD}{dep:?}{RESET} N=0x{:>08x} IAT=0x{:>08x} ILT=0x{:>08x}\n {resolved:?}", + print!(" (module {BOLD}{dep:?}{RESET} N=0x{:>08x} IAT=0x{:>08x} ILT=0x{:>08x}\n {resolved:?}", &descriptor.name.0, &descriptor.first_thunk.0, &descriptor.original_first_thunk.0); @@ -56,13 +56,13 @@ impl Vestal { let call_via = descriptor.first_thunk.0 + index as u32 * 8; let name = match import { ImportData::Ordinal(x) => { - print!("\n (import-ordinal {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} 0x{:>04x})", - call_via, thunk, orig, lookup, x); + //print!("\n (import-ordinal {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} 0x{:>04x})", + //call_via, thunk, orig, lookup, x); format!("___VESTAL___ORD___{x}___") }, ImportData::ImportByName(name) => { - print!("\n (import-by-name {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} {:?})", - call_via, thunk, orig, lookup, name); + //print!("\n (import-by-name {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} {:?})", + //call_via, thunk, orig, lookup, name); format!("{name}") }, }; diff --git a/crates/vestal/src/main.rs b/crates/vestal/src/main.rs index e138c32..6ee589c 100644 --- a/crates/vestal/src/main.rs +++ b/crates/vestal/src/main.rs @@ -1,6 +1,7 @@ #![feature(slice_split_once)] mod util; mod load; +mod show; pub(crate) use self::util::*; use clap::{arg, command, value_parser, ArgAction, Command}; fn main () -> Usually<()> { @@ -42,114 +43,17 @@ impl Vestal { fn enter (&mut self, path: &PathBuf) -> Usually<()> { let mut total = 0usize; self.load(&path)?; - let data = self.path_to_data.get(path); - let len = data.as_ref().unwrap().len(); - let data = data.as_ref().unwrap(); - //println!(); - //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 true || dll_path.as_ref() == path { - let dll_data = self.path_to_data.get(dll_path).unwrap(); - total += dll_data.len(); - println!("{:?}", dll_data.hex_dump()); - let buf = dll.get_buffer(); - 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; - let section_data = &buf[section_ptr..section_ptr+section_len]; - let mut decoder = iced_x86::Decoder::with_ip(64, section_data, 0x1000, 0); - while decoder.can_decode() { - let position = decoder.position(); - let instruction = decoder.decode(); - let opcodes = §ion_data[position..position+instruction.len()]; - //println!("0x{position:08x} {opcodes:32} {instruction}"); - if (instruction.flow_control() == iced_x86::FlowControl::IndirectBranch - || instruction.flow_control() == iced_x86::FlowControl::IndirectCall) - && instruction.op0_kind() == iced_x86::OpKind::Memory { - match opcodes[0] { - 0xff => match opcodes[1] { - 0x10 | 0x12 | 0x13 | - 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 | - 0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => continue, - _ => {}, - }, - 0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] { - 0xff => continue, - _ => {}, - }, - 0x48 => match opcodes[2] { - 0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => continue, - _ => {}, - }, - _ => {} - } - let offset = (position + section_ptr) as u32; - let offset_rva = dll.offset_to_rva(Offset(offset))?.0; - let call_target = match opcodes[0] { - 0xff => match opcodes[1] { - 0x15 | 0x25 => - offset_rva + opcodes.len() as u32 + u32::from_le_bytes([ - opcodes[2], - opcodes[3], - opcodes[4], - opcodes[5] - ]), - _ => 0x0 - }, - 0x48 => match opcodes[1] { - 0xff => match opcodes[2] { - 0x15 | 0x25 => - offset_rva + opcodes.len() as u32 + u32::from_le_bytes([ - opcodes[3], - opcodes[4], - opcodes[5], - opcodes[6] - ]), - _ => 0x0 - }, - _ => 0x0 - } - _ => 0x0 - }; - println!("{BOLD}{:20?}{RESET} O=0x{:08x} {BOLD}R=0x{:08x}{RESET} {:25} {:40} 0x{:08x} {:?}", - dll_path.file_name().unwrap(), - offset, - offset_rva, - opcodes.iter().map(|x|format!("{x:>02x}")).collect::>().join(" "), - instruction, - call_target, - self.addr_to_import.get(&call_target)); - //println!("0x{:08x} {}", decoder.position(), instruction); - //return Ok(()) - } - } - } + self.show_dll(dll_path)?; + let dll_data = self.path_to_data.get(dll_path).unwrap(); + let len = dll_data.len(); + println!(" (bytes {len} 0x{len:x})"); + self.show_calls(dll_path, dll_path.as_ref() == path)?; + total += len; + //println!("{:?}", dll_data.hex_dump()); } - //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"); - for addr in self.addr_to_import.keys() { - let (dll, export) = self.addr_to_import.get(addr).unwrap(); - println!("{BOLD}0x{addr:>08x}{RESET} {dll:>20} {export:<40}"); - } - //println!("{:#?}", &self.addr_to_import); - println!("Total code bytes: {total} (0x{total:x})"); + //self.show_addr_to_import(); + println!("(bytes-total {total} (0x{total:x})"); Ok(()) } } diff --git a/crates/vestal/src/show.rs b/crates/vestal/src/show.rs new file mode 100644 index 0000000..e36fc21 --- /dev/null +++ b/crates/vestal/src/show.rs @@ -0,0 +1,116 @@ +use crate::*; +impl Vestal { + pub fn show_addr_to_import (&self) { + for (addr, (dll, export)) in self.addr_to_import.iter() { + println!("{BOLD}0x{addr:>08x}{RESET} {dll:>20} {export:<40}"); + } + } + pub fn show_vst_entrypoint (&self, path: &PathBuf) { + //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"); + //println!("{:#?}", &self.addr_to_import); + } + pub fn show_dll (&self, path: &PathBuf) -> Usually<()> { + let dll = self.path_to_pe.get(path).expect("no such library"); + let ep_rva = dll.get_entrypoint()?; + let ep_off = dll.rva_to_offset(ep_rva)?; + println!("\n({:p} 0x{:x?} {:x?} {:x?}\n {path:?})", + dll.as_ptr(), + dll.get_image_base()?, + ep_rva, + ep_off); + Ok(()) + } + pub fn show_calls (&self, path: &PathBuf, verbose: bool) -> Usually<()> { + let mut calls = 0; + let dll = self.path_to_pe.get(path).expect("no such library"); + let buf = dll.get_buffer(); + 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; + let section_data = &buf[section_ptr..section_ptr+section_len]; + let mut decoder = iced_x86::Decoder::with_ip(64, section_data, 0x1000, 0); + while decoder.can_decode() { + let position = decoder.position(); + let instruction = decoder.decode(); + let opcodes = §ion_data[position..position+instruction.len()]; + //println!("0x{position:08x} {opcodes:32} {instruction}"); + if (instruction.flow_control() == iced_x86::FlowControl::IndirectBranch + || instruction.flow_control() == iced_x86::FlowControl::IndirectCall) + && instruction.op0_kind() == iced_x86::OpKind::Memory { + match opcodes[0] { + 0xff => match opcodes[1] { + 0x10 | 0x12 | 0x13 | + 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 | + 0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => continue, + _ => {}, + }, + 0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] { + 0xff => continue, + _ => {}, + }, + 0x48 => match opcodes[2] { + 0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => continue, + _ => {}, + }, + _ => {} + } + let offset = (position + section_ptr) as u32; + let offset_rva = dll.offset_to_rva(Offset(offset))?.0; + let call_target = match opcodes[0] { + 0xff => match opcodes[1] { + 0x15 | 0x25 => + offset_rva + opcodes.len() as u32 + u32::from_le_bytes([ + opcodes[2], + opcodes[3], + opcodes[4], + opcodes[5] + ]), + _ => 0x0 + }, + 0x48 => match opcodes[1] { + 0xff => match opcodes[2] { + 0x15 | 0x25 => + offset_rva + opcodes.len() as u32 + u32::from_le_bytes([ + opcodes[3], + opcodes[4], + opcodes[5], + opcodes[6] + ]), + _ => 0x0 + }, + _ => 0x0 + } + _ => 0x0 + }; + let unknown = (String::from("unknown"), String::from("unknown")); + let external = format!("{}::{}", + self.addr_to_import.get(&call_target).unwrap_or(&unknown).0, + self.addr_to_import.get(&call_target).unwrap_or(&unknown).1); + let dependent = path.file_name().unwrap(); + if verbose { + println!(" ({BOLD}{external:30}{RESET} O=0x{:08x} {BOLD}R=0x{:08x}{RESET} {:25} {:40} 0x{:08x}", + offset, + offset_rva, + opcodes.iter().map(|x|format!("{x:>02x}")).collect::>().join(" "), + instruction, + call_target, + ); + } + calls += 1; + } + } + println!(" (calls {calls})"); + Ok(()) + } +}