mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 12:56:41 +01:00
wip: nicer hl
This commit is contained in:
parent
cfc1d6c0d8
commit
9deba511bd
3 changed files with 114 additions and 70 deletions
|
|
@ -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<Call>, recurse: bool, verbose: bool,
|
||||
&self,
|
||||
dll: &Dll,
|
||||
addr: u32,
|
||||
call: &Arc<Call>,
|
||||
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<str> = 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<usize> {
|
||||
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)? {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,57 @@
|
|||
use crate::*;
|
||||
use std::fmt::Write;
|
||||
|
||||
impl Dll {
|
||||
pub fn print_call (&self, addr: usize, module: Option<&Arc<str>>, method: Option<&Arc<str>>) {
|
||||
let mut decoder = Decoder::with_ip(64, &self.code[addr..], 0x1000, DecoderOptions::NONE);
|
||||
pub struct Show;
|
||||
|
||||
impl Show {
|
||||
pub fn num (n: usize) -> Arc<str> {
|
||||
format!("0x{n:>08x}").into()
|
||||
}
|
||||
pub fn call (
|
||||
dll: &Dll,
|
||||
addr: usize,
|
||||
call: Option<&Arc<Call>>,
|
||||
) {
|
||||
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<Call>>
|
||||
) {
|
||||
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<Call>>
|
||||
) {
|
||||
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<str> {
|
||||
//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<str> {
|
||||
format!("{:>08x} {}", addr, Self::fmt_bytes(data)).into()
|
||||
}
|
||||
pub fn fmt_bytes (bytes: &[u8]) -> Arc<str> {
|
||||
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<str> {
|
||||
format!("{:>08x} {}", addr, fmt_bytes(data)).into()
|
||||
}
|
||||
|
||||
pub fn fmt_bytes (bytes: &[u8]) -> Arc<str> {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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<T> = Result<T, Box<dyn std::error::Error>>;
|
||||
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!(" ⋮ ");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue