mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 10:46:42 +01:00
good entrypoint for async rust
This commit is contained in:
parent
6660e28287
commit
0a1b74b2ae
6 changed files with 170 additions and 112 deletions
|
|
@ -434,3 +434,88 @@ impl Default for AEffect {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Relink a VST.
|
||||
//fn run (&mut self, path: impl AsRef<Path>) -> Usually<()> {
|
||||
//let path = path.as_ref().to_str().expect("path must be unicode");
|
||||
//let path = self.find(path)?.unwrap_or_else(||panic!("# not found: {path:?}"));
|
||||
//let main = self.load(&path)?;
|
||||
//Ok(())
|
||||
//}
|
||||
/// Load all dependencies recursively, starting from the given path.
|
||||
//fn load_all (&mut self, path: &impl AsRef<Path>) -> Usually<Arc<Module>> {
|
||||
//let name = to_dll_name(path);
|
||||
//let path: Arc<PathBuf> = Arc::from(PathBuf::from(path.as_ref()));
|
||||
//if self.modules.contains_key(&name) {
|
||||
//let module = self.modules.get(&name).unwrap().clone();
|
||||
//return Ok(module)
|
||||
//}
|
||||
//Log::load(self.verbose, &path);
|
||||
//let module = Arc::new(Module::new(&path, self.verbose)?.load(self.verbose)?);
|
||||
//self.modules.insert(module.name.clone(), module.clone());
|
||||
//Ok(module)
|
||||
//}
|
||||
//fn resolve (&self, dll: &Module, addr: u32, link: &Arc<CallSite>) -> Usually<()> {
|
||||
//let addr = (addr - dll.code_base) as usize;
|
||||
//dll.show_call_site(addr, link.length, 1);
|
||||
//link.show();
|
||||
//Ok(())
|
||||
//}
|
||||
//fn resolve_recursively (&self, dll: &Module, addr: u32, link: &Arc<CallSite>) -> Usually<()> {
|
||||
//self.resolve(dll, addr, link)?;
|
||||
//let module = &link.target.name;
|
||||
//let export = &link.method;
|
||||
//if let Some((module, export)) = match self.modules
|
||||
//.get(module)
|
||||
//.map(|module|module.exports.get(export))
|
||||
//{
|
||||
//Some(Some(ThunkData::Function(rva))) => Some((module.clone(), export.clone())),
|
||||
//Some(Some(ThunkData::ForwarderString(rva))) => dll.resolve_forward(&rva)?,
|
||||
//Some(Some(thunk)) => panic!("# unsupported {thunk:?}"),
|
||||
//Some(None) => panic!("# export not resolved: {export}"),
|
||||
//None => panic!("# module not resolved: {module}"),
|
||||
//} {
|
||||
//let module = self.modules.get(&module).unwrap_or_else(||panic!("# no module {module}"));
|
||||
//let method = module.exports.get(&export).unwrap_or_else(||panic!("# no method {export}"));
|
||||
//println!("{module:?} {export} {method:?}");
|
||||
//} else {
|
||||
//panic!("# unresolved link at {:?} [{addr}]", &dll.name)
|
||||
//}
|
||||
//Ok(())
|
||||
//}
|
||||
|
||||
/// Collect an imported dependency's descriptor thunks into a temporary [Vec].
|
||||
///
|
||||
/// Most of these are currently discarded, but may be needed in the future
|
||||
/// to resolve some of the trickier linkings.
|
||||
fn import_collect (pe: &VecPE, descriptor: &ImageImportDescriptor)
|
||||
-> Usually<(Arc<str>, Vec<(usize, Arc<str>)>)>
|
||||
{
|
||||
let mut buffer = vec![];
|
||||
let name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
|
||||
for (index, import) in descriptor.get_imports(pe)?.iter().enumerate() {
|
||||
buffer.push((index, match import {
|
||||
ImportData::Ordinal(x) => format!("___VESTAL_ORDINAL_{x}"),
|
||||
ImportData::ImportByName(name) => format!("{name}"),
|
||||
}.into()));
|
||||
}
|
||||
Ok((name.into(), buffer))
|
||||
//let imp = descriptor.get_imports(pe)?;
|
||||
//let iat = descriptor.get_first_thunk(pe)?;
|
||||
//let ilt = descriptor.get_original_first_thunk(pe)?;
|
||||
//let lut = descriptor.get_lookup_thunks(pe)?;
|
||||
//for (index, (import, thunk, orig, lookup)) in izip!(
|
||||
//imp,
|
||||
//iat.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "IAT thunk"))),
|
||||
//ilt.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "ILT (orig) thunk"))),
|
||||
//lut.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "lookup thunk"))),
|
||||
//).enumerate() {
|
||||
//buffer.push((index, import));//, thunk, orig, lookup));
|
||||
//}
|
||||
}
|
||||
|
||||
//fn thunk_unwrap (thunk: &Thunk, name: impl AsRef<str>) -> u64 {
|
||||
//match thunk {
|
||||
//Thunk::Thunk32(t) => panic!("32 bit {}", name.as_ref()),
|
||||
//Thunk::Thunk64(t) => t.0
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::*;
|
||||
|
||||
impl Module {
|
||||
/// Collect all calls that point to imports.
|
||||
pub fn load_call_sites (self: Arc<Self>) -> Usually<Arc<Self>> {
|
||||
|
|
@ -14,28 +15,6 @@ impl Module {
|
|||
}
|
||||
Ok(self)
|
||||
}
|
||||
fn target (opcodes: &[u8], offset_rva: u32) -> Option<u32> {
|
||||
let rip = offset_rva + opcodes.len() as u32;
|
||||
match opcodes[0] {
|
||||
0xff => match opcodes[1] {
|
||||
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
|
||||
opcodes[2], opcodes[3], opcodes[4], opcodes[5]
|
||||
])),
|
||||
_ => {}
|
||||
},
|
||||
0x48 => match opcodes[1] {
|
||||
0xff => match opcodes[2] {
|
||||
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
|
||||
opcodes[3], opcodes[4], opcodes[5], opcodes[6]
|
||||
])),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_link (&self, link: &Arc<CallSite>) -> Option<u32> {
|
||||
None
|
||||
|
|
@ -60,3 +39,54 @@ impl Module {
|
|||
.map(|(x, y)|(x.into(), y.into())))
|
||||
}
|
||||
}
|
||||
|
||||
impl CallSite {
|
||||
pub fn matches (instruction: &Instruction) -> bool {
|
||||
instruction.op0_kind() == OpKind::Memory && (
|
||||
instruction.flow_control() == FlowControl::IndirectBranch ||
|
||||
instruction.flow_control() == FlowControl::IndirectCall
|
||||
)
|
||||
}
|
||||
pub fn skip (opcodes: &[u8]) -> bool {
|
||||
match opcodes[0] {
|
||||
0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] {
|
||||
0xff => return true,
|
||||
_ => {}
|
||||
},
|
||||
0x48 => match opcodes[2] {
|
||||
0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => return true,
|
||||
_ => {}
|
||||
},
|
||||
0xff => match opcodes[1] {
|
||||
0x10 | 0x12 | 0x13 |
|
||||
0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 |
|
||||
0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => return true,
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
}
|
||||
pub fn target (opcodes: &[u8], offset_rva: u32) -> Option<u32> {
|
||||
let rip = offset_rva + opcodes.len() as u32;
|
||||
match opcodes[0] {
|
||||
0xff => match opcodes[1] {
|
||||
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
|
||||
opcodes[2], opcodes[3], opcodes[4], opcodes[5]
|
||||
])),
|
||||
_ => {}
|
||||
},
|
||||
0x48 => match opcodes[1] {
|
||||
0xff => match opcodes[2] {
|
||||
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
|
||||
opcodes[3], opcodes[4], opcodes[5], opcodes[6]
|
||||
])),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use crate::*;
|
|||
impl Module {
|
||||
/// Collect all exported methods.
|
||||
pub fn load_exports (self: Arc<Self>) -> Usually<Arc<Self>> {
|
||||
let directory = ExportDirectory::parse(self.pe.as_ref())?;
|
||||
let directory = ExportDirectory::parse(self.pe.as_ref())?;
|
||||
let export_map = directory.get_export_map(self.pe.as_ref())?;
|
||||
*self.exports.write().unwrap() = export_map.into_iter().map(|(k, v)|(k.into(), v)).collect();
|
||||
let exports = export_map.into_iter().map(|(k, v)|(k.into(), v)).collect();
|
||||
*self.exports.write().unwrap() = exports;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ impl Module {
|
|||
pub fn load_imports (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
|
||||
let pe = self.pe.clone();
|
||||
let directory = ImportDirectory::parse(pe.as_ref())?;
|
||||
let mut new_modules = vec![];
|
||||
for descriptor in directory.descriptors.iter() {
|
||||
let (name, imports) = Self::parse_import(pe.as_ref(), descriptor)?;
|
||||
Log::dep(self.verbose, &name, &imports);
|
||||
let exists = self.namespace.read().unwrap().contains_key(&name);
|
||||
println!("{exists} {name} {:?}", self.namespace.read().unwrap().keys().collect::<Vec<_>>());
|
||||
if !exists {
|
||||
Log::dep(false, &name, &imports);
|
||||
let path = self.find(&name)?.expect("not found");
|
||||
let module = Arc::new(Self {
|
||||
namespace: self.namespace.clone(),
|
||||
|
|
@ -17,7 +17,12 @@ impl Module {
|
|||
..Self::from_path(&path, self.verbose)?
|
||||
});
|
||||
self.namespace.write().unwrap().insert(module.name.clone(), module.clone());
|
||||
module.load(recurse);
|
||||
new_modules.push(module);
|
||||
}
|
||||
}
|
||||
if recurse {
|
||||
for module in new_modules {
|
||||
module.load(recurse)?;
|
||||
}
|
||||
}
|
||||
if self.verbose {
|
||||
|
|
|
|||
|
|
@ -119,10 +119,14 @@ impl Module {
|
|||
}
|
||||
/// Load the dependency tree, starting from this module.
|
||||
fn load (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
|
||||
Ok(self
|
||||
.load_imports(recurse)?
|
||||
let module = self
|
||||
.load_exports()?
|
||||
.load_call_sites()?)
|
||||
.load_imports(recurse)?
|
||||
.load_call_sites()?;
|
||||
if module.verbose {
|
||||
println!("{:?}", &module);
|
||||
}
|
||||
Ok(module)
|
||||
}
|
||||
/// Search for DLL by name in search paths.
|
||||
fn find (&self, name: &impl AsRef<str>) -> Usually<Option<PathBuf>> {
|
||||
|
|
@ -130,13 +134,9 @@ impl Module {
|
|||
for base in self.search_paths.read().unwrap().iter() {
|
||||
let mut path = base.as_ref().clone();
|
||||
path.push(name.to_lowercase());
|
||||
if self.verbose {
|
||||
println!("(find? {name} {path:?})");
|
||||
}
|
||||
Log::find(false, &name, &path);
|
||||
if std::fs::exists(&path)? {
|
||||
if self.verbose {
|
||||
println!("(found {name} {path:?})");
|
||||
}
|
||||
Log::found(false, &name, &path);
|
||||
return Ok(Some(canonicalize(&path)?))
|
||||
}
|
||||
}
|
||||
|
|
@ -172,69 +172,3 @@ fn base_of_code (pe: &VecPE) -> Usually<u32> {
|
|||
NTHeaders::NTHeaders64(h64) => h64.optional_header.base_of_code.0,
|
||||
})
|
||||
}
|
||||
|
||||
/// Collect an imported dependency's descriptor thunks into a temporary [Vec].
|
||||
///
|
||||
/// Most of these are currently discarded, but may be needed in the future
|
||||
/// to resolve some of the trickier linkings.
|
||||
fn import_collect (pe: &VecPE, descriptor: &ImageImportDescriptor)
|
||||
-> Usually<(Arc<str>, Vec<(usize, Arc<str>)>)>
|
||||
{
|
||||
let mut buffer = vec![];
|
||||
let name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
|
||||
for (index, import) in descriptor.get_imports(pe)?.iter().enumerate() {
|
||||
buffer.push((index, match import {
|
||||
ImportData::Ordinal(x) => format!("___VESTAL_ORDINAL_{x}"),
|
||||
ImportData::ImportByName(name) => format!("{name}"),
|
||||
}.into()));
|
||||
}
|
||||
Ok((name.into(), buffer))
|
||||
//let imp = descriptor.get_imports(pe)?;
|
||||
//let iat = descriptor.get_first_thunk(pe)?;
|
||||
//let ilt = descriptor.get_original_first_thunk(pe)?;
|
||||
//let lut = descriptor.get_lookup_thunks(pe)?;
|
||||
//for (index, (import, thunk, orig, lookup)) in izip!(
|
||||
//imp,
|
||||
//iat.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "IAT thunk"))),
|
||||
//ilt.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "ILT (orig) thunk"))),
|
||||
//lut.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "lookup thunk"))),
|
||||
//).enumerate() {
|
||||
//buffer.push((index, import));//, thunk, orig, lookup));
|
||||
//}
|
||||
}
|
||||
|
||||
//fn thunk_unwrap (thunk: &Thunk, name: impl AsRef<str>) -> u64 {
|
||||
//match thunk {
|
||||
//Thunk::Thunk32(t) => panic!("32 bit {}", name.as_ref()),
|
||||
//Thunk::Thunk64(t) => t.0
|
||||
//}
|
||||
//}
|
||||
|
||||
impl CallSite {
|
||||
fn matches (instruction: &Instruction) -> bool {
|
||||
instruction.op0_kind() == OpKind::Memory && (
|
||||
instruction.flow_control() == FlowControl::IndirectBranch ||
|
||||
instruction.flow_control() == FlowControl::IndirectCall
|
||||
)
|
||||
}
|
||||
fn skip (opcodes: &[u8]) -> bool {
|
||||
match opcodes[0] {
|
||||
0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] {
|
||||
0xff => return true,
|
||||
_ => {}
|
||||
},
|
||||
0x48 => match opcodes[2] {
|
||||
0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => return true,
|
||||
_ => {}
|
||||
},
|
||||
0xff => match opcodes[1] {
|
||||
0x10 | 0x12 | 0x13 |
|
||||
0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 |
|
||||
0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => return true,
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ impl Log {
|
|||
}
|
||||
pub fn load (show: bool, path: &impl AsRef<Path>) {
|
||||
if show {
|
||||
println!("(load {:?})", path.as_ref());
|
||||
println!("{DIM}(load {:?}){RESET}", path.as_ref());
|
||||
}
|
||||
}
|
||||
pub fn dep (show: bool, name: &impl AsRef<str>, exports: &[(usize, Arc<str>)]) {
|
||||
|
|
@ -29,6 +29,16 @@ impl Log {
|
|||
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 {
|
||||
|
|
@ -52,17 +62,10 @@ impl Show {
|
|||
|
||||
impl std::fmt::Debug for Module {
|
||||
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
|
||||
let deps = "";// format!("(deps lib {:>4} addr {:>4})",
|
||||
//self.dependencies.len(),
|
||||
//self.deps_by_address.len());
|
||||
let links = "";// format!("(links src {:>4} tgt {:>4})",
|
||||
//self.links_by_source.len(),
|
||||
//self.links_by_target.len());
|
||||
let exports = format!("(exp {:>5})",
|
||||
self.exports.read().unwrap().len());
|
||||
write!(f, "(dll {BOLD}{UNDERLINE}{:15}{RESET} [0x{:>08x}] (img 0x{:>08x} -> mem 0x{:>08x}) {deps} {links} {exports})",
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue