mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 10:46:42 +01:00
flatten and cleanup
This commit is contained in:
parent
459f6c643c
commit
ed01876426
2 changed files with 311 additions and 310 deletions
|
|
@ -2,7 +2,7 @@
|
|||
mod util;
|
||||
mod bang;
|
||||
//mod load;
|
||||
//mod show;
|
||||
mod show;
|
||||
//mod link;
|
||||
pub(crate) use self::util::*;
|
||||
|
||||
|
|
@ -29,16 +29,6 @@ fn main () -> Usually<()> {
|
|||
let name = rebuilder.load(&path, true)?;
|
||||
let main = rebuilder.dlls.get(&name).unwrap();
|
||||
rebuilder.resolve_calls(&main, true, true)?;
|
||||
//println!("{:#?}", &main.calls_by_source);
|
||||
for (name, dll) in rebuilder.dlls.iter() {
|
||||
}
|
||||
//let mut decoder = Decoder::with_ip(64, &main.code, 0x1000, 0);
|
||||
//while decoder.can_decode() {
|
||||
//let instruction = decoder.decode();
|
||||
//if Dll::matches(&instruction) {
|
||||
//println!("{instruction}");
|
||||
//}
|
||||
//}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +118,7 @@ impl Rebuilder {
|
|||
dll.print_hex(addr, 1);
|
||||
if recurse {
|
||||
let mut decoder = Decoder::with_ip(
|
||||
64, &dll.code[addr..], 0, DecoderOptions::NONE
|
||||
64, &dll.code[addr..], 0x1000, DecoderOptions::NONE
|
||||
);
|
||||
while decoder.can_decode() {
|
||||
let position = decoder.position();
|
||||
|
|
@ -200,21 +190,21 @@ impl Dll {
|
|||
let mut calls_by_target = Default::default();
|
||||
let mut deps_by_library = Default::default();
|
||||
let mut deps_by_address = Default::default();
|
||||
let exports = Self::exports(&pe).unwrap_or_default();
|
||||
let (modules_count, methods_count) = Self::deps(
|
||||
&pe,
|
||||
let exports = collect_exports(&pe).unwrap_or_default();
|
||||
let (modules_count, methods_count) = collect_deps(
|
||||
&mut deps_by_library,
|
||||
&mut deps_by_address,
|
||||
&pe,
|
||||
false
|
||||
)?;
|
||||
let calls = Call::calls(
|
||||
let calls = collect_calls(
|
||||
&mut calls_by_source,
|
||||
&mut calls_by_target,
|
||||
Some(&deps_by_address),
|
||||
&name,
|
||||
&pe,
|
||||
start,
|
||||
text,
|
||||
Some(&deps_by_address),
|
||||
&mut calls_by_source,
|
||||
&mut calls_by_target,
|
||||
false
|
||||
)?;
|
||||
Ok(Self {
|
||||
|
|
@ -234,109 +224,169 @@ impl Dll {
|
|||
pe,
|
||||
})
|
||||
}
|
||||
fn deps (
|
||||
pe: &VecPE,
|
||||
deps_by_library: &mut BTreeMap<Arc<str>, BTreeMap<Arc<str>, u32>>,
|
||||
deps_by_address: &mut BTreeMap<u32, (Arc<str>, Arc<str>)>,
|
||||
verbose: bool,
|
||||
) -> Usually<(usize, usize)> {
|
||||
let directory = ImportDirectory::parse(pe)?;
|
||||
let mut modules = 0;
|
||||
let mut methods = 0;
|
||||
for descriptor in directory.descriptors {
|
||||
let module_name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
|
||||
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)?;
|
||||
let unwrap_thunk = |thunk: &Thunk, name|match thunk {
|
||||
Thunk::Thunk32(t) => panic!("32 bit {name}"),
|
||||
Thunk::Thunk64(t) => t.0
|
||||
};
|
||||
for (index, (import, thunk, orig, lookup)) in izip!(
|
||||
imp,
|
||||
iat.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "IAT thunk"))),
|
||||
ilt.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "ILT (orig) thunk"))),
|
||||
lut.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "lookup thunk"))),
|
||||
).enumerate() {
|
||||
let call_via = descriptor.first_thunk.0 + index as u32 * 8;
|
||||
let method = match import {
|
||||
ImportData::Ordinal(x) => format!("___VESTAL_ORDINAL_{x}"),
|
||||
ImportData::ImportByName(name) => format!("{name}"),
|
||||
};
|
||||
let module_name: Arc<str> = module_name.clone().into();
|
||||
if !deps_by_library.contains_key(&module_name) {
|
||||
deps_by_library.insert(module_name.clone(), Default::default());
|
||||
modules += 1;
|
||||
}
|
||||
let module = deps_by_library.get_mut(&module_name).unwrap();
|
||||
let method: Arc<str> = method.clone().into();
|
||||
if module.contains_key(&method) {
|
||||
panic!("duplicate method {method} in {module_name}");
|
||||
}
|
||||
module.insert(method.clone(), call_via);
|
||||
if deps_by_address.contains_key(&call_via) {
|
||||
panic!("duplicate address {call_via} from {module_name}");
|
||||
}
|
||||
deps_by_address.insert(call_via, (module_name.clone(), method.clone()));
|
||||
methods += 1;
|
||||
if verbose {
|
||||
println!(" ({index:5} 0x{call_via:08x} {module_name:>20} {method})");
|
||||
}
|
||||
}
|
||||
}
|
||||
if verbose {
|
||||
println!(" (deps-modules {modules})");
|
||||
println!(" (deps-methods {methods})");
|
||||
for (module, methods) in deps_by_library.iter() {
|
||||
print!(" ({module}");
|
||||
for (method, addr) in methods.iter() {
|
||||
print!("\n (0x{addr:08x} {method})")
|
||||
}
|
||||
println!(")");
|
||||
}
|
||||
}
|
||||
Ok((modules, methods))
|
||||
}
|
||||
fn exports (pe: &VecPE) -> Usually<BTreeMap<Arc<str>, ThunkData>> {
|
||||
Ok(ImageExportDirectory::parse(pe)?
|
||||
.get_export_map(pe)?
|
||||
.into_iter()
|
||||
.map(|(k, v)|(k.into(), v))
|
||||
.collect())
|
||||
}
|
||||
fn parse_call (&self, call: &Arc<Call>) -> Option<u32> {
|
||||
self.deps_by_library.get(call.module.as_ref()?)?.get(call.method.as_ref()?).map(|x|*x)
|
||||
}
|
||||
fn print_call (&self, addr: usize, module: Option<&Arc<str>>, method: Option<&Arc<str>>) {
|
||||
let mut decoder = Decoder::with_ip(64, &self.code[addr..], 0, DecoderOptions::NONE);
|
||||
let instruction = decoder.decode();
|
||||
let opcodes = &self.code[addr..addr+instruction.len()].iter()
|
||||
.map(|x|format!("{x:02x}"))
|
||||
.join(" ");
|
||||
println!("{BOLD}0x{addr:>08x}{RESET} {:20} {DIM}{opcodes}{RESET} {BOLD}{instruction}{RESET} {module:?} {method:?}", &self.name);
|
||||
}
|
||||
fn print_hex (&self, addr: usize, n: usize) {
|
||||
let cfg = HexConfig {title: false, width: 16, group: 4, chunk: 1, ..HexConfig::default()};
|
||||
let snap = |x|(x/16)*16;
|
||||
let a = snap(addr - 16*n);
|
||||
let b = addr;
|
||||
let c = snap(addr + 16);
|
||||
let d = snap(c + 16*n);
|
||||
if n > 0 {
|
||||
println!("{DIM}{:?}{RESET}", &self.code[a..b].hex_conf(HexConfig {
|
||||
display_offset: self.code_base as usize + a, ..cfg
|
||||
}));
|
||||
}
|
||||
println!("{BOLD}{:?}{RESET}", &self.code[b..c].hex_conf(HexConfig {
|
||||
display_offset: self.code_base as usize + b, ..cfg
|
||||
}));
|
||||
if n > 0 {
|
||||
println!("{DIM}{:?}{RESET}", &self.code[c..d].hex_conf(HexConfig {
|
||||
display_offset: self.code_base as usize + c, ..cfg
|
||||
}));
|
||||
}
|
||||
|
||||
fn collect_deps (
|
||||
deps_by_library: &mut BTreeMap<Arc<str>, BTreeMap<Arc<str>, u32>>,
|
||||
deps_by_address: &mut BTreeMap<u32, (Arc<str>, Arc<str>)>,
|
||||
pe: &VecPE,
|
||||
verbose: bool,
|
||||
) -> Usually<(usize, usize)> {
|
||||
let directory = ImportDirectory::parse(pe)?;
|
||||
let mut modules = 0;
|
||||
let mut methods = 0;
|
||||
for descriptor in directory.descriptors {
|
||||
let module_name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
|
||||
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)?;
|
||||
let unwrap_thunk = |thunk: &Thunk, name|match thunk {
|
||||
Thunk::Thunk32(t) => panic!("32 bit {name}"),
|
||||
Thunk::Thunk64(t) => t.0
|
||||
};
|
||||
for (index, (import, thunk, orig, lookup)) in izip!(
|
||||
imp,
|
||||
iat.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "IAT thunk"))),
|
||||
ilt.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "ILT (orig) thunk"))),
|
||||
lut.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "lookup thunk"))),
|
||||
).enumerate() {
|
||||
let call_via = descriptor.first_thunk.0 + index as u32 * 8;
|
||||
let method = match import {
|
||||
ImportData::Ordinal(x) => format!("___VESTAL_ORDINAL_{x}"),
|
||||
ImportData::ImportByName(name) => format!("{name}"),
|
||||
};
|
||||
let module_name: Arc<str> = module_name.clone().into();
|
||||
if !deps_by_library.contains_key(&module_name) {
|
||||
deps_by_library.insert(module_name.clone(), Default::default());
|
||||
modules += 1;
|
||||
}
|
||||
let module = deps_by_library.get_mut(&module_name).unwrap();
|
||||
let method: Arc<str> = method.clone().into();
|
||||
if module.contains_key(&method) {
|
||||
panic!("duplicate method {method} in {module_name}");
|
||||
}
|
||||
module.insert(method.clone(), call_via);
|
||||
if deps_by_address.contains_key(&call_via) {
|
||||
panic!("duplicate address {call_via} from {module_name}");
|
||||
}
|
||||
deps_by_address.insert(call_via, (module_name.clone(), method.clone()));
|
||||
methods += 1;
|
||||
if verbose {
|
||||
println!(" ({index:5} 0x{call_via:08x} {module_name:>20} {method})");
|
||||
}
|
||||
}
|
||||
}
|
||||
if verbose {
|
||||
println!(" (deps-modules {modules})");
|
||||
println!(" (deps-methods {methods})");
|
||||
for (module, methods) in deps_by_library.iter() {
|
||||
print!(" ({module}");
|
||||
for (method, addr) in methods.iter() {
|
||||
print!("\n (0x{addr:08x} {method})")
|
||||
}
|
||||
println!(")");
|
||||
}
|
||||
}
|
||||
Ok((modules, methods))
|
||||
}
|
||||
|
||||
fn collect_exports (
|
||||
pe: &VecPE
|
||||
) -> Usually<BTreeMap<Arc<str>, ThunkData>> {
|
||||
Ok(ImageExportDirectory::parse(pe)?
|
||||
.get_export_map(pe)?
|
||||
.into_iter()
|
||||
.map(|(k, v)|(k.into(), v))
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn collect_calls (
|
||||
calls_by_source: &mut BTreeMap<u32, Arc<Call>>,
|
||||
calls_by_target: &mut BTreeMap<u32, Vec<Arc<Call>>>,
|
||||
deps: Option<&BTreeMap<u32, (Arc<str>, Arc<str>)>>,
|
||||
name: &Arc<str>,
|
||||
pe: &VecPE,
|
||||
start: usize,
|
||||
data: &[u8],
|
||||
verbose: bool,
|
||||
) -> Usually<usize> {
|
||||
let mut decoder = Decoder::with_ip(64, data, 0x1000, 0);
|
||||
let mut calls = 0;
|
||||
while decoder.can_decode() {
|
||||
if let Some(call) = collect_call(name, pe, start, data, deps, &mut decoder, false)? {
|
||||
calls += 1;
|
||||
calls_by_source.insert(call.source, call.clone());
|
||||
if !calls_by_target.contains_key(&call.target) {
|
||||
calls_by_target.insert(call.target, Default::default());
|
||||
}
|
||||
calls_by_target.get_mut(&call.target).unwrap().push(call);
|
||||
}
|
||||
}
|
||||
if verbose {
|
||||
println!(" (call-sites {calls})");
|
||||
for (target, sites) in calls_by_target.iter() {
|
||||
let (_, _, external) = dep_name(deps, *target);
|
||||
println!(" ({:>5}x call 0x{target:08x} {external})", sites.len());
|
||||
//.map(|site|format!("0x{:08x}", site.offset))
|
||||
//.collect::<Vec<_>>());
|
||||
//println!(" (call 0x{target:08x} {external}\n {:?})", sites.iter()
|
||||
//.map(|site|format!("0x{:08x}", site.offset))
|
||||
//.collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
Ok(calls)
|
||||
}
|
||||
|
||||
fn collect_call (
|
||||
name: &Arc<str>,
|
||||
pe: &VecPE,
|
||||
start: usize,
|
||||
data: &[u8],
|
||||
deps: Option<&BTreeMap<u32, (Arc<str>, Arc<str>)>>,
|
||||
decoder: &mut Decoder,
|
||||
verbose: bool,
|
||||
) -> Usually<Option<Arc<Call>>> {
|
||||
let position = decoder.position();
|
||||
let instruction = decoder.decode();
|
||||
let opcodes = &data[position..position+instruction.len()];
|
||||
if Call::matches(&instruction) && !Call::skip(opcodes) {
|
||||
let offset = (position + start) as u32;
|
||||
let offset_rva = pe.offset_to_rva(Offset(offset))?.0;
|
||||
if let Some(target) = Call::target(opcodes, offset_rva) {
|
||||
let (module, method, external) = dep_name(deps, target);
|
||||
if verbose {
|
||||
let external = format!("{}::{}",
|
||||
module.as_ref().map(|x|x.as_ref()).unwrap_or("???"),
|
||||
method.as_ref().map(|x|x.as_ref()).unwrap_or("???"));
|
||||
println!(" ({BOLD}0x{:08x}{RESET} 0x{:08x} {BOLD}{:30}{RESET} 0x{:x} {}",
|
||||
offset, offset_rva, instruction, target, external);
|
||||
}
|
||||
return Ok(Some(Arc::new(Call {
|
||||
offset: offset,
|
||||
source: offset_rva,
|
||||
length: opcodes.len(),
|
||||
target,
|
||||
module,
|
||||
method,
|
||||
})))
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn dep_name (
|
||||
deps: Option<&BTreeMap<u32, (Arc<str>, Arc<str>)>>, target: u32
|
||||
) -> (Option<Arc<str>>, Option<Arc<str>>, Arc<str>) {
|
||||
let module = deps.and_then(|deps|deps.get(&target)).map(|dep|dep.0.clone());
|
||||
let method = deps.and_then(|deps|deps.get(&target)).map(|dep|dep.1.clone());
|
||||
let external = format!("{}::{}",
|
||||
module.as_ref().map(|x|x.as_ref()).unwrap_or("???"),
|
||||
method.as_ref().map(|x|x.as_ref()).unwrap_or("???"));
|
||||
(module, method, external.into())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -409,86 +459,4 @@ impl Call {
|
|||
}
|
||||
None
|
||||
}
|
||||
fn dep_name (deps: Option<&BTreeMap<u32, (Arc<str>, Arc<str>)>>, target: u32)
|
||||
-> (Option<Arc<str>>, Option<Arc<str>>, Arc<str>)
|
||||
{
|
||||
let module = deps.and_then(|deps|deps.get(&target)).map(|dep|dep.0.clone());
|
||||
let method = deps.and_then(|deps|deps.get(&target)).map(|dep|dep.1.clone());
|
||||
let external = format!("{}::{}",
|
||||
module.as_ref().map(|x|x.as_ref()).unwrap_or("???"),
|
||||
method.as_ref().map(|x|x.as_ref()).unwrap_or("???"));
|
||||
(module, method, external.into())
|
||||
}
|
||||
fn calls (
|
||||
name: &Arc<str>,
|
||||
pe: &VecPE,
|
||||
start: usize,
|
||||
data: &[u8],
|
||||
deps: Option<&BTreeMap<u32, (Arc<str>, Arc<str>)>>,
|
||||
calls_by_source: &mut BTreeMap<u32, Arc<Call>>,
|
||||
calls_by_target: &mut BTreeMap<u32, Vec<Arc<Call>>>,
|
||||
verbose: bool,
|
||||
) -> Usually<usize> {
|
||||
let mut decoder = Decoder::with_ip(64, data, 0x1000, 0);
|
||||
let mut calls = 0;
|
||||
while decoder.can_decode() {
|
||||
if let Some(call) = Self::call(name, pe, start, data, deps, &mut decoder, false)? {
|
||||
calls += 1;
|
||||
calls_by_source.insert(call.source, call.clone());
|
||||
if !calls_by_target.contains_key(&call.target) {
|
||||
calls_by_target.insert(call.target, Default::default());
|
||||
}
|
||||
calls_by_target.get_mut(&call.target).unwrap().push(call);
|
||||
}
|
||||
}
|
||||
if verbose {
|
||||
println!(" (call-sites {calls})");
|
||||
for (target, sites) in calls_by_target.iter() {
|
||||
let (_, _, external) = Self::dep_name(deps, *target);
|
||||
println!(" ({:>5}x call 0x{target:08x} {external})", sites.len());
|
||||
//.map(|site|format!("0x{:08x}", site.offset))
|
||||
//.collect::<Vec<_>>());
|
||||
//println!(" (call 0x{target:08x} {external}\n {:?})", sites.iter()
|
||||
//.map(|site|format!("0x{:08x}", site.offset))
|
||||
//.collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
Ok(calls)
|
||||
}
|
||||
fn call (
|
||||
name: &Arc<str>,
|
||||
pe: &VecPE,
|
||||
start: usize,
|
||||
data: &[u8],
|
||||
deps: Option<&BTreeMap<u32, (Arc<str>, Arc<str>)>>,
|
||||
decoder: &mut Decoder,
|
||||
verbose: bool,
|
||||
) -> Usually<Option<Arc<Call>>> {
|
||||
let position = decoder.position();
|
||||
let instruction = decoder.decode();
|
||||
let opcodes = &data[position..position+instruction.len()];
|
||||
if Call::matches(&instruction) && !Call::skip(opcodes) {
|
||||
let offset = (position + start) as u32;
|
||||
let offset_rva = pe.offset_to_rva(Offset(offset))?.0;
|
||||
if let Some(target) = Call::target(opcodes, offset_rva) {
|
||||
let (module, method, external) = Self::dep_name(deps, target);
|
||||
if verbose {
|
||||
let external = format!("{}::{}",
|
||||
module.as_ref().map(|x|x.as_ref()).unwrap_or("???"),
|
||||
method.as_ref().map(|x|x.as_ref()).unwrap_or("???"));
|
||||
println!(" ({BOLD}0x{:08x}{RESET} 0x{:08x} {BOLD}{:30}{RESET} 0x{:x} {}",
|
||||
offset, offset_rva, instruction, target, external);
|
||||
}
|
||||
return Ok(Some(Arc::new(Call {
|
||||
offset: offset,
|
||||
source: offset_rva,
|
||||
length: opcodes.len(),
|
||||
target,
|
||||
module,
|
||||
method,
|
||||
})))
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,116 +1,149 @@
|
|||
use crate::*;
|
||||
impl Vestal {
|
||||
pub fn show_addr_to_import (&self) {
|
||||
for (addr, (dll, export)) in self.addr_to_import.iter() {
|
||||
println!("{BOLD}0x{addr:>08x}{RESET} {dll:>20} {export:<40}");
|
||||
|
||||
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);
|
||||
let instruction = decoder.decode();
|
||||
let opcodes = &self.code[addr..addr+instruction.len()].iter()
|
||||
.map(|x|format!("{x:02x}"))
|
||||
.join(" ");
|
||||
println!("{BOLD}0x{addr:>08x}{RESET} {:20} {DIM}{opcodes}{RESET} {BOLD}{instruction}{RESET} {module:?} {method:?}", &self.name);
|
||||
}
|
||||
pub fn print_hex (&self, addr: usize, n: usize) {
|
||||
let cfg = HexConfig {title: false, width: 16, group: 4, chunk: 1, ..HexConfig::default()};
|
||||
let snap = |x|(x/16)*16;
|
||||
let a = snap(addr - 16*n);
|
||||
let b = addr;
|
||||
let c = snap(addr + 16);
|
||||
let d = snap(c + 16*n);
|
||||
if n > 0 {
|
||||
println!("{DIM}{:?}{RESET}", &self.code[a..b].hex_conf(HexConfig {
|
||||
display_offset: self.code_base as usize + a, ..cfg
|
||||
}));
|
||||
}
|
||||
}
|
||||
pub fn show_vst_entrypoint (&self, path: &PathBuf) {
|
||||
//let exports = self.path_to_exports.get(path).expect("no exports");
|
||||
//for export in exports.iter() {
|
||||
//if export.name_string() == Some("VSTPluginMain".to_string()) {
|
||||
//println!("{export:?}");
|
||||
//println!("{}", export.name_string().unwrap());
|
||||
//let addr = (export.addr() as usize);
|
||||
//println!();
|
||||
//println!();
|
||||
//return Ok(())
|
||||
//}
|
||||
//}
|
||||
//panic!("no main");
|
||||
//println!("{:#?}", &self.addr_to_import);
|
||||
}
|
||||
pub fn show_dll (&self, path: &PathBuf) -> Usually<()> {
|
||||
let dll = self.path_to_pe.get(path).expect("no such library");
|
||||
let ep_rva = dll.get_entrypoint()?;
|
||||
let ep_off = dll.rva_to_offset(ep_rva)?;
|
||||
println!("\n({:p} 0x{:x?} {:x?} {:x?}\n {path:?})",
|
||||
dll.as_ptr(),
|
||||
dll.get_image_base()?,
|
||||
ep_rva,
|
||||
ep_off);
|
||||
Ok(())
|
||||
}
|
||||
pub fn show_calls (&self, path: &PathBuf, verbose: bool) -> Usually<()> {
|
||||
let mut calls = 0;
|
||||
let dll = self.path_to_pe.get(path).expect("no such library");
|
||||
let buf = dll.get_buffer();
|
||||
let section = dll.get_section_by_name(".text")?;
|
||||
let section_ptr = section.pointer_to_raw_data.0 as usize;
|
||||
let section_len = section.size_of_raw_data as usize;
|
||||
let section_data = &buf[section_ptr..section_ptr+section_len];
|
||||
let mut decoder = iced_x86::Decoder::with_ip(64, section_data, 0x1000, 0);
|
||||
while decoder.can_decode() {
|
||||
let position = decoder.position();
|
||||
let instruction = decoder.decode();
|
||||
let opcodes = §ion_data[position..position+instruction.len()];
|
||||
//println!("0x{position:08x} {opcodes:32} {instruction}");
|
||||
if (instruction.flow_control() == iced_x86::FlowControl::IndirectBranch
|
||||
|| instruction.flow_control() == iced_x86::FlowControl::IndirectCall)
|
||||
&& instruction.op0_kind() == iced_x86::OpKind::Memory {
|
||||
match opcodes[0] {
|
||||
0xff => match opcodes[1] {
|
||||
0x10 | 0x12 | 0x13 |
|
||||
0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 |
|
||||
0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => continue,
|
||||
_ => {},
|
||||
},
|
||||
0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] {
|
||||
0xff => continue,
|
||||
_ => {},
|
||||
},
|
||||
0x48 => match opcodes[2] {
|
||||
0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => continue,
|
||||
_ => {},
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
let offset = (position + section_ptr) as u32;
|
||||
let offset_rva = dll.offset_to_rva(Offset(offset))?.0;
|
||||
let call_target = match opcodes[0] {
|
||||
0xff => match opcodes[1] {
|
||||
0x15 | 0x25 =>
|
||||
offset_rva + opcodes.len() as u32 + u32::from_le_bytes([
|
||||
opcodes[2],
|
||||
opcodes[3],
|
||||
opcodes[4],
|
||||
opcodes[5]
|
||||
]),
|
||||
_ => 0x0
|
||||
},
|
||||
0x48 => match opcodes[1] {
|
||||
0xff => match opcodes[2] {
|
||||
0x15 | 0x25 =>
|
||||
offset_rva + opcodes.len() as u32 + u32::from_le_bytes([
|
||||
opcodes[3],
|
||||
opcodes[4],
|
||||
opcodes[5],
|
||||
opcodes[6]
|
||||
]),
|
||||
_ => 0x0
|
||||
},
|
||||
_ => 0x0
|
||||
}
|
||||
_ => 0x0
|
||||
};
|
||||
let unknown = (String::from("unknown"), String::from("unknown"));
|
||||
let external = format!("{}::{}",
|
||||
self.addr_to_import.get(&call_target).unwrap_or(&unknown).0,
|
||||
self.addr_to_import.get(&call_target).unwrap_or(&unknown).1);
|
||||
let dependent = path.file_name().unwrap();
|
||||
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,
|
||||
);
|
||||
}
|
||||
calls += 1;
|
||||
}
|
||||
println!("{BOLD}{:?}{RESET}", &self.code[b..c].hex_conf(HexConfig {
|
||||
display_offset: self.code_base as usize + b, ..cfg
|
||||
}));
|
||||
if n > 0 {
|
||||
println!("{DIM}{:?}{RESET}", &self.code[c..d].hex_conf(HexConfig {
|
||||
display_offset: self.code_base as usize + c, ..cfg
|
||||
}));
|
||||
}
|
||||
println!(" (calls {calls})");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//impl Vestal {
|
||||
//pub fn show_addr_to_import (&self) {
|
||||
//for (addr, (dll, export)) in self.addr_to_import.iter() {
|
||||
//println!("{BOLD}0x{addr:>08x}{RESET} {dll:>20} {export:<40}");
|
||||
//}
|
||||
//}
|
||||
//pub fn show_vst_entrypoint (&self, path: &PathBuf) {
|
||||
////let exports = self.path_to_exports.get(path).expect("no exports");
|
||||
////for export in exports.iter() {
|
||||
////if export.name_string() == Some("VSTPluginMain".to_string()) {
|
||||
////println!("{export:?}");
|
||||
////println!("{}", export.name_string().unwrap());
|
||||
////let addr = (export.addr() as usize);
|
||||
////println!();
|
||||
////println!();
|
||||
////return Ok(())
|
||||
////}
|
||||
////}
|
||||
////panic!("no main");
|
||||
////println!("{:#?}", &self.addr_to_import);
|
||||
//}
|
||||
//pub fn show_dll (&self, path: &PathBuf) -> Usually<()> {
|
||||
//let dll = self.path_to_pe.get(path).expect("no such library");
|
||||
//let ep_rva = dll.get_entrypoint()?;
|
||||
//let ep_off = dll.rva_to_offset(ep_rva)?;
|
||||
//println!("\n({:p} 0x{:x?} {:x?} {:x?}\n {path:?})",
|
||||
//dll.as_ptr(),
|
||||
//dll.get_image_base()?,
|
||||
//ep_rva,
|
||||
//ep_off);
|
||||
//Ok(())
|
||||
//}
|
||||
//pub fn show_calls (&self, path: &PathBuf, verbose: bool) -> Usually<()> {
|
||||
//let mut calls = 0;
|
||||
//let dll = self.path_to_pe.get(path).expect("no such library");
|
||||
//let buf = dll.get_buffer();
|
||||
//let section = dll.get_section_by_name(".text")?;
|
||||
//let section_ptr = section.pointer_to_raw_data.0 as usize;
|
||||
//let section_len = section.size_of_raw_data as usize;
|
||||
//let section_data = &buf[section_ptr..section_ptr+section_len];
|
||||
//let mut decoder = iced_x86::Decoder::with_ip(64, section_data, 0x1000, 0);
|
||||
//while decoder.can_decode() {
|
||||
//let position = decoder.position();
|
||||
//let instruction = decoder.decode();
|
||||
//let opcodes = §ion_data[position..position+instruction.len()];
|
||||
////println!("0x{position:08x} {opcodes:32} {instruction}");
|
||||
//if (instruction.flow_control() == iced_x86::FlowControl::IndirectBranch
|
||||
//|| instruction.flow_control() == iced_x86::FlowControl::IndirectCall)
|
||||
//&& instruction.op0_kind() == iced_x86::OpKind::Memory {
|
||||
//match opcodes[0] {
|
||||
//0xff => match opcodes[1] {
|
||||
//0x10 | 0x12 | 0x13 |
|
||||
//0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 |
|
||||
//0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => continue,
|
||||
//_ => {},
|
||||
//},
|
||||
//0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] {
|
||||
//0xff => continue,
|
||||
//_ => {},
|
||||
//},
|
||||
//0x48 => match opcodes[2] {
|
||||
//0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => continue,
|
||||
//_ => {},
|
||||
//},
|
||||
//_ => {}
|
||||
//}
|
||||
//let offset = (position + section_ptr) as u32;
|
||||
//let offset_rva = dll.offset_to_rva(Offset(offset))?.0;
|
||||
//let call_target = match opcodes[0] {
|
||||
//0xff => match opcodes[1] {
|
||||
//0x15 | 0x25 =>
|
||||
//offset_rva + opcodes.len() as u32 + u32::from_le_bytes([
|
||||
//opcodes[2],
|
||||
//opcodes[3],
|
||||
//opcodes[4],
|
||||
//opcodes[5]
|
||||
//]),
|
||||
//_ => 0x0
|
||||
//},
|
||||
//0x48 => match opcodes[1] {
|
||||
//0xff => match opcodes[2] {
|
||||
//0x15 | 0x25 =>
|
||||
//offset_rva + opcodes.len() as u32 + u32::from_le_bytes([
|
||||
//opcodes[3],
|
||||
//opcodes[4],
|
||||
//opcodes[5],
|
||||
//opcodes[6]
|
||||
//]),
|
||||
//_ => 0x0
|
||||
//},
|
||||
//_ => 0x0
|
||||
//}
|
||||
//_ => 0x0
|
||||
//};
|
||||
//let unknown = (String::from("unknown"), String::from("unknown"));
|
||||
//let external = format!("{}::{}",
|
||||
//self.addr_to_import.get(&call_target).unwrap_or(&unknown).0,
|
||||
//self.addr_to_import.get(&call_target).unwrap_or(&unknown).1);
|
||||
//let dependent = path.file_name().unwrap();
|
||||
//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,
|
||||
//);
|
||||
//}
|
||||
//calls += 1;
|
||||
//}
|
||||
//}
|
||||
//println!(" (calls {calls})");
|
||||
//Ok(())
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue