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::*;
const RESET: &str = "\u{001b}[0m";
const BOLD: &str = "\u{001b}[1m";
impl Vestal {
pub fn resolve (&self, name: &str) -> Usually<Option<PathBuf>> {
@ -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!(")")

View file

@ -29,13 +29,14 @@ fn main () -> Usually<()> {
#[derive(Default, Debug)]
struct Vestal {
search_paths: Vec<PathBuf>,
paths_visited: HashSet<Arc<PathBuf>>,
path_to_bang: HashMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_data: HashMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_pe: HashMap<Arc<PathBuf>, Arc<VecPE>>,
path_to_rpe: HashMap<Arc<PathBuf>, Arc<VecPE>>,
//path_to_exports: HashMap<Arc<PathBuf>, Vec<ImageExportDescriptor>>,
//path_to_imports: HashMap<Arc<PathBuf>, Vec<ImageImportDescriptor>>,
paths_visited: BTreeSet<Arc<PathBuf>>,
path_to_bang: BTreeMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_data: BTreeMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_pe: BTreeMap<Arc<PathBuf>, Arc<VecPE>>,
path_to_rpe: BTreeMap<Arc<PathBuf>, Arc<VecPE>>,
addr_to_import: BTreeMap<u32, (String, String)>,
//path_to_exports: BTreeMap<Arc<PathBuf>, Vec<ImageExportDescriptor>>,
//path_to_imports: BTreeMap<Arc<PathBuf>, Vec<ImageImportDescriptor>>,
}
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::<Vec<_>>().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(())
}
}

View file

@ -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<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
/// a `#!/usr/bin/env vestal` line to them.
pub fn slice_shebang (buffer: &[u8]) -> (Arc<[u8]>, Arc<[u8]>) {