mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 12:56:41 +01:00
resolve 1 level of imports
This commit is contained in:
parent
5188bc5581
commit
dbca25d9cb
1 changed files with 54 additions and 53 deletions
|
|
@ -26,11 +26,11 @@ struct Dll {
|
||||||
pe: Arc<VecPE>,
|
pe: Arc<VecPE>,
|
||||||
/// Bytes of `.text` section
|
/// Bytes of `.text` section
|
||||||
code: Arc<[u8]>,
|
code: Arc<[u8]>,
|
||||||
/// DLLs that this one depends on
|
/// Addresses of each imported method from each dependency
|
||||||
deps: BTreeMap<Arc<str>, Arc<Self>>,
|
deps: BTreeMap<Arc<str>, BTreeMap<Arc<str>, u32>>,
|
||||||
/// Calls to deps by source address.
|
/// Calls to dependencies by source address
|
||||||
calls_by_source: BTreeMap<u32, Arc<Call>>,
|
calls_by_source: BTreeMap<u32, Arc<Call>>,
|
||||||
/// Calls to deps by target address.
|
/// Calls to dependencies by target address
|
||||||
calls_by_target: BTreeMap<u32, Vec<Arc<Call>>>,
|
calls_by_target: BTreeMap<u32, Vec<Arc<Call>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,15 +53,20 @@ struct Call {
|
||||||
impl Rebuilder {
|
impl Rebuilder {
|
||||||
fn new (path: &impl AsRef<Path>) -> Usually<Self> {
|
fn new (path: &impl AsRef<Path>) -> Usually<Self> {
|
||||||
let mut build = Self { paths: Default::default(), dlls: Default::default() };
|
let mut build = Self { paths: Default::default(), dlls: Default::default() };
|
||||||
let dll = Dll::new(&mut build, &Arc::new(PathBuf::from(path.as_ref())));
|
let path: Arc<PathBuf> = Arc::from(PathBuf::from(path.as_ref()));
|
||||||
|
build.paths.insert(path.clone());
|
||||||
|
let dll = Dll::new(&Arc::new(PathBuf::from(path.as_ref())), false)?;
|
||||||
|
build.dlls.insert(dll.name.clone(), dll);
|
||||||
Ok(build)
|
Ok(build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dll {
|
impl Dll {
|
||||||
fn new (build: &mut Rebuilder, path: &Arc<PathBuf>) -> Usually<Arc<Self>> {
|
fn new (
|
||||||
|
path: &Arc<PathBuf>,
|
||||||
|
verbose: bool
|
||||||
|
) -> Usually<Arc<Self>> {
|
||||||
println!("\n(load {BOLD}{path:?}{RESET})");
|
println!("\n(load {BOLD}{path:?}{RESET})");
|
||||||
build.paths.insert(path.clone());
|
|
||||||
let name = path.file_name().expect("no file name");
|
let name = path.file_name().expect("no file name");
|
||||||
let name: Arc<str> = name.to_str().map(Arc::from).expect("non-unicode filename");
|
let name: Arc<str> = name.to_str().map(Arc::from).expect("non-unicode filename");
|
||||||
let (bang, data) = crate::bang::slice_shebang(read(path.as_path())?.as_slice());
|
let (bang, data) = crate::bang::slice_shebang(read(path.as_path())?.as_slice());
|
||||||
|
|
@ -72,6 +77,12 @@ impl Dll {
|
||||||
let text = &data[start..start+size];
|
let text = &data[start..start+size];
|
||||||
let mut calls_by_source = Default::default();
|
let mut calls_by_source = Default::default();
|
||||||
let mut calls_by_target = Default::default();
|
let mut calls_by_target = Default::default();
|
||||||
|
let mut deps = Default::default();
|
||||||
|
let (modules_count, methods_count) = Self::deps(
|
||||||
|
&pe,
|
||||||
|
&mut deps,
|
||||||
|
false
|
||||||
|
)?;
|
||||||
let calls = Self::calls(
|
let calls = Self::calls(
|
||||||
&name,
|
&name,
|
||||||
&pe,
|
&pe,
|
||||||
|
|
@ -81,38 +92,43 @@ impl Dll {
|
||||||
&mut calls_by_target,
|
&mut calls_by_target,
|
||||||
false
|
false
|
||||||
)?;
|
)?;
|
||||||
let (modules_count, methods_count) = Self::imports(&pe)?;
|
|
||||||
let dll = Arc::new(Self {
|
let dll = Arc::new(Self {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
bang,
|
bang,
|
||||||
pe,
|
pe,
|
||||||
code: Arc::from(text),
|
code: Arc::from(text),
|
||||||
deps: Default::default(),
|
deps: deps.clone(),
|
||||||
calls_by_source,
|
calls_by_source,
|
||||||
calls_by_target,
|
calls_by_target,
|
||||||
});
|
});
|
||||||
println!(" (deps-modules {modules_count})");
|
println!(" (deps-modules {modules_count})");
|
||||||
println!(" (deps-methods {methods_count})");
|
println!(" (deps-methods {methods_count})");
|
||||||
println!(" (call-sites {calls})");
|
println!(" (call-sites {calls})");
|
||||||
for (call, sites) in dll.calls_by_target.iter() {
|
if verbose {
|
||||||
println!(" (0x{call:08x}\n {:?})", sites.iter()
|
for (call, sites) in dll.calls_by_target.iter() {
|
||||||
.map(|call|format!("0x{:08x}", call.offset))
|
println!(" (0x{call:08x}\n {:?})", sites.iter()
|
||||||
.collect::<Vec<_>>());
|
.map(|call|format!("0x{:08x}", call.offset))
|
||||||
|
.collect::<Vec<_>>());
|
||||||
|
}
|
||||||
|
println!("{deps:#?}");
|
||||||
}
|
}
|
||||||
build.dlls.insert(name.clone(), dll.clone());
|
|
||||||
Ok(dll)
|
Ok(dll)
|
||||||
}
|
}
|
||||||
fn imports (pe: &VecPE) -> Usually<(usize, usize)> {
|
fn deps (
|
||||||
|
pe: &VecPE,
|
||||||
|
deps: &mut BTreeMap<Arc<str>, BTreeMap<Arc<str>, u32>>,
|
||||||
|
verbose: bool,
|
||||||
|
) -> Usually<(usize, usize)> {
|
||||||
let directory = ImportDirectory::parse(pe)?;
|
let directory = ImportDirectory::parse(pe)?;
|
||||||
let mut total = 0;
|
let mut modules = 0;
|
||||||
|
let mut methods = 0;
|
||||||
for descriptor in directory.descriptors {
|
for descriptor in directory.descriptors {
|
||||||
let dep = descriptor.get_name(pe)?.as_str()?.to_lowercase();
|
let module_name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
|
||||||
let imp = descriptor.get_imports(pe)?;
|
let imp = descriptor.get_imports(pe)?;
|
||||||
let iat = descriptor.get_first_thunk(pe)?;
|
let iat = descriptor.get_first_thunk(pe)?;
|
||||||
let ilt = descriptor.get_original_first_thunk(pe)?;
|
let ilt = descriptor.get_original_first_thunk(pe)?;
|
||||||
let lut = descriptor.get_lookup_thunks(pe)?;
|
let lut = descriptor.get_lookup_thunks(pe)?;
|
||||||
let mut imports = Vec::new();
|
|
||||||
let unwrap_thunk = |thunk: &Thunk, name|match thunk {
|
let unwrap_thunk = |thunk: &Thunk, name|match thunk {
|
||||||
Thunk::Thunk32(t) => panic!("32 bit {name}"),
|
Thunk::Thunk32(t) => panic!("32 bit {name}"),
|
||||||
Thunk::Thunk64(t) => t.0
|
Thunk::Thunk64(t) => t.0
|
||||||
|
|
@ -124,32 +140,28 @@ impl Dll {
|
||||||
lut.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "lookup thunk"))),
|
lut.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "lookup thunk"))),
|
||||||
).enumerate() {
|
).enumerate() {
|
||||||
let call_via = descriptor.first_thunk.0 + index as u32 * 8;
|
let call_via = descriptor.first_thunk.0 + index as u32 * 8;
|
||||||
let name = match import {
|
let method = match import {
|
||||||
ImportData::Ordinal(x) => {
|
ImportData::Ordinal(x) => format!("___VESTAL_ORDINAL_{x}"),
|
||||||
//print!("\n (import-ordinal {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} 0x{:>04x})",
|
ImportData::ImportByName(name) => format!("{name}"),
|
||||||
//call_via, thunk, orig, lookup, x);
|
|
||||||
format!("___VESTAL___ORD___{x}___")
|
|
||||||
},
|
|
||||||
ImportData::ImportByName(name) => {
|
|
||||||
//print!("\n (import-by-name {BOLD}0x{:>08x}{RESET} IAT={} ILT={} LU={} {:?})",
|
|
||||||
//call_via, thunk, orig, lookup, name);
|
|
||||||
format!("{name}")
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
println!(" ({index:5} 0x{call_via:08x} {dep:>20} {name}");
|
let module_name: Arc<str> = module_name.clone().into();
|
||||||
imports.push((thunk, orig, import));
|
if !deps.contains_key(&module_name) {
|
||||||
total += 1;
|
deps.insert(module_name.clone(), Default::default());
|
||||||
//if let Some(existing) = self.addr_to_import.get(&call_via) {
|
modules += 1;
|
||||||
//panic!("addr space overlap at 0x{call_via:x}: {}::{} vs {}::{}",
|
}
|
||||||
//existing.0,
|
let module = deps.get_mut(&module_name).unwrap();
|
||||||
//existing.1,
|
let method: Arc<str> = method.clone().into();
|
||||||
//dep.to_string(),
|
if module.contains_key(&method) {
|
||||||
//name);
|
panic!("duplicate method {method} in {module_name}");
|
||||||
//}
|
}
|
||||||
//self.addr_to_import.insert(call_via, (dep.to_string(), name));
|
module.insert(method.clone(), call_via);
|
||||||
|
methods += 1;
|
||||||
|
if verbose {
|
||||||
|
println!(" ({index:5} 0x{call_via:08x} {module_name:>20} {method})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((0, total))
|
Ok((modules, methods))
|
||||||
}
|
}
|
||||||
fn calls (
|
fn calls (
|
||||||
name: &Arc<str>,
|
name: &Arc<str>,
|
||||||
|
|
@ -193,17 +205,6 @@ impl Dll {
|
||||||
print!(" ({BOLD}0x{offset:08x}{RESET} 0x{offset_rva:08x}");
|
print!(" ({BOLD}0x{offset:08x}{RESET} 0x{offset_rva:08x}");
|
||||||
println!(" {BOLD}{instruction:30}{RESET} 0x{call_target:x})");
|
println!(" {BOLD}{instruction:30}{RESET} 0x{call_target:x})");
|
||||||
}
|
}
|
||||||
//let unknown = (String::from("unknown"), String::from("unknown"));
|
|
||||||
//let target = self.addr_to_import.get(call_target).unwrap_or(&unknown).0;
|
|
||||||
//let method = self.addr_to_import.get(call_target).unwrap_or(&unknown).1;
|
|
||||||
//let external = format!("{}::{}", target, method);
|
|
||||||
//if verbose {
|
|
||||||
//println!(" ({BOLD}{external}{RESET}\n Offset(0x{:08x}) RVA(R=0x{:08x})\n {:25} {:40} 0x{:08x}",
|
|
||||||
//offset, offset_rva,
|
|
||||||
//opcodes.iter().map(|x|format!("{x:>02x}")).collect::<Vec<_>>().join(" "),
|
|
||||||
//instruction, call_target,
|
|
||||||
//);
|
|
||||||
//}
|
|
||||||
return Ok(Some(Arc::new(Call {
|
return Ok(Some(Arc::new(Call {
|
||||||
offset: offset,
|
offset: offset,
|
||||||
source: offset_rva,
|
source: offset_rva,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue