From 9deba511bd2ef57846f08b82f5fccd6e781ca9aa Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 22 Feb 2025 22:06:36 +0200 Subject: [PATCH] wip: nicer hl --- crates/vestal/src/main.rs | 49 ++++++++------- crates/vestal/src/show.rs | 125 ++++++++++++++++++++++++-------------- crates/vestal/src/util.rs | 10 ++- 3 files changed, 114 insertions(+), 70 deletions(-) diff --git a/crates/vestal/src/main.rs b/crates/vestal/src/main.rs index 14b5624..d8e7fbe 100644 --- a/crates/vestal/src/main.rs +++ b/crates/vestal/src/main.rs @@ -1,10 +1,7 @@ #![feature(slice_split_once)] -mod util; +mod util; pub(crate) use self::util::*; +mod show; pub(crate) use self::show::*; mod bang; -//mod load; -mod show; -//mod link; -pub(crate) use self::util::*; fn main () -> Usually<()> { use clap::{arg, command, value_parser, ArgAction, Command}; @@ -89,24 +86,32 @@ impl Rebuilder { Ok(None) } fn resolve_calls (&self, dll: &Dll, recurse: bool, verbose: bool) -> Usually<()> { + println!("--------------------------------"); for (addr, call) in dll.calls_by_source.iter() { + println!(); + println!("{:11}{BOLD}{}{RESET}", "", dll.name); self.resolve_call(dll, *addr, call, recurse, verbose)?; } Ok(()) } fn resolve_call ( - &self, dll: &Dll, addr: u32, call: &Arc, recurse: bool, verbose: bool, + &self, + dll: &Dll, + addr: u32, + call: &Arc, + recurse: bool, + verbose: bool, ) -> Usually<()> { let addr = (addr - dll.code_base) as usize; - //if verbose { - println!("--------------------------------"); - dll.print_call(addr, call.module.as_ref(), call.method.as_ref()); - dll.print_hex(addr, 1); - //} + //Show::call(&dll, addr, Some(call)); + //Show::call_target_addrs(Some(call)); + Show::call_site(&dll, addr, call.length, 1); + Show::call_dasm(&dll.code[addr..addr+call.length]); + Show::call_module_method(Some(call)); if let Some(method) = dll.parse_call(call) { let module_name = call.module.as_ref().unwrap(); let method_name = call.method.as_ref().unwrap(); - println!("{BOLD}0x{method:>08x}{RESET} {module_name:20} {method_name}"); + //println!("{BOLD}0x{method:>08x}{RESET} {module_name:20} {method_name}"); if let Some(path) = self.find(module_name, false)? { let name = path.file_name().expect("no file name"); let name: Arc = name.to_str().map(Arc::from).expect("non-unicode filename"); @@ -114,23 +119,25 @@ impl Rebuilder { if let Some(thunk) = dll.exports.get(method_name) { if let ThunkData::Function(rva) = thunk { let addr = (rva.0 - dll.code_base) as usize; - println!(" ⋮ "); - println!("{BOLD}0x{:>08x}{RESET} {}::{} found", rva.0, &dll.name, method_name); - dll.print_hex(addr, 1); if recurse { - let mut decoder = Decoder::with_ip( - 64, &dll.code[addr..], 0, DecoderOptions::NONE - ); + println!("\n {RESET} {BOLD}{} ({method_name}){RESET}", &dll.name); + let mut decoder = Decoder::with_ip(64, &dll.code[addr..], 0, DecoderOptions::NONE); while decoder.can_decode() { let position = decoder.position(); let instruction = decoder.decode(); - dll.print_call(addr + position, None, None); let opcodes = &dll.code[position..position+instruction.len()]; + //Show::call_site(&dll, addr, instruction.len(), 1); if Call::matches(&instruction) && !Call::skip(opcodes) { + let addr = addr + position; let start = 0x0; let offset = (position + start) as u32; let offset_rva = dll.pe.offset_to_rva(Offset(offset))?.0 as u32; - println!(" └--> {:?}", Call::target(opcodes, 0)); + let target = Call::target(opcodes, 0); + Show::call_site(&dll, addr, instruction.len(), 1); + //println!(" ╰-------> (target {:?}) (offset {offset:?}) (rva {offset_rva:?})", target); + Show::call_dasm(&dll.code[addr..addr+call.length]); + Show::call_module_method(dll.calls_by_source.get(&(addr as u32))); + //Show::call(&dll, addr + position, None); } if dll.code[addr + position] == 0xc3 { break @@ -321,7 +328,7 @@ fn collect_calls ( data: &[u8], verbose: bool, ) -> Usually { - let mut decoder = Decoder::with_ip(64, data, 0x1000, 0); + let mut decoder = Decoder::with_ip(64, data, 0, 0); let mut calls = 0; while decoder.can_decode() { if let Some(call) = collect_call(name, pe, start, data, deps, &mut decoder, false)? { diff --git a/crates/vestal/src/show.rs b/crates/vestal/src/show.rs index cfa8686..37c75ab 100644 --- a/crates/vestal/src/show.rs +++ b/crates/vestal/src/show.rs @@ -1,25 +1,57 @@ use crate::*; use std::fmt::Write; -impl Dll { - pub fn print_call (&self, addr: usize, module: Option<&Arc>, method: Option<&Arc>) { - let mut decoder = Decoder::with_ip(64, &self.code[addr..], 0x1000, DecoderOptions::NONE); +pub struct Show; + +impl Show { + pub fn num (n: usize) -> Arc { + format!("0x{n:>08x}").into() + } + pub fn call ( + dll: &Dll, + addr: usize, + call: Option<&Arc>, + ) { + let mut decoder = Decoder::with_ip(64, &dll.code[addr..], 0x1000, DecoderOptions::NONE); let instruction = decoder.decode(); let is_stack = instruction.is_stack_instruction(); let is_link = Call::matches(&instruction); let style = if is_stack || is_link { BOLD } else { DIM }; - print!("{style}0x{addr:>08x} {:20}{RESET}", &self.name); - print!(" {style}{:26}{RESET}", Self::fmt_bytes(&self.code[addr..addr+instruction.len()])); + print!("{style}{} {:20}{RESET}", Show::num(addr), &dll.name); + print!(" {style}{:26}{RESET}", fmt_bytes(&dll.code[addr..addr+instruction.len()])); println!(" {style}{instruction}{RESET}"); + } + pub fn call_target_addrs ( + call: Option<&Arc> + ) { + println!(" {}{}{}", + call.map(|call|format!(" (offset {})", Show::num(call.offset as usize))) + .unwrap_or(String::new()), + call.map(|call|format!(" (source {})", Show::num(call.source as usize))) + .unwrap_or(String::new()), + call.map(|call|format!(" (target {})", Show::num(call.target as usize))) + .unwrap_or(String::new())); + } + pub fn call_module_method ( + call: Option<&Arc> + ) { + let module = call.map(|call|call.module.as_ref()).flatten(); + let method = call.map(|call|call.method.as_ref()).flatten(); if module.is_some() || method.is_some() { - println!(" └--> {}{}{}", + println!(" {}{}{}", module.map(|x|x.as_ref()).unwrap_or(&""), if module.is_some() && method.is_some() { "::" } else { "" }, method.map(|x|x.as_ref()).unwrap_or(&"")); } } - pub fn print_hex (&self, addr: usize, context: usize) { - let base = self.code_base as usize; + + pub fn call_site ( + dll: &Dll, + addr: usize, + length: usize, + context: usize, + ) { + let base = dll.code_base as usize; let line = 16; let group = 2; let snap = |x|(x/line)*line; @@ -29,57 +61,58 @@ impl Dll { for (index, byte) in (byte_start..byte_end).enumerate() { write!(&mut output, "{DIM}"); if byte % line == 0 { + write!(&mut output, " "); if (byte >= snap(addr)) && (byte < snap(addr) + line) { - write!(&mut output, "{RESET}{BOLD}"); + write!(&mut output, "{RESET}╭"); + } else if byte >= snap(addr) + line { + write!(&mut output, "┊"); + } else { + write!(&mut output, " "); } - write!(&mut output, " {byte:08x}"); + write!(&mut output, "{byte:08x}"); } write!(&mut output, "{DIM}"); + if (byte >= addr) && (byte < addr + length) { + write!(&mut output, "{RESET}{BOLD}{INVERT}"); + } if byte % group == 0 { - write!(&mut output, " "); + if byte == addr { + write!(&mut output, "{}", "▌"); + } else if byte == addr + length { + write!(&mut output, "{RESET}{BOLD}{INVERT}▐{RESET}{DIM}"); + } else { + write!(&mut output, "{}", " "); + } } - if (byte >= addr) && (byte < addr + 8) { - write!(&mut output, "{RESET}{BOLD}"); - } - write!(&mut output, "{:02x}", self.code[byte]); + write!(&mut output, "{:02x}", dll.code[byte]); if byte % line == line - 1 { - write!(&mut output, "\n"); + write!(&mut output, " \n"); } + write!(&mut output, "{RESET}"); } - println!("{output}"); - //let cfg = HexConfig {title: false, width: 16, group: 4, chunk: 1, ..HexConfig::default()}; - //if n > 0 { - //println!(" {DIM}{}{RESET}", Self::fmt_hex_line(a, &self.code[a..b])); - //} - //println!(" {BOLD}{}{RESET}", Self::fmt_hex_line(b, &self.code[b..c])); - //if n > 0 { - //println!(" {DIM}{}{RESET}", Self::fmt_hex_line(c, &self.code[c..d])); - //} + print!("{output}"); } - //pub fn fmt_hex_block (data: &[u8], addr: usize, length: usize, context: usize) -> Arc { - //let start = addr; - //let end = addr + length; - //let line = 16; - //let snap = |x|(x/line)*line; - //let addr = snap(addr); - //let prev = addr - line * context; - //let next = addr + line * (context + 1); - //if n > 0 { - //println!(" {DIM}{}{RESET}", Self::fmt_hex_line(prev, &self.code[prev..addr])); - //} - //println!(" {BOLD}{}{RESET}", Self::fmt_hex_line(b, &self.code[addr..addr+length])); - //if n > 0 { - //println!(" {DIM}{}{RESET}", Self::fmt_hex_line(c, &self.code[addr+length..next])); - //} - //} - pub fn fmt_hex_line (addr: usize, data: &[u8]) -> Arc { - format!("{:>08x} {}", addr, Self::fmt_bytes(data)).into() - } - pub fn fmt_bytes (bytes: &[u8]) -> Arc { - bytes.iter().map(|x|format!("{x:02x}")).join(" ").into() + + pub fn call_dasm (bytes: &[u8]) { + let mut decoder = Decoder::with_ip(64, bytes, 0x0, DecoderOptions::NONE); + while decoder.can_decode() { + let position = decoder.position(); + let instruction = decoder.decode(); + let opcodes = &bytes[position..position+instruction.len()]; + println!(" ╰-------> {BOLD}{instruction}{RESET} ({DIM}{}{RESET})", fmt_bytes(opcodes)); + break + } } } +pub fn fmt_hex_line (addr: usize, data: &[u8]) -> Arc { + format!("{:>08x} {}", addr, fmt_bytes(data)).into() +} + +pub fn fmt_bytes (bytes: &[u8]) -> Arc { + bytes.iter().map(|x|format!("{x:02x}")).join(" ").into() +} + //impl Vestal { //pub fn show_addr_to_import (&self) { //for (addr, (dll, export)) in self.addr_to_import.iter() { diff --git a/crates/vestal/src/util.rs b/crates/vestal/src/util.rs index 66eb174..db72f74 100644 --- a/crates/vestal/src/util.rs +++ b/crates/vestal/src/util.rs @@ -17,12 +17,16 @@ pub(crate) use ::pretty_hex::*; pub(crate) use ::exe::{Buffer, PE, VecPE, PtrPE, types::*, headers::*}; pub(crate) use ::iced_x86::{Encoder, Decoder, DecoderOptions, Instruction, OpKind, FlowControl}; pub(crate) type Usually = Result>; -pub const RESET: &str = "\u{001b}[0m"; -pub const BOLD: &str = "\u{001b}[1m"; -pub const DIM: &str = "\u{001b}[2m"; +pub const RESET: &str = "\u{001b}[0m"; +pub const BOLD: &str = "\u{001b}[1m"; +pub const DIM: &str = "\u{001b}[2m"; +pub const ITALIC: &str = "\u{001b}[3m"; +pub const UNDERLINE: &str = "\u{001b}[4m"; +pub const INVERT: &str = "\u{001b}[7m"; pub enum Verbosity { Silent, Terse, Brief, Verbose, } + //println!(" ⋮ ");