diff --git a/crates/vestal/src/main.rs b/crates/vestal/src/main.rs index a4faaac..2ca7700 100644 --- a/crates/vestal/src/main.rs +++ b/crates/vestal/src/main.rs @@ -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, BTreeMap, u32>>, - deps_by_address: &mut BTreeMap, Arc)>, - 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 = 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 = 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, ThunkData>> { - Ok(ImageExportDirectory::parse(pe)? - .get_export_map(pe)? - .into_iter() - .map(|(k, v)|(k.into(), v)) - .collect()) - } fn parse_call (&self, call: &Arc) -> Option { 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>, method: Option<&Arc>) { - 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, BTreeMap, u32>>, + deps_by_address: &mut BTreeMap, Arc)>, + 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 = 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 = 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, 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>, + calls_by_target: &mut BTreeMap>>, + deps: Option<&BTreeMap, Arc)>>, + name: &Arc, + pe: &VecPE, + start: usize, + data: &[u8], + verbose: bool, +) -> Usually { + 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::>()); + //println!(" (call 0x{target:08x} {external}\n {:?})", sites.iter() + //.map(|site|format!("0x{:08x}", site.offset)) + //.collect::>()); + } + } + Ok(calls) +} + +fn collect_call ( + name: &Arc, + pe: &VecPE, + start: usize, + data: &[u8], + deps: Option<&BTreeMap, Arc)>>, + decoder: &mut Decoder, + verbose: bool, +) -> Usually>> { + 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, Arc)>>, target: u32 +) -> (Option>, Option>, Arc) { + 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, Arc)>>, target: u32) - -> (Option>, Option>, Arc) - { - 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, - pe: &VecPE, - start: usize, - data: &[u8], - deps: Option<&BTreeMap, Arc)>>, - calls_by_source: &mut BTreeMap>, - calls_by_target: &mut BTreeMap>>, - verbose: bool, - ) -> Usually { - 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::>()); - //println!(" (call 0x{target:08x} {external}\n {:?})", sites.iter() - //.map(|site|format!("0x{:08x}", site.offset)) - //.collect::>()); - } - } - Ok(calls) - } - fn call ( - name: &Arc, - pe: &VecPE, - start: usize, - data: &[u8], - deps: Option<&BTreeMap, Arc)>>, - decoder: &mut Decoder, - verbose: bool, - ) -> Usually>> { - 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) - } } diff --git a/crates/vestal/src/show.rs b/crates/vestal/src/show.rs index 46c3717..3bc0077 100644 --- a/crates/vestal/src/show.rs +++ b/crates/vestal/src/show.rs @@ -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>, method: Option<&Arc>) { + 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::>().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::>().join(" "), + //instruction, + //call_target, + //); + //} + //calls += 1; + //} + //} + //println!(" (calls {calls})"); + //Ok(()) + //} +//}