From d61606fe48d47e8a340c59a709943029b85c3425 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 20 Feb 2025 23:46:06 +0200 Subject: [PATCH] link call/jmp to library targets --- crates/vestal/src/load.rs | 26 ++++++++------ crates/vestal/src/main.rs | 71 +++++++++++++++++++++++++++++---------- crates/vestal/src/util.rs | 4 ++- 3 files changed, 73 insertions(+), 28 deletions(-) diff --git a/crates/vestal/src/load.rs b/crates/vestal/src/load.rs index 9a32271..2f24c07 100644 --- a/crates/vestal/src/load.rs +++ b/crates/vestal/src/load.rs @@ -1,6 +1,4 @@ use crate::*; -const RESET: &str = "\u{001b}[0m"; -const BOLD: &str = "\u{001b}[1m"; impl Vestal { pub fn resolve (&self, name: &str) -> Usually> { @@ -27,14 +25,14 @@ impl Vestal { Ok(()) } pub fn load_imports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> { - let mut import_map = HashMap::new(); + let mut import_map = BTreeMap::new(); let directory = ImportDirectory::parse(dll)?; for descriptor in directory.descriptors { let dep = descriptor.get_name(dll)?.as_str()?; let iat = descriptor.get_first_thunk(dll)?; let ilt = descriptor.get_original_first_thunk(dll)?; let lookups = descriptor.get_lookup_thunks(dll)?; - let resolved = self.resolve(&dep)?.expect("no path for {name}"); + 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:?}", &descriptor.name.0, &descriptor.first_thunk.0, @@ -56,15 +54,23 @@ impl Vestal { descriptor.get_imports(dll)? ).enumerate() { let call_via = descriptor.first_thunk.0 + index as u32 * 8; - match import { - ImportData::Ordinal(x) => + 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), - ImportData::ImportByName(name) => + 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), - } + call_via, thunk, orig, lookup, name); + format!("{name}") + }, + }; imports.push((thunk, orig, import)); + if self.addr_to_import.contains_key(&call_via) { + panic!("addr space overlap"); + } + self.addr_to_import.insert(call_via, (dep.to_string(), name)); } import_map.insert(dep, (resolved, imports)); println!(")") diff --git a/crates/vestal/src/main.rs b/crates/vestal/src/main.rs index eec820e..4ceceb6 100644 --- a/crates/vestal/src/main.rs +++ b/crates/vestal/src/main.rs @@ -28,14 +28,15 @@ fn main () -> Usually<()> { } #[derive(Default, Debug)] struct Vestal { - search_paths: Vec, - paths_visited: HashSet>, - path_to_bang: HashMap, Arc<[u8]>>, - path_to_data: HashMap, Arc<[u8]>>, - path_to_pe: HashMap, Arc>, - path_to_rpe: HashMap, Arc>, - //path_to_exports: HashMap, Vec>, - //path_to_imports: HashMap, Vec>, + search_paths: Vec, + paths_visited: BTreeSet>, + path_to_bang: BTreeMap, Arc<[u8]>>, + path_to_data: BTreeMap, Arc<[u8]>>, + path_to_pe: BTreeMap, Arc>, + path_to_rpe: BTreeMap, Arc>, + addr_to_import: BTreeMap, + //path_to_exports: BTreeMap, Vec>, + //path_to_imports: BTreeMap, Vec>, } impl Vestal { fn enter (&mut self, path: &PathBuf) -> Usually<()> { @@ -43,9 +44,9 @@ impl Vestal { 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!(); + //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)?; @@ -54,7 +55,7 @@ impl Vestal { dll.get_image_base()?, ep_rva, ep_off); - if dll_path.as_ref() == path { + if true || dll_path.as_ref() == path { let buf = dll.get_buffer(); let section = dll.get_section_by_name(".text")?; let section_ptr = section.pointer_to_raw_data.0 as usize; @@ -71,7 +72,8 @@ impl Vestal { && instruction.op0_kind() == iced_x86::OpKind::Memory { match opcodes[0] { 0xff => match opcodes[1] { - 0x10 | 0x12 | 0x13 | 0x50 | 0x52 | 0x53 | 0x55 | 0x56 | 0x57 | + 0x10 | 0x12 | 0x13 | + 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 | 0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => continue, _ => {}, }, @@ -86,11 +88,41 @@ impl Vestal { _ => {} } let offset = (position + section_ptr) as u32; - println!("0x{:08x} (0x{:08x}) {:32} {}", - position + section_ptr, - dll.offset_to_rva(Offset(offset))?.0, + 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); + instruction, + call_target, + self.addr_to_import.get(&call_target)); //println!("0x{:08x} {}", decoder.position(), instruction); //return Ok(()) } @@ -109,6 +141,11 @@ impl Vestal { //} //} //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); Ok(()) } } diff --git a/crates/vestal/src/util.rs b/crates/vestal/src/util.rs index 276d57f..c217023 100644 --- a/crates/vestal/src/util.rs +++ b/crates/vestal/src/util.rs @@ -2,7 +2,7 @@ pub(crate) use std::pin::Pin; pub(crate) use std::sync::Arc; pub(crate) use std::error::Error; pub(crate) use std::path::{Path, PathBuf}; -pub(crate) use std::collections::{HashMap, HashSet}; +pub(crate) use std::collections::{BTreeMap, BTreeSet}; pub(crate) use std::fs::{read, canonicalize}; pub(crate) use itertools::izip; //pub(crate) use ::lancelot::loader::pe::{PE, reloc::apply_relocations}; @@ -14,6 +14,8 @@ pub(crate) use ::object::write::elf::Writer as ElfWriter; pub(crate) use ::pretty_hex::*; pub(crate) use ::exe::{Buffer, PE, VecPE, PtrPE, types::*, headers::*}; pub(crate) type Usually = Result>; +pub const RESET: &str = "\u{001b}[0m"; +pub const BOLD: &str = "\u{001b}[1m"; /// You can manually patch DLLs by prepending /// a `#!/usr/bin/env vestal` line to them. pub fn slice_shebang (buffer: &[u8]) -> (Arc<[u8]>, Arc<[u8]>) {