vestal/crates/vestal/src/show.rs

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 = &section_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(())
//}
//}