start tracing call instructions

This commit is contained in:
🪞👃🪞 2025-02-20 01:33:44 +02:00
parent 33546ccfb4
commit e5baca6c31
4 changed files with 89 additions and 106 deletions

10
Cargo.lock generated
View file

@ -313,6 +313,15 @@ dependencies = [
"cc", "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]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.7.1" version = "2.7.1"
@ -675,6 +684,7 @@ dependencies = [
"clap", "clap",
"exe", "exe",
"hexy", "hexy",
"iced-x86",
"object", "object",
"pretty-hex", "pretty-hex",
"syscalls", "syscalls",

View file

@ -10,6 +10,7 @@ object = { version = "0.36.7", features = [ "read_core", "write_core", "elf", "p
hexy = "0.1.4" hexy = "0.1.4"
pretty-hex = "0.4.1" pretty-hex = "0.4.1"
exe = "0.5.6" exe = "0.5.6"
iced-x86 = "1.21.0"
#elf = "0.7.4" #elf = "0.7.4"
#goblin = "0.9.3" #goblin = "0.9.3"
#lancelot = "0.9.7" #lancelot = "0.9.7"

View file

@ -38,32 +38,69 @@ struct Vestal {
//path_to_exports: HashMap<Arc<PathBuf>, Vec<ImageExportDescriptor>>, //path_to_exports: HashMap<Arc<PathBuf>, Vec<ImageExportDescriptor>>,
//path_to_imports: HashMap<Arc<PathBuf>, Vec<ImageImportDescriptor>>, //path_to_imports: HashMap<Arc<PathBuf>, Vec<ImageImportDescriptor>>,
} }
#[derive(Debug)]
struct Export {
id: u32,
name: Option<Arc<[u8]>>,
target: Target,
}
impl Export {
fn name_string (&self) -> Option<String> {
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 { 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 = &section_data[position..position+instruction.len()].iter().map(|x|format!("{x:>02x}")).collect::<Vec<_>>().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<Option<PathBuf>> { fn resolve (&self, name: &str) -> Usually<Option<PathBuf>> {
for base in self.search_paths.iter() { for base in self.search_paths.iter() {
let mut path = base.clone(); let mut path = base.clone();
@ -77,28 +114,36 @@ impl Vestal {
fn load (&mut self, path: &PathBuf) -> Usually<()> { fn load (&mut self, path: &PathBuf) -> Usually<()> {
if !self.paths_visited.contains(path) { if !self.paths_visited.contains(path) {
let path = Arc::new(path.clone()); let path = Arc::new(path.clone());
println!("(load {path:?})"); println!("\n(load {path:?})");
self.paths_visited.insert(path.clone()); self.paths_visited.insert(path.clone());
let data = self.load_bang_data(&path)?; let data = self.load_bang_data(&path)?;
let dll = self.load_pe(&path, &data)?; let dll = self.load_pe(&path, &data)?;
let imports = self.load_imports(&path, &dll); let imports = self.load_imports(&path, &dll);
let exports = self.load_exports(&path, &dll); let exports = self.load_exports(&path, &dll);
println!("(entrypoint {:?})", dll.get_entrypoint()?);
} }
Ok(()) Ok(())
} }
fn load_imports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> { fn load_imports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> {
let mut import_map = HashMap::new();
let directory = ImportDirectory::parse(dll)?; let directory = ImportDirectory::parse(dll)?;
for descriptor in directory.descriptors { 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)? { for import in descriptor.get_imports(dll)? {
match import { match import {
ImportData::Ordinal(x) => print!("\n (ordi 0x{x:>04x})"), ImportData::Ordinal(x) => print!("\n (import-ordinal 0x{x:>04x})"),
ImportData::ImportByName(n) => print!("\n (name {n})"), ImportData::ImportByName(n) => print!("\n (import-by-name {n:?})"),
} }
imports.push(import);
} }
import_map.insert(dep, (resolved, imports));
println!(")") println!(")")
} }
for (name, (path, imports)) in import_map.iter() {
self.load(path)?;
}
Ok(()) Ok(())
} }
fn load_exports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> { 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()); let (bang, data) = slice_shebang(read(path.as_path())?.as_slice());
self.path_to_bang.insert(path.clone(), bang.clone()); self.path_to_bang.insert(path.clone(), bang.clone());
if bang.len() > 0 { 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()); 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) Ok(data)
} }
fn load_pe (&mut self, path: &Arc<PathBuf>, data: &Arc<[u8]>) -> Usually<Arc<VecPE>> { fn load_pe (&mut self, path: &Arc<PathBuf>, data: &Arc<[u8]>) -> Usually<Arc<VecPE>> {
@ -119,77 +164,4 @@ impl Vestal {
self.path_to_pe.insert(path.clone(), pe.clone()); self.path_to_pe.insert(path.clone(), pe.clone());
Ok(pe) 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(())
//}

View file

@ -11,7 +11,7 @@ pub(crate) use ::object::endian::LittleEndian;
//pub(crate) use ::object::read::pe::{PeFile, ExportTarget}; //pub(crate) use ::object::read::pe::{PeFile, ExportTarget};
pub(crate) use ::object::write::elf::Writer as ElfWriter; pub(crate) use ::object::write::elf::Writer as ElfWriter;
pub(crate) use ::pretty_hex::*; 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<T> = Result<T, Box<dyn std::error::Error>>; pub(crate) type Usually<T> = Result<T, Box<dyn std::error::Error>>;
/// 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.