mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 08:36:41 +01:00
get call addrs
This commit is contained in:
parent
513166ddd5
commit
6796e3e50f
3 changed files with 111 additions and 92 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
target
|
target
|
||||||
*.dll
|
*.dll
|
||||||
|
*.exe
|
||||||
|
|
|
||||||
103
crates/vestal/src/load.rs
Normal file
103
crates/vestal/src/load.rs
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
use crate::*;
|
||||||
|
const RESET: &str = "\u{001b}[0m";
|
||||||
|
const BOLD: &str = "\u{001b}[1m";
|
||||||
|
|
||||||
|
impl Vestal {
|
||||||
|
pub fn resolve (&self, name: &str) -> Usually<Option<PathBuf>> {
|
||||||
|
for base in self.search_paths.iter() {
|
||||||
|
let mut path = base.clone();
|
||||||
|
path.push(name.to_lowercase());
|
||||||
|
if std::fs::exists(&path)? {
|
||||||
|
return Ok(Some(canonicalize(&path)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
pub fn load (&mut self, path: &PathBuf) -> Usually<()> {
|
||||||
|
if !self.paths_visited.contains(path) {
|
||||||
|
let path = Arc::new(path.clone());
|
||||||
|
println!("\n(load {path:?})");
|
||||||
|
self.paths_visited.insert(path.clone());
|
||||||
|
let data = self.load_bang_data(&path)?;
|
||||||
|
let dll = self.load_pe(&path, &data)?;
|
||||||
|
let rdll = self.load_rpe(&path, &dll, 0)?;
|
||||||
|
let imports = self.load_imports(&path, &dll);
|
||||||
|
let exports = self.load_exports(&path, &dll);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn load_imports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> {
|
||||||
|
let mut import_map = HashMap::new();
|
||||||
|
let directory = ImportDirectory::parse(dll)?;
|
||||||
|
for descriptor in directory.descriptors {
|
||||||
|
let dep = descriptor.get_name(dll)?.as_str()?;
|
||||||
|
let iat = descriptor.get_first_thunk(dll)?;
|
||||||
|
let ilt = descriptor.get_original_first_thunk(dll)?;
|
||||||
|
let lookups = descriptor.get_lookup_thunks(dll)?;
|
||||||
|
let resolved = self.resolve(&dep)?.expect("no path for {name}");
|
||||||
|
print!("\n (module {BOLD}{dep:?}{RESET} N=0x{:>08x} IAT=0x{:>08x} ILT=0x{:>08x}\n {resolved:?}",
|
||||||
|
&descriptor.name.0,
|
||||||
|
&descriptor.first_thunk.0,
|
||||||
|
&descriptor.original_first_thunk.0);
|
||||||
|
let mut imports = Vec::new();
|
||||||
|
for (index, (thunk, orig, lookup, import)) in izip!(
|
||||||
|
iat.iter().map(|thunk|format!("0x{:08x}", match thunk {
|
||||||
|
Thunk::Thunk32(t) => panic!("32 bit thunk"),
|
||||||
|
Thunk::Thunk64(t) => t.0
|
||||||
|
})),
|
||||||
|
ilt.iter().map(|thunk|format!("0x{:08x}", match thunk {
|
||||||
|
Thunk::Thunk32(t) => panic!("32 bit original thunk"),
|
||||||
|
Thunk::Thunk64(t) => t.0
|
||||||
|
})),
|
||||||
|
lookups.iter().map(|thunk|format!("0x{:08x}", match thunk {
|
||||||
|
Thunk::Thunk32(t) => panic!("32 bit original thunk"),
|
||||||
|
Thunk::Thunk64(t) => t.0
|
||||||
|
})),
|
||||||
|
descriptor.get_imports(dll)?
|
||||||
|
).enumerate() {
|
||||||
|
let call_via = descriptor.first_thunk.0 + index as u32 * 8;
|
||||||
|
match import {
|
||||||
|
ImportData::Ordinal(x) =>
|
||||||
|
print!("\n (import-ordinal {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} 0x{:>04x})",
|
||||||
|
call_via, thunk, orig, lookup, x),
|
||||||
|
ImportData::ImportByName(name) =>
|
||||||
|
print!("\n (import-by-name {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} {:?})",
|
||||||
|
call_via, thunk, orig, lookup, name),
|
||||||
|
}
|
||||||
|
imports.push((thunk, orig, import));
|
||||||
|
}
|
||||||
|
import_map.insert(dep, (resolved, imports));
|
||||||
|
println!(")")
|
||||||
|
}
|
||||||
|
for (name, (path, imports)) in import_map.iter() {
|
||||||
|
self.load(path)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn load_exports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn load_bang_data (&mut self, path: &Arc<PathBuf>) -> Usually<Arc<[u8]>> {
|
||||||
|
let (bang, data) = slice_shebang(read(path.as_path())?.as_slice());
|
||||||
|
self.path_to_bang.insert(path.clone(), bang.clone());
|
||||||
|
if bang.len() > 0 {
|
||||||
|
println!(" (bang {path:?} {:x})", bang.len())
|
||||||
|
}
|
||||||
|
self.path_to_data.insert(path.clone(), data.clone());
|
||||||
|
println!(" (buffer {:p} 0x{:08x} {path:?})", data.as_ptr(), data.len());
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
pub fn load_pe (&mut self, path: &Arc<PathBuf>, data: &Arc<[u8]>) -> Usually<Arc<VecPE>> {
|
||||||
|
let pe = Arc::new(VecPE::from_disk_data(data));
|
||||||
|
self.path_to_pe.insert(path.clone(), pe.clone());
|
||||||
|
Ok(pe)
|
||||||
|
}
|
||||||
|
pub fn load_rpe (&mut self, path: &Arc<PathBuf>, data: &VecPE, base: u64) -> Usually<Arc<VecPE>> {
|
||||||
|
let rdir = RelocationDirectory::parse(data)?;
|
||||||
|
let mut rpe = data.clone();
|
||||||
|
rdir.relocate(&mut rpe, base)?;
|
||||||
|
let rpe = Arc::new(rpe);
|
||||||
|
self.path_to_rpe.insert(path.clone(), rpe.clone());
|
||||||
|
Ok(rpe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
#![feature(slice_split_once)]
|
#![feature(slice_split_once)]
|
||||||
mod util;
|
mod util;
|
||||||
|
mod load;
|
||||||
pub(crate) use self::util::*;
|
pub(crate) use self::util::*;
|
||||||
//mod dll;
|
|
||||||
//mod exec;
|
|
||||||
use clap::{arg, command, value_parser, ArgAction, Command};
|
use clap::{arg, command, value_parser, ArgAction, Command};
|
||||||
fn main () -> Usually<()> {
|
fn main () -> Usually<()> {
|
||||||
let matches = command!()
|
let matches = command!()
|
||||||
|
|
@ -18,8 +17,7 @@ fn main () -> Usually<()> {
|
||||||
println!("(search {path:?})")
|
println!("(search {path:?})")
|
||||||
}
|
}
|
||||||
if let Some(path) = vestal.resolve(path.to_str().expect("path must be unicode"))? {
|
if let Some(path) = vestal.resolve(path.to_str().expect("path must be unicode"))? {
|
||||||
vestal.load(&path)?;
|
vestal.enter(&path)?;
|
||||||
vestal.run_main(&path)?;
|
|
||||||
} else {
|
} else {
|
||||||
panic!("Could not find: {path:?}")
|
panic!("Could not find: {path:?}")
|
||||||
}
|
}
|
||||||
|
|
@ -35,11 +33,13 @@ struct Vestal {
|
||||||
path_to_bang: HashMap<Arc<PathBuf>, Arc<[u8]>>,
|
path_to_bang: HashMap<Arc<PathBuf>, Arc<[u8]>>,
|
||||||
path_to_data: HashMap<Arc<PathBuf>, Arc<[u8]>>,
|
path_to_data: HashMap<Arc<PathBuf>, Arc<[u8]>>,
|
||||||
path_to_pe: HashMap<Arc<PathBuf>, Arc<VecPE>>,
|
path_to_pe: HashMap<Arc<PathBuf>, Arc<VecPE>>,
|
||||||
|
path_to_rpe: HashMap<Arc<PathBuf>, Arc<VecPE>>,
|
||||||
//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>>,
|
||||||
}
|
}
|
||||||
impl Vestal {
|
impl Vestal {
|
||||||
fn run_main (&self, path: &PathBuf) -> Usually<()> {
|
fn enter (&mut self, path: &PathBuf) -> Usually<()> {
|
||||||
|
self.load(&path)?;
|
||||||
let data = self.path_to_data.get(path);
|
let data = self.path_to_data.get(path);
|
||||||
let len = data.as_ref().unwrap().len();
|
let len = data.as_ref().unwrap().len();
|
||||||
let data = data.as_ref().unwrap();
|
let data = data.as_ref().unwrap();
|
||||||
|
|
@ -62,9 +62,9 @@ impl Vestal {
|
||||||
let section_data = &buf[section_ptr..section_ptr+section_len];
|
let section_data = &buf[section_ptr..section_ptr+section_len];
|
||||||
let mut decoder = iced_x86::Decoder::with_ip(64, section_data, 0x1000, 0);
|
let mut decoder = iced_x86::Decoder::with_ip(64, section_data, 0x1000, 0);
|
||||||
while decoder.can_decode() {
|
while decoder.can_decode() {
|
||||||
let position = decoder.position();
|
let position = decoder.position();
|
||||||
let instruction = decoder.decode();
|
let instruction = decoder.decode();
|
||||||
let opcodes = §ion_data[position..position+instruction.len()];
|
let opcodes = §ion_data[position..position+instruction.len()];
|
||||||
//println!("0x{position:08x} {opcodes:32} {instruction}");
|
//println!("0x{position:08x} {opcodes:32} {instruction}");
|
||||||
if (instruction.flow_control() == iced_x86::FlowControl::IndirectBranch
|
if (instruction.flow_control() == iced_x86::FlowControl::IndirectBranch
|
||||||
|| instruction.flow_control() == iced_x86::FlowControl::IndirectCall)
|
|| instruction.flow_control() == iced_x86::FlowControl::IndirectCall)
|
||||||
|
|
@ -91,7 +91,6 @@ impl Vestal {
|
||||||
dll.offset_to_rva(Offset(offset))?.0,
|
dll.offset_to_rva(Offset(offset))?.0,
|
||||||
opcodes.iter().map(|x|format!("{x:>02x}")).collect::<Vec<_>>().join(" "),
|
opcodes.iter().map(|x|format!("{x:>02x}")).collect::<Vec<_>>().join(" "),
|
||||||
instruction);
|
instruction);
|
||||||
break
|
|
||||||
//println!("0x{:08x} {}", decoder.position(), instruction);
|
//println!("0x{:08x} {}", decoder.position(), instruction);
|
||||||
//return Ok(())
|
//return Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -112,88 +111,4 @@ impl Vestal {
|
||||||
//panic!("no main");
|
//panic!("no main");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn resolve (&self, name: &str) -> Usually<Option<PathBuf>> {
|
|
||||||
for base in self.search_paths.iter() {
|
|
||||||
let mut path = base.clone();
|
|
||||||
path.push(name.to_lowercase());
|
|
||||||
if std::fs::exists(&path)? {
|
|
||||||
return Ok(Some(canonicalize(&path)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
fn load (&mut self, path: &PathBuf) -> Usually<()> {
|
|
||||||
if !self.paths_visited.contains(path) {
|
|
||||||
let path = Arc::new(path.clone());
|
|
||||||
println!("\n(load {path:?})");
|
|
||||||
self.paths_visited.insert(path.clone());
|
|
||||||
let data = self.load_bang_data(&path)?;
|
|
||||||
let dll = self.load_pe(&path, &data)?;
|
|
||||||
let imports = self.load_imports(&path, &dll);
|
|
||||||
let exports = self.load_exports(&path, &dll);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn load_imports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> {
|
|
||||||
let mut import_map = HashMap::new();
|
|
||||||
let directory = ImportDirectory::parse(dll)?;
|
|
||||||
for descriptor in directory.descriptors {
|
|
||||||
let dep = descriptor.get_name(dll)?.as_str()?;
|
|
||||||
let resolved = self.resolve(&dep)?.expect("no path for {name}");
|
|
||||||
print!("\n (module {dep:?} 0x{:>08x} 0x{:>08x}\n {resolved:?}",
|
|
||||||
&descriptor.first_thunk.0,
|
|
||||||
&descriptor.original_first_thunk.0);
|
|
||||||
let mut imports = Vec::new();
|
|
||||||
let thunks = descriptor.get_first_thunk(dll)?;
|
|
||||||
let origs = descriptor.get_original_first_thunk(dll)?;
|
|
||||||
let lookups = descriptor.get_lookup_thunks(dll)?;
|
|
||||||
for (thunk, orig, lookup, import) in izip!(
|
|
||||||
thunks.iter().map(|thunk|format!("0x{:08x}", match thunk {
|
|
||||||
Thunk::Thunk32(t) => panic!("32 bit thunk"),
|
|
||||||
Thunk::Thunk64(t) => t.0
|
|
||||||
})),
|
|
||||||
origs.iter().map(|thunk|format!("0x{:08x}", match thunk {
|
|
||||||
Thunk::Thunk32(t) => panic!("32 bit original thunk"),
|
|
||||||
Thunk::Thunk64(t) => t.0
|
|
||||||
})),
|
|
||||||
lookups.iter().map(|thunk|format!("0x{:08x}", match thunk {
|
|
||||||
Thunk::Thunk32(t) => panic!("32 bit original thunk"),
|
|
||||||
Thunk::Thunk64(t) => t.0
|
|
||||||
})),
|
|
||||||
descriptor.get_imports(dll)?
|
|
||||||
) {
|
|
||||||
match import {
|
|
||||||
ImportData::Ordinal(x) =>
|
|
||||||
print!("\n (import-ordinal {thunk} 0x{x:>04x})"),
|
|
||||||
ImportData::ImportByName(n) =>
|
|
||||||
print!("\n (import-by-name {thunk} {n:?})"),
|
|
||||||
}
|
|
||||||
imports.push((thunk, orig, import));
|
|
||||||
}
|
|
||||||
import_map.insert(dep, (resolved, imports));
|
|
||||||
println!(")")
|
|
||||||
}
|
|
||||||
for (name, (path, imports)) in import_map.iter() {
|
|
||||||
self.load(path)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn load_exports (&mut self, path: &PathBuf, dll: &VecPE) -> Usually<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn load_bang_data (&mut self, path: &Arc<PathBuf>) -> Usually<Arc<[u8]>> {
|
|
||||||
let (bang, data) = slice_shebang(read(path.as_path())?.as_slice());
|
|
||||||
self.path_to_bang.insert(path.clone(), bang.clone());
|
|
||||||
if bang.len() > 0 {
|
|
||||||
println!(" (bang {path:?} {:x})", bang.len())
|
|
||||||
}
|
|
||||||
self.path_to_data.insert(path.clone(), data.clone());
|
|
||||||
println!(" (buffer {:p} 0x{:08x} {path:?})", data.as_ptr(), data.len());
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
fn load_pe (&mut self, path: &Arc<PathBuf>, data: &Arc<[u8]>) -> Usually<Arc<VecPE>> {
|
|
||||||
let pe = Arc::new(VecPE::from_disk_data(data));
|
|
||||||
self.path_to_pe.insert(path.clone(), pe.clone());
|
|
||||||
Ok(pe)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue