flatten and cleanup

This commit is contained in:
🪞👃🪞 2025-02-22 17:24:34 +02:00
parent 459f6c643c
commit ed01876426
2 changed files with 311 additions and 310 deletions

View file

@ -2,7 +2,7 @@
mod util; mod util;
mod bang; mod bang;
//mod load; //mod load;
//mod show; mod show;
//mod link; //mod link;
pub(crate) use self::util::*; pub(crate) use self::util::*;
@ -29,16 +29,6 @@ fn main () -> Usually<()> {
let name = rebuilder.load(&path, true)?; let name = rebuilder.load(&path, true)?;
let main = rebuilder.dlls.get(&name).unwrap(); let main = rebuilder.dlls.get(&name).unwrap();
rebuilder.resolve_calls(&main, true, true)?; 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(()) Ok(())
} }
@ -128,7 +118,7 @@ impl Rebuilder {
dll.print_hex(addr, 1); dll.print_hex(addr, 1);
if recurse { if recurse {
let mut decoder = Decoder::with_ip( let mut decoder = Decoder::with_ip(
64, &dll.code[addr..], 0, DecoderOptions::NONE 64, &dll.code[addr..], 0x1000, DecoderOptions::NONE
); );
while decoder.can_decode() { while decoder.can_decode() {
let position = decoder.position(); let position = decoder.position();
@ -200,21 +190,21 @@ impl Dll {
let mut calls_by_target = Default::default(); let mut calls_by_target = Default::default();
let mut deps_by_library = Default::default(); let mut deps_by_library = Default::default();
let mut deps_by_address = Default::default(); let mut deps_by_address = Default::default();
let exports = Self::exports(&pe).unwrap_or_default(); let exports = collect_exports(&pe).unwrap_or_default();
let (modules_count, methods_count) = Self::deps( let (modules_count, methods_count) = collect_deps(
&pe,
&mut deps_by_library, &mut deps_by_library,
&mut deps_by_address, &mut deps_by_address,
&pe,
false false
)?; )?;
let calls = Call::calls( let calls = collect_calls(
&mut calls_by_source,
&mut calls_by_target,
Some(&deps_by_address),
&name, &name,
&pe, &pe,
start, start,
text, text,
Some(&deps_by_address),
&mut calls_by_source,
&mut calls_by_target,
false false
)?; )?;
Ok(Self { Ok(Self {
@ -234,109 +224,169 @@ impl Dll {
pe, 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> { 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) 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(); fn collect_deps (
let opcodes = &self.code[addr..addr+instruction.len()].iter() deps_by_library: &mut BTreeMap<Arc<str>, BTreeMap<Arc<str>, u32>>,
.map(|x|format!("{x:02x}")) deps_by_address: &mut BTreeMap<u32, (Arc<str>, Arc<str>)>,
.join(" "); pe: &VecPE,
println!("{BOLD}0x{addr:>08x}{RESET} {:20} {DIM}{opcodes}{RESET} {BOLD}{instruction}{RESET} {module:?} {method:?}", &self.name); verbose: bool,
} ) -> Usually<(usize, usize)> {
fn print_hex (&self, addr: usize, n: usize) { let directory = ImportDirectory::parse(pe)?;
let cfg = HexConfig {title: false, width: 16, group: 4, chunk: 1, ..HexConfig::default()}; let mut modules = 0;
let snap = |x|(x/16)*16; let mut methods = 0;
let a = snap(addr - 16*n); for descriptor in directory.descriptors {
let b = addr; let module_name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
let c = snap(addr + 16); let imp = descriptor.get_imports(pe)?;
let d = snap(c + 16*n); let iat = descriptor.get_first_thunk(pe)?;
if n > 0 { let ilt = descriptor.get_original_first_thunk(pe)?;
println!("{DIM}{:?}{RESET}", &self.code[a..b].hex_conf(HexConfig { let lut = descriptor.get_lookup_thunks(pe)?;
display_offset: self.code_base as usize + a, ..cfg let unwrap_thunk = |thunk: &Thunk, name|match thunk {
})); Thunk::Thunk32(t) => panic!("32 bit {name}"),
} Thunk::Thunk64(t) => t.0
println!("{BOLD}{:?}{RESET}", &self.code[b..c].hex_conf(HexConfig { };
display_offset: self.code_base as usize + b, ..cfg for (index, (import, thunk, orig, lookup)) in izip!(
})); imp,
if n > 0 { iat.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "IAT thunk"))),
println!("{DIM}{:?}{RESET}", &self.code[c..d].hex_conf(HexConfig { ilt.iter().map(|thunk|format!("0x{:08x}", unwrap_thunk(thunk, "ILT (orig) thunk"))),
display_offset: self.code_base as usize + c, ..cfg 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)] #[derive(Debug)]
@ -409,86 +459,4 @@ impl Call {
} }
None 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)
}
} }

View file

@ -1,116 +1,149 @@
use crate::*; use crate::*;
impl Vestal {
pub fn show_addr_to_import (&self) { impl Dll {
for (addr, (dll, export)) in self.addr_to_import.iter() { pub fn print_call (&self, addr: usize, module: Option<&Arc<str>>, method: Option<&Arc<str>>) {
println!("{BOLD}0x{addr:>08x}{RESET} {dll:>20} {export:<40}"); 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
}));
} }
} println!("{BOLD}{:?}{RESET}", &self.code[b..c].hex_conf(HexConfig {
pub fn show_vst_entrypoint (&self, path: &PathBuf) { display_offset: self.code_base as usize + b, ..cfg
//let exports = self.path_to_exports.get(path).expect("no exports"); }));
//for export in exports.iter() { if n > 0 {
//if export.name_string() == Some("VSTPluginMain".to_string()) { println!("{DIM}{:?}{RESET}", &self.code[c..d].hex_conf(HexConfig {
//println!("{export:?}"); display_offset: self.code_base as usize + c, ..cfg
//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 = &section_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(())
} }
} }
//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 = &section_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(())
//}
//}