mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 08:36:41 +01:00
270 lines
11 KiB
Rust
270 lines
11 KiB
Rust
use crate::*;
|
|
use std::fmt::Write;
|
|
|
|
pub fn fmt_bytes (bytes: &[u8]) -> Arc<str> {
|
|
bytes.iter().map(|x|format!("{x:02x}")).join(" ").into()
|
|
}
|
|
|
|
pub fn fmt_num (n: usize) -> Arc<str> {
|
|
format!("0x{n:>08x}").into()
|
|
}
|
|
|
|
pub struct Show;
|
|
|
|
pub struct Log;
|
|
|
|
impl Log {
|
|
pub fn add (show: bool, path: &impl AsRef<Path>) {
|
|
if show {
|
|
println!("(search {:?})", path.as_ref())
|
|
}
|
|
}
|
|
pub fn load (show: bool, path: &impl AsRef<Path>) {
|
|
if show {
|
|
println!("{DIM}(load {:?}){RESET}", path.as_ref());
|
|
}
|
|
}
|
|
pub fn dep (show: bool, name: &impl AsRef<str>, exports: &[(usize, Arc<str>)]) {
|
|
if show {
|
|
println!("(dep {:?} {})", name.as_ref(), exports.len());
|
|
}
|
|
}
|
|
pub fn find (show: bool, name: &impl AsRef<str>, path: &impl AsRef<Path>) {
|
|
if show {
|
|
println!("(find? {} {:?})", name.as_ref(), path.as_ref());
|
|
}
|
|
}
|
|
pub fn found (show: bool, name: &impl AsRef<str>, path: &impl AsRef<Path>) {
|
|
if show {
|
|
println!("(found {} {:?})", name.as_ref(), path.as_ref());
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Show {
|
|
pub fn link_target_addrs (link: Option<&Arc<CallSite>>) {
|
|
println!(" {}{}{}",
|
|
link.map(|link|format!(" (offset {})", fmt_num(link.offset as usize))).unwrap_or(String::new()),
|
|
link.map(|link|format!(" (source {})", fmt_num(link.source as usize))).unwrap_or(String::new()),
|
|
link.map(|link|format!(" (target {})", fmt_num(link.address as usize))).unwrap_or(String::new()));
|
|
}
|
|
pub fn link_dasm (bytes: &[u8], rip: usize) -> Arc<str> {
|
|
let mut decoder = Decoder::with_ip(64, bytes, 0x1000 + rip as u64, DecoderOptions::NONE);
|
|
while decoder.can_decode() {
|
|
let position = decoder.position();
|
|
let instruction = decoder.decode();
|
|
let opcodes = &bytes[position..position+instruction.len()];
|
|
return format!("{BOLD}{instruction}{RESET} ({DIM}{}{RESET})", fmt_bytes(opcodes)).into()
|
|
}
|
|
Default::default()
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for Module {
|
|
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
|
|
write!(f, "(dll {BOLD}{UNDERLINE}{:15}{RESET} [0x{:>08x}] {} (img 0x{:>08x} -> mem 0x{:>08x}))",
|
|
&self.name,
|
|
self.code_size,
|
|
format!("({:>5})", self.exports.read().unwrap().len()),
|
|
self.code_start,
|
|
self.code_base)
|
|
}
|
|
}
|
|
|
|
impl Module {
|
|
pub fn show_dependencies (&self) {
|
|
for (name, module) in self.dependencies.iter() {
|
|
print!(" ({module:?}");
|
|
for (method, addr) in module.exports.read().unwrap().iter() {
|
|
//print!("\n (0x{addr:08x} {method})")
|
|
}
|
|
println!(")");
|
|
}
|
|
}
|
|
pub fn show_instruction (&self, addr: usize) {
|
|
let mut decoder = Decoder::with_ip(64, &self.code[addr..], 0x1000, DecoderOptions::NONE);
|
|
let instruction = decoder.decode();
|
|
let is_stack = instruction.is_stack_instruction();
|
|
let is_link = CallSite::matches(&instruction);
|
|
let style = if is_stack || is_link { BOLD } else { DIM };
|
|
print!("{style}{} {:20}{RESET}", fmt_num(addr), &self.name);
|
|
print!(" {style}{:26}{RESET}", fmt_bytes(&self.code[addr..addr+instruction.len()]));
|
|
println!(" {style}{instruction}{RESET}");
|
|
}
|
|
pub fn show_call_site (&self, addr: usize, length: usize, context: usize) {
|
|
let base = self.code_base as usize;
|
|
let line = 16;
|
|
let group = 2;
|
|
let snap = |x|(x/line)*line;
|
|
let byte_start = snap(addr).saturating_sub(context*line);
|
|
let byte_end = snap(addr) + (context + 1) * line;
|
|
let mut output = String::new();
|
|
for (index, byte) in (byte_start..byte_end).enumerate() {
|
|
write!(&mut output, "{DIM}");
|
|
if byte % line == 0 {
|
|
if (byte >= snap(addr)) && (byte < snap(addr) + line) {
|
|
write!(&mut output, "{RESET}╭─");
|
|
} else if byte >= snap(addr) + line {
|
|
write!(&mut output, "┊ ");
|
|
} else {
|
|
write!(&mut output, " ");
|
|
}
|
|
write!(&mut output, "{:08x}", byte + base);
|
|
}
|
|
write!(&mut output, "{DIM}");
|
|
if (byte >= addr) && (byte < addr + length) {
|
|
write!(&mut output, "{RESET}{BOLD}{INVERT}");
|
|
}
|
|
if byte % group == 0 {
|
|
if byte == addr {
|
|
write!(&mut output, "{}", "▌");
|
|
} else if byte == addr + length {
|
|
write!(&mut output, "{RESET}{BOLD}{INVERT}▐{RESET}{DIM}");
|
|
} else {
|
|
write!(&mut output, "{}", " ");
|
|
}
|
|
}
|
|
write!(&mut output, "{:02x}", self.code[byte]);
|
|
write!(&mut output, "{RESET}");
|
|
if byte % line == line - 1 {
|
|
if snap(byte) == snap(addr) {
|
|
let dasm = Show::link_dasm(&self.code[addr..], addr);
|
|
write!(&mut output, " -> {dasm}");
|
|
}
|
|
write!(&mut output, " \n");
|
|
}
|
|
}
|
|
print!("{output}");
|
|
}
|
|
}
|
|
|
|
impl CallSite {
|
|
pub fn show (&self) {
|
|
let caller = self.caller.name.as_ref();
|
|
let module = self.target.name.as_ref();
|
|
let method = self.method.as_ref();
|
|
let style = GREEN;
|
|
println!("╰--------> {caller} -> {style}{module}::{method}{RESET}");
|
|
//module.map(|x|x.as_ref()).unwrap_or(&""),
|
|
//method.map(|x|x.as_ref()).unwrap_or(&""));
|
|
//} else {
|
|
//println!("╰--------> {caller} -> {RED}(unresolved){RESET} {self:?}");
|
|
//}
|
|
}
|
|
}
|
|
|
|
//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_links (&self, path: &PathBuf, verbose: bool) -> Usually<()> {
|
|
//let mut links = 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::IndirectCallSite)
|
|
//&& 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 link_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(&link_target).unwrap_or(&unknown).0,
|
|
//self.addr_to_import.get(&link_target).unwrap_or(&unknown).1);
|
|
//let dependent = path.file_name().unwrap();
|
|
//if verbose {
|
|
//println!(" ({BOLD}{external}{RESET}\n Offset(0x{:08x}) RVA(R=0x{:08x})\n {:25} {:40} 0x{:08x}",
|
|
//offset,
|
|
//offset_rva,
|
|
//opcodes.iter().map(|x|format!("{x:>02x}")).collect::<Vec<_>>().join(" "),
|
|
//instruction,
|
|
//link_target,
|
|
//);
|
|
//}
|
|
//links += 1;
|
|
//}
|
|
//}
|
|
//println!(" (links {links})");
|
|
//Ok(())
|
|
//}
|
|
//}
|