link call/jmp to library targets

This commit is contained in:
🪞👃🪞 2025-02-20 23:46:06 +02:00
parent 6796e3e50f
commit d61606fe48
3 changed files with 73 additions and 28 deletions

View file

@ -1,6 +1,4 @@
use crate::*; use crate::*;
const RESET: &str = "\u{001b}[0m";
const BOLD: &str = "\u{001b}[1m";
impl Vestal { impl Vestal {
pub fn resolve (&self, name: &str) -> Usually<Option<PathBuf>> { pub fn resolve (&self, name: &str) -> Usually<Option<PathBuf>> {
@ -27,14 +25,14 @@ impl Vestal {
Ok(()) Ok(())
} }
pub fn load_imports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> { 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)?; let directory = ImportDirectory::parse(dll)?;
for descriptor in directory.descriptors { for descriptor in directory.descriptors {
let dep = descriptor.get_name(dll)?.as_str()?; let dep = descriptor.get_name(dll)?.as_str()?;
let iat = descriptor.get_first_thunk(dll)?; let iat = descriptor.get_first_thunk(dll)?;
let ilt = descriptor.get_original_first_thunk(dll)?; let ilt = descriptor.get_original_first_thunk(dll)?;
let lookups = descriptor.get_lookup_thunks(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:?}", print!("\n (module {BOLD}{dep:?}{RESET} N=0x{:>08x} IAT=0x{:>08x} ILT=0x{:>08x}\n {resolved:?}",
&descriptor.name.0, &descriptor.name.0,
&descriptor.first_thunk.0, &descriptor.first_thunk.0,
@ -56,15 +54,23 @@ impl Vestal {
descriptor.get_imports(dll)? descriptor.get_imports(dll)?
).enumerate() { ).enumerate() {
let call_via = descriptor.first_thunk.0 + index as u32 * 8; let call_via = descriptor.first_thunk.0 + index as u32 * 8;
match import { let name = match import {
ImportData::Ordinal(x) => ImportData::Ordinal(x) => {
print!("\n (import-ordinal {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} 0x{:>04x})", print!("\n (import-ordinal {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} 0x{:>04x})",
call_via, thunk, orig, lookup, x), call_via, thunk, orig, lookup, x);
ImportData::ImportByName(name) => format!("___VESTAL___ORD___{x}___")
},
ImportData::ImportByName(name) => {
print!("\n (import-by-name {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} {:?})", 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)); 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)); import_map.insert(dep, (resolved, imports));
println!(")") println!(")")

View file

@ -29,13 +29,14 @@ fn main () -> Usually<()> {
#[derive(Default, Debug)] #[derive(Default, Debug)]
struct Vestal { struct Vestal {
search_paths: Vec<PathBuf>, search_paths: Vec<PathBuf>,
paths_visited: HashSet<Arc<PathBuf>>, paths_visited: BTreeSet<Arc<PathBuf>>,
path_to_bang: HashMap<Arc<PathBuf>, Arc<[u8]>>, path_to_bang: BTreeMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_data: HashMap<Arc<PathBuf>, Arc<[u8]>>, path_to_data: BTreeMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_pe: HashMap<Arc<PathBuf>, Arc<VecPE>>, path_to_pe: BTreeMap<Arc<PathBuf>, Arc<VecPE>>,
path_to_rpe: HashMap<Arc<PathBuf>, Arc<VecPE>>, path_to_rpe: BTreeMap<Arc<PathBuf>, Arc<VecPE>>,
//path_to_exports: HashMap<Arc<PathBuf>, Vec<ImageExportDescriptor>>, addr_to_import: BTreeMap<u32, (String, String)>,
//path_to_imports: HashMap<Arc<PathBuf>, Vec<ImageImportDescriptor>>, //path_to_exports: BTreeMap<Arc<PathBuf>, Vec<ImageExportDescriptor>>,
//path_to_imports: BTreeMap<Arc<PathBuf>, Vec<ImageImportDescriptor>>,
} }
impl Vestal { impl Vestal {
fn enter (&mut self, path: &PathBuf) -> Usually<()> { fn enter (&mut self, path: &PathBuf) -> Usually<()> {
@ -43,9 +44,9 @@ impl Vestal {
let data = self.path_to_data.get(path); let data = self.path_to_data.get(path);
let len = data.as_ref().unwrap().len(); let len = data.as_ref().unwrap().len();
let data = data.as_ref().unwrap(); let data = data.as_ref().unwrap();
println!(); //println!();
println!("{:?}", data[0..256].hex_dump()); //println!("{:?}", data[0..256].hex_dump());
println!(); //println!();
for (dll_path, dll) in self.path_to_pe.iter() { for (dll_path, dll) in self.path_to_pe.iter() {
let ep_rva = dll.get_entrypoint()?; let ep_rva = dll.get_entrypoint()?;
let ep_off = dll.rva_to_offset(ep_rva)?; let ep_off = dll.rva_to_offset(ep_rva)?;
@ -54,7 +55,7 @@ impl Vestal {
dll.get_image_base()?, dll.get_image_base()?,
ep_rva, ep_rva,
ep_off); ep_off);
if dll_path.as_ref() == path { if true || dll_path.as_ref() == path {
let buf = dll.get_buffer(); let buf = dll.get_buffer();
let section = dll.get_section_by_name(".text")?; let section = dll.get_section_by_name(".text")?;
let section_ptr = section.pointer_to_raw_data.0 as usize; let section_ptr = section.pointer_to_raw_data.0 as usize;
@ -71,7 +72,8 @@ impl Vestal {
&& instruction.op0_kind() == iced_x86::OpKind::Memory { && instruction.op0_kind() == iced_x86::OpKind::Memory {
match opcodes[0] { match opcodes[0] {
0xff => match opcodes[1] { 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, 0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => continue,
_ => {}, _ => {},
}, },
@ -86,11 +88,41 @@ impl Vestal {
_ => {} _ => {}
} }
let offset = (position + section_ptr) as u32; let offset = (position + section_ptr) as u32;
println!("0x{:08x} (0x{:08x}) {:32} {}", let offset_rva = dll.offset_to_rva(Offset(offset))?.0;
position + section_ptr, let call_target = match opcodes[0] {
dll.offset_to_rva(Offset(offset))?.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::<Vec<_>>().join(" "), opcodes.iter().map(|x|format!("{x:>02x}")).collect::<Vec<_>>().join(" "),
instruction); instruction,
call_target,
self.addr_to_import.get(&call_target));
//println!("0x{:08x} {}", decoder.position(), instruction); //println!("0x{:08x} {}", decoder.position(), instruction);
//return Ok(()) //return Ok(())
} }
@ -109,6 +141,11 @@ impl Vestal {
//} //}
//} //}
//panic!("no main"); //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(()) Ok(())
} }
} }

View file

@ -2,7 +2,7 @@ pub(crate) use std::pin::Pin;
pub(crate) use std::sync::Arc; pub(crate) use std::sync::Arc;
pub(crate) use std::error::Error; pub(crate) use std::error::Error;
pub(crate) use std::path::{Path, PathBuf}; 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 std::fs::{read, canonicalize};
pub(crate) use itertools::izip; pub(crate) use itertools::izip;
//pub(crate) use ::lancelot::loader::pe::{PE, reloc::apply_relocations}; //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 ::pretty_hex::*;
pub(crate) use ::exe::{Buffer, PE, VecPE, PtrPE, types::*, headers::*}; pub(crate) use ::exe::{Buffer, PE, VecPE, PtrPE, types::*, headers::*};
pub(crate) type Usually<T> = Result<T, Box<dyn std::error::Error>>; pub(crate) type Usually<T> = Result<T, Box<dyn std::error::Error>>;
pub const RESET: &str = "\u{001b}[0m";
pub const BOLD: &str = "\u{001b}[1m";
/// You can manually patch DLLs by prepending /// You can manually patch DLLs by prepending
/// a `#!/usr/bin/env vestal` line to them. /// a `#!/usr/bin/env vestal` line to them.
pub fn slice_shebang (buffer: &[u8]) -> (Arc<[u8]>, Arc<[u8]>) { pub fn slice_shebang (buffer: &[u8]) -> (Arc<[u8]>, Arc<[u8]>) {