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(())
|
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::*;
|
use crate::*;
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// Collect all calls that point to imports.
|
/// Collect all calls that point to imports.
|
||||||
pub fn load_call_sites (self: Arc<Self>) -> Usually<Arc<Self>> {
|
pub fn load_call_sites (self: Arc<Self>) -> Usually<Arc<Self>> {
|
||||||
|
|
@ -14,28 +15,6 @@ impl Module {
|
||||||
}
|
}
|
||||||
Ok(self)
|
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> {
|
fn parse_link (&self, link: &Arc<CallSite>) -> Option<u32> {
|
||||||
None
|
None
|
||||||
|
|
@ -60,3 +39,54 @@ impl Module {
|
||||||
.map(|(x, y)|(x.into(), y.into())))
|
.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 {
|
impl Module {
|
||||||
/// Collect all exported methods.
|
/// Collect all exported methods.
|
||||||
pub fn load_exports (self: Arc<Self>) -> Usually<Arc<Self>> {
|
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())?;
|
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)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ impl Module {
|
||||||
pub fn load_imports (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
|
pub fn load_imports (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
|
||||||
let pe = self.pe.clone();
|
let pe = self.pe.clone();
|
||||||
let directory = ImportDirectory::parse(pe.as_ref())?;
|
let directory = ImportDirectory::parse(pe.as_ref())?;
|
||||||
|
let mut new_modules = vec![];
|
||||||
for descriptor in directory.descriptors.iter() {
|
for descriptor in directory.descriptors.iter() {
|
||||||
let (name, imports) = Self::parse_import(pe.as_ref(), descriptor)?;
|
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);
|
let exists = self.namespace.read().unwrap().contains_key(&name);
|
||||||
println!("{exists} {name} {:?}", self.namespace.read().unwrap().keys().collect::<Vec<_>>());
|
|
||||||
if !exists {
|
if !exists {
|
||||||
|
Log::dep(false, &name, &imports);
|
||||||
let path = self.find(&name)?.expect("not found");
|
let path = self.find(&name)?.expect("not found");
|
||||||
let module = Arc::new(Self {
|
let module = Arc::new(Self {
|
||||||
namespace: self.namespace.clone(),
|
namespace: self.namespace.clone(),
|
||||||
|
|
@ -17,7 +17,12 @@ impl Module {
|
||||||
..Self::from_path(&path, self.verbose)?
|
..Self::from_path(&path, self.verbose)?
|
||||||
});
|
});
|
||||||
self.namespace.write().unwrap().insert(module.name.clone(), module.clone());
|
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 {
|
if self.verbose {
|
||||||
|
|
|
||||||
|
|
@ -119,10 +119,14 @@ impl Module {
|
||||||
}
|
}
|
||||||
/// Load the dependency tree, starting from this module.
|
/// Load the dependency tree, starting from this module.
|
||||||
fn load (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
|
fn load (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
|
||||||
Ok(self
|
let module = self
|
||||||
.load_imports(recurse)?
|
|
||||||
.load_exports()?
|
.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.
|
/// Search for DLL by name in search paths.
|
||||||
fn find (&self, name: &impl AsRef<str>) -> Usually<Option<PathBuf>> {
|
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() {
|
for base in self.search_paths.read().unwrap().iter() {
|
||||||
let mut path = base.as_ref().clone();
|
let mut path = base.as_ref().clone();
|
||||||
path.push(name.to_lowercase());
|
path.push(name.to_lowercase());
|
||||||
if self.verbose {
|
Log::find(false, &name, &path);
|
||||||
println!("(find? {name} {path:?})");
|
|
||||||
}
|
|
||||||
if std::fs::exists(&path)? {
|
if std::fs::exists(&path)? {
|
||||||
if self.verbose {
|
Log::found(false, &name, &path);
|
||||||
println!("(found {name} {path:?})");
|
|
||||||
}
|
|
||||||
return Ok(Some(canonicalize(&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,
|
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>) {
|
pub fn load (show: bool, path: &impl AsRef<Path>) {
|
||||||
if show {
|
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>)]) {
|
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());
|
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 {
|
impl Show {
|
||||||
|
|
@ -52,17 +62,10 @@ impl Show {
|
||||||
|
|
||||||
impl std::fmt::Debug for Module {
|
impl std::fmt::Debug for Module {
|
||||||
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
|
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
|
||||||
let deps = "";// format!("(deps lib {:>4} addr {:>4})",
|
write!(f, "(dll {BOLD}{UNDERLINE}{:15}{RESET} [0x{:>08x}] {} (img 0x{:>08x} -> mem 0x{:>08x}))",
|
||||||
//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})",
|
|
||||||
&self.name,
|
&self.name,
|
||||||
self.code_size,
|
self.code_size,
|
||||||
|
format!("({:>5})", self.exports.read().unwrap().len()),
|
||||||
self.code_start,
|
self.code_start,
|
||||||
self.code_base)
|
self.code_base)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue