mirror of
https://github.com/Noratrieb/portability.git
synced 2026-01-14 15:55:04 +01:00
emulation
This commit is contained in:
parent
e8ba83c443
commit
8c23716f8f
3 changed files with 250 additions and 156 deletions
186
src/emulated.rs
186
src/emulated.rs
|
|
@ -1,4 +1,9 @@
|
|||
#![allow(non_snake_case)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
mod base_defs {
|
||||
use std::{ffi::CStr, fmt::Debug};
|
||||
|
||||
pub(crate) type HANDLE = usize;
|
||||
|
||||
#[repr(transparent)]
|
||||
|
|
@ -23,6 +28,25 @@ mod base_defs {
|
|||
f.write_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct LPCSTR(pub *const std::ffi::c_char);
|
||||
impl LPCSTR {
|
||||
pub(crate) fn as_cstr(&self) -> &CStr {
|
||||
unsafe { CStr::from_ptr(self.0) }
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for LPCSTR {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Debug::fmt(self.as_cstr(), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(super) struct CRITICAL_SECTION {
|
||||
pub(super) mutex: std::sync::atomic::AtomicU64,
|
||||
pub(super) pad: [u8; 40 - 8],
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_emulation_entry {
|
||||
|
|
@ -56,6 +80,16 @@ define_emulation_entry!(
|
|||
ws2_32,
|
||||
);
|
||||
|
||||
macro_rules! make_body {
|
||||
($name:ident $($argname:ident),* @ delegate($dll:ident)) => {
|
||||
crate::emulated::$dll::$name($($argname),*)
|
||||
};
|
||||
($name:ident $($argname:ident),* @ $($body:tt)*) => {
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { $($body)* }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! emulate {
|
||||
($dllname:literal, mod $modname:ident {
|
||||
$(
|
||||
|
|
@ -79,7 +113,7 @@ macro_rules! emulate {
|
|||
if function_name == stringify!($name) {
|
||||
unsafe {
|
||||
// NOTE: The ABI string is a lie.....
|
||||
return Some(std::mem::transmute($name::trampoline as unsafe extern "C" fn($($argty),*)));
|
||||
return Some(std::mem::transmute($name as unsafe extern "win64" fn($($argty),*) $(-> $ret)?));
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
|
@ -87,43 +121,13 @@ macro_rules! emulate {
|
|||
None
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::emulated::base_defs::*;
|
||||
|
||||
$(
|
||||
#[allow(non_snake_case)]
|
||||
mod $name {
|
||||
#[allow(unused_imports)]
|
||||
use crate::emulated::base_defs::*;
|
||||
|
||||
// https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
pub(super) unsafe extern "C" fn trampoline($($argname: $argty)*) {
|
||||
unsafe { inner($($argname),*) }
|
||||
}
|
||||
} else if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
|
||||
#[naked_function::naked]
|
||||
#[export_name = concat!("portability_callconv_trampoline_", stringify!($modname), "__", stringify!($name))]
|
||||
pub(super) unsafe extern "C" fn trampoline($($argname: $argty),*) {
|
||||
// Map Windows arguments to System V arguments.
|
||||
// For now we only support 4 integer arguments.
|
||||
asm!(
|
||||
"mov rdi, rcx", // arg 1
|
||||
"mov rsi, rdx", // arg 2
|
||||
"mov rdx, r8", // arg 3
|
||||
"mov rcx, r9", // arg 4
|
||||
"jmp {}",
|
||||
sym inner,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
compile_error!("unsupported architecture or operating system");
|
||||
}
|
||||
}
|
||||
|
||||
$(#[$attr])*
|
||||
unsafe extern "C" fn inner($($argname: $argty),*) $(-> $ret)? {
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { $($body)* }
|
||||
}
|
||||
$(#[$attr])*
|
||||
pub(super) unsafe extern "win64" fn $name($($argname: $argty),*) $(-> $ret)? {
|
||||
make_body! { $name $($argname),* @ $($body)* }
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
|
@ -165,9 +169,17 @@ emulate!(
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
emulate!(
|
||||
"api-ms-win-core-synch-l1-2-0.dll",
|
||||
mod api_ms_win_core_synch_l1_2_0 {
|
||||
fn InitializeCriticalSectionEx(
|
||||
lpCriticalSection: *mut (),
|
||||
dwSpinCount: u32,
|
||||
flags: u32,
|
||||
) -> bool {
|
||||
delegate(kernel32)
|
||||
}
|
||||
fn WaitOnAddress() {
|
||||
todo!("WaitOnAddress")
|
||||
}
|
||||
|
|
@ -293,9 +305,8 @@ emulate!(
|
|||
fn DecodePointer() {
|
||||
todo!("DecodePointer")
|
||||
}
|
||||
fn DeleteCriticalSection() {
|
||||
todo!("DeleteCriticalSection")
|
||||
}
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-deletecriticalsection>
|
||||
fn DeleteCriticalSection(_lpCriticalSection: *mut ()) {}
|
||||
fn DeleteFiber() {
|
||||
todo!("DeleteFiber")
|
||||
}
|
||||
|
|
@ -314,8 +325,19 @@ emulate!(
|
|||
fn EncodePointer() {
|
||||
todo!("EncodePointer")
|
||||
}
|
||||
fn EnterCriticalSection() {
|
||||
todo!("EnterCriticalSection")
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-entercriticalsection>
|
||||
fn EnterCriticalSection(lpCriticalSection: *mut CRITICAL_SECTION) {
|
||||
// a shitty spinlock
|
||||
while (&*lpCriticalSection)
|
||||
.mutex
|
||||
.compare_exchange_weak(
|
||||
0,
|
||||
1,
|
||||
std::sync::atomic::Ordering::Acquire,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
)
|
||||
.is_err()
|
||||
{}
|
||||
}
|
||||
fn EnumSystemLocalesW() {
|
||||
todo!("EnumSystemLocalesW")
|
||||
|
|
@ -335,8 +357,10 @@ emulate!(
|
|||
fn FindNextFileW() {
|
||||
todo!("FindNextFileW")
|
||||
}
|
||||
fn FlsAlloc() {
|
||||
todo!("FlsAlloc")
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/fibersapi/nf-fibersapi-flsalloc>
|
||||
fn FlsAlloc(_callback: extern "win64" fn()) -> u32 {
|
||||
const FLS_OUT_OF_INDEXES: u32 = -1_i32 as u32;
|
||||
FLS_OUT_OF_INDEXES
|
||||
}
|
||||
fn FlsFree() {
|
||||
todo!("FlsFree")
|
||||
|
|
@ -448,8 +472,8 @@ emulate!(
|
|||
fn GetFullPathNameW() {
|
||||
todo!("GetFullPathNameW")
|
||||
}
|
||||
fn GetLastError() {
|
||||
todo!("GetLastError")
|
||||
fn GetLastError() -> u32 {
|
||||
1
|
||||
}
|
||||
fn GetLocaleInfoEx() {
|
||||
todo!("GetLocaleInfoEx")
|
||||
|
|
@ -469,8 +493,9 @@ emulate!(
|
|||
fn GetModuleHandleExW() {
|
||||
todo!("GetModuleHandleExW")
|
||||
}
|
||||
fn GetModuleHandleW() {
|
||||
todo!("GetModuleHandleW")
|
||||
fn GetModuleHandleW() -> u64 {
|
||||
tracing::error!("TODO GetModuleHandleW");
|
||||
0
|
||||
}
|
||||
fn GetNativeSystemInfo() {
|
||||
todo!("GetNativeSystemInfo")
|
||||
|
|
@ -482,8 +507,17 @@ emulate!(
|
|||
todo!("GetOverlappedResult")
|
||||
}
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress>
|
||||
fn GetProcAddress(hModule: u64, lpProcName: LPCWSTR) {
|
||||
todo!("GetProcAddress: {lpProcName:?}")
|
||||
fn GetProcAddress(hModule: u64, lpProcName: LPCSTR) -> usize {
|
||||
let dll = crate::GLOBAL_STATE
|
||||
.state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.hmodule_to_dll
|
||||
.get(&hModule)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
// TODO: error handling...
|
||||
crate::va_for_dll_export_by_name(&dll, lpProcName.as_cstr(), 0)
|
||||
}
|
||||
fn GetProcessHeap() {
|
||||
todo!("GetProcessHeap")
|
||||
|
|
@ -578,8 +612,19 @@ emulate!(
|
|||
fn InitializeCriticalSectionAndSpinCount() {
|
||||
todo!("InitializeCriticalSectionAndSpinCount")
|
||||
}
|
||||
fn InitializeCriticalSectionEx() {
|
||||
todo!("InitializeCriticalSectionEx")
|
||||
fn InitializeCriticalSectionEx(
|
||||
lpCriticalSection: *mut (),
|
||||
_dwSpinCount: u32,
|
||||
_flags: u32,
|
||||
) -> bool {
|
||||
lpCriticalSection
|
||||
.cast::<CRITICAL_SECTION>()
|
||||
.write(CRITICAL_SECTION {
|
||||
mutex: Default::default(),
|
||||
pad: Default::default(),
|
||||
});
|
||||
const _: () = assert!(size_of::<CRITICAL_SECTION>() == 40);
|
||||
true
|
||||
}
|
||||
fn InitializeProcThreadAttributeList() {
|
||||
todo!("InitializeProcThreadAttributeList")
|
||||
|
|
@ -590,11 +635,13 @@ emulate!(
|
|||
fn InterlockedFlushSList() {
|
||||
todo!("InterlockedFlushSList")
|
||||
}
|
||||
fn IsDebuggerPresent() {
|
||||
todo!("IsDebuggerPresent")
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-isdebuggerpresent>
|
||||
fn IsDebuggerPresent() -> bool {
|
||||
false
|
||||
}
|
||||
fn IsProcessorFeaturePresent() {
|
||||
todo!("IsProcessorFeaturePresent")
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent>
|
||||
fn IsProcessorFeaturePresent(_ProcessorFeature: u32) -> bool {
|
||||
false
|
||||
}
|
||||
fn IsThreadAFiber() {
|
||||
todo!("IsThreadAFiber")
|
||||
|
|
@ -633,8 +680,8 @@ emulate!(
|
|||
&crate::GLOBAL_STATE.executable_path(),
|
||||
);
|
||||
match result {
|
||||
crate::LoadedDll::Emulated => 1,
|
||||
crate::LoadedDll::Real(img, _, _) => img.base as u64,
|
||||
Some(result) => result.hmodule(),
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
fn LoadLibraryW() {
|
||||
|
|
@ -762,8 +809,9 @@ emulate!(
|
|||
fn SetThreadStackGuarantee() {
|
||||
todo!("SetThreadStackGuarantee")
|
||||
}
|
||||
fn SetUnhandledExceptionFilter() {
|
||||
todo!("SetUnhandledExceptionFilter")
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setunhandledexceptionfilter>
|
||||
fn SetUnhandledExceptionFilter(_lpTopLevelExceptionFilter: *mut ()) -> *mut () {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
fn SetWaitableTimer() {
|
||||
todo!("SetWaitableTimer")
|
||||
|
|
@ -804,8 +852,10 @@ emulate!(
|
|||
fn TryAcquireSRWLockExclusive() {
|
||||
todo!("TryAcquireSRWLockExclusive")
|
||||
}
|
||||
fn UnhandledExceptionFilter() {
|
||||
todo!("UnhandledExceptionFilter")
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-unhandledexceptionfilter>
|
||||
fn UnhandledExceptionFilter(_ExceptionInfo: *const ()) -> u64 {
|
||||
const EXCEPTION_CONTINUE_SEARCH: u64 = 0x0;
|
||||
EXCEPTION_CONTINUE_SEARCH
|
||||
}
|
||||
fn UnlockFile() {
|
||||
todo!("UnlockFile")
|
||||
|
|
@ -866,14 +916,20 @@ emulate!(
|
|||
fn NtWriteFile() {
|
||||
todo!("NtWriteFile")
|
||||
}
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlcapturecontext>
|
||||
fn RtlCaptureContext() {
|
||||
todo!("RtlCaptureContext")
|
||||
tracing::error!("TODO: RtlCaptureContext - looks like someone feels like crashing...")
|
||||
}
|
||||
fn RtlGetLastNtStatus() {
|
||||
todo!("RtlGetLastNtStatus")
|
||||
}
|
||||
fn RtlLookupFunctionEntry() {
|
||||
todo!("RtlLookupFunctionEntry")
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtllookupfunctionentry>
|
||||
fn RtlLookupFunctionEntry(
|
||||
_ControlPc: u64,
|
||||
_ImageBase: *mut (),
|
||||
_HistoryTable: *mut (),
|
||||
) -> *const () {
|
||||
std::ptr::null()
|
||||
}
|
||||
fn RtlNtStatusToDosError() {
|
||||
todo!("RtlNtStatusToDosError")
|
||||
|
|
|
|||
196
src/lib.rs
196
src/lib.rs
|
|
@ -2,11 +2,15 @@ mod emulated;
|
|||
mod sys;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::{CStr, CString},
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
path::{Path, PathBuf},
|
||||
sync::Mutex,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
LazyLock, Mutex,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
|
|
@ -252,7 +256,9 @@ pub fn execute(pe: &[u8], executable_path: &Path) {
|
|||
tracing::debug!("YOLO to {:#x}", entrypoint);
|
||||
|
||||
unsafe {
|
||||
let result = sys::call_entrypoint_via_stdcall(entrypoint);
|
||||
let entrypoint =
|
||||
std::mem::transmute::<usize, unsafe extern "win64" fn() -> u32>(entrypoint);
|
||||
let result = entrypoint();
|
||||
tracing::info!("result: {result}");
|
||||
};
|
||||
}
|
||||
|
|
@ -280,29 +286,59 @@ impl<'pe> DerefMut for Image<'pe> {
|
|||
|
||||
#[derive(Clone)]
|
||||
enum LoadedDll {
|
||||
Emulated,
|
||||
Real(Image<'static>, ExportDirectoryTable, Vec<CString>),
|
||||
Emulated {
|
||||
name: String,
|
||||
hmodule: u64,
|
||||
},
|
||||
Real {
|
||||
name: String,
|
||||
img: Image<'static>,
|
||||
edt: ExportDirectoryTable,
|
||||
export_names: Vec<CString>,
|
||||
},
|
||||
}
|
||||
|
||||
impl LoadedDll {
|
||||
fn hmodule(&self) -> u64 {
|
||||
match self {
|
||||
Self::Emulated { hmodule, .. } => *hmodule,
|
||||
Self::Real { img, .. } => img.base as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TheGlobalState {
|
||||
loaded_libraries: Vec<(String, LoadedDll)>,
|
||||
executable_path: Option<PathBuf>,
|
||||
hmodule_to_dll: HashMap<u64, LoadedDll>,
|
||||
next_emulated_hmodule_idx: AtomicU64,
|
||||
}
|
||||
|
||||
struct GlobalStateWrapper {
|
||||
state: Mutex<TheGlobalState>,
|
||||
state: std::sync::LazyLock<Mutex<TheGlobalState>>,
|
||||
}
|
||||
|
||||
impl GlobalStateWrapper {
|
||||
fn executable_path(&self) -> PathBuf {
|
||||
self.state.lock().unwrap().executable_path.clone().unwrap()
|
||||
}
|
||||
fn get_emulated_hmodule_idx(&self) -> u64 {
|
||||
self.state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.next_emulated_hmodule_idx
|
||||
.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
static GLOBAL_STATE: GlobalStateWrapper = GlobalStateWrapper {
|
||||
state: Mutex::new(TheGlobalState {
|
||||
loaded_libraries: Vec::new(),
|
||||
executable_path: None,
|
||||
state: LazyLock::new(|| {
|
||||
Mutex::new(TheGlobalState {
|
||||
loaded_libraries: Vec::new(),
|
||||
executable_path: None,
|
||||
hmodule_to_dll: HashMap::new(),
|
||||
next_emulated_hmodule_idx: AtomicU64::new(1),
|
||||
})
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -465,7 +501,8 @@ fn load_inner<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image
|
|||
break;
|
||||
}
|
||||
|
||||
let dll = load_dll(dll_name, executable_path);
|
||||
let dll = load_dll(dll_name, executable_path)
|
||||
.unwrap_or_else(|| panic!("could not find dll {dll_name}"));
|
||||
|
||||
let import_lookups = bytemuck::cast_slice::<u8, u64>(
|
||||
&image[import_directory.import_address_table_rva as usize..],
|
||||
|
|
@ -477,36 +514,21 @@ fn load_inner<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image
|
|||
break;
|
||||
}
|
||||
|
||||
fn compute_export_rva(
|
||||
export_directory_table: &ExportDirectoryTable,
|
||||
unbiased_ordinal: usize,
|
||||
img: &Image<'_>,
|
||||
) -> usize {
|
||||
let eat_addr_rva = export_directory_table.export_address_table_rva as usize
|
||||
+ (unbiased_ordinal * 4);
|
||||
let export_rva = u32::from_ne_bytes(img[eat_addr_rva..][..4].try_into().unwrap());
|
||||
|
||||
if (img.opt_header.export_table.rva
|
||||
..(img.opt_header.export_table.rva + img.opt_header.export_table.size))
|
||||
.contains(&export_rva)
|
||||
{
|
||||
todo!("symbol forwarding")
|
||||
}
|
||||
|
||||
export_rva as usize
|
||||
}
|
||||
|
||||
let ordinal_name_flag = import_lookup >> 63;
|
||||
let resolved_va = if ordinal_name_flag == 1 {
|
||||
let ordinal_number = import_lookup & 0xFFFF;
|
||||
tracing::debug!("import by ordinal: {ordinal_number}");
|
||||
|
||||
match &dll {
|
||||
LoadedDll::Emulated => {
|
||||
LoadedDll::Emulated { .. } => {
|
||||
tracing::error!("unsupported: emulated import via ordinal for {dll_name}. resolving them to 0");
|
||||
0
|
||||
}
|
||||
LoadedDll::Real(img, export_directory_table, _) => {
|
||||
LoadedDll::Real {
|
||||
img,
|
||||
edt: export_directory_table,
|
||||
..
|
||||
} => {
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-ordinal-table
|
||||
let unbiased_ordinal =
|
||||
ordinal_number as usize - export_directory_table.ordinal_base as usize;
|
||||
|
|
@ -528,37 +550,7 @@ fn load_inner<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image
|
|||
CStr::from_bytes_until_nul(&image[hint_name_table_rva as usize + 2..]).unwrap();
|
||||
tracing::debug!("import by name: hint={hint} name={func_name:?}");
|
||||
|
||||
match &dll {
|
||||
LoadedDll::Emulated => emulated::emulate(dll_name, func_name.to_str().unwrap())
|
||||
.unwrap_or_else(|| {
|
||||
panic!("could not find function {func_name:?} in dll {dll_name:?}");
|
||||
}),
|
||||
LoadedDll::Real(img, export_directory_table, names) => {
|
||||
let idx =
|
||||
if names.get(hint as usize) == Some(&func_name.to_owned()) {
|
||||
hint as usize
|
||||
} else {
|
||||
names.binary_search(&func_name.to_owned()).unwrap_or_else(|_| {
|
||||
panic!("could not find function {func_name:?} in dll {dll_name}")
|
||||
})
|
||||
};
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-ordinal-table
|
||||
let ordinal_table = bytemuck::cast_slice::<u8, u16>(
|
||||
&img[export_directory_table.ordinal_table_rva as usize..]
|
||||
[..2 * export_directory_table.number_of_name_pointers as usize],
|
||||
);
|
||||
let unbiased_ordinal = ordinal_table[idx];
|
||||
|
||||
let export_rva = compute_export_rva(
|
||||
export_directory_table,
|
||||
unbiased_ordinal as usize,
|
||||
img,
|
||||
);
|
||||
|
||||
img.base + export_rva as usize
|
||||
}
|
||||
}
|
||||
va_for_dll_export_by_name(&dll, func_name, hint as usize)
|
||||
};
|
||||
|
||||
assert_eq!(size_of::<usize>(), size_of::<u64>());
|
||||
|
|
@ -597,7 +589,63 @@ fn load_inner<'pe>(pe: &'pe [u8], executable_path: &Path, is_dll: bool) -> Image
|
|||
image
|
||||
}
|
||||
|
||||
fn load_dll(dll_name: &str, executable_path: &Path) -> LoadedDll {
|
||||
fn va_for_dll_export_by_name(dll: &LoadedDll, func_name: &CStr, hint: usize) -> usize {
|
||||
match &dll {
|
||||
LoadedDll::Emulated { name, .. } => emulated::emulate(name, func_name.to_str().unwrap())
|
||||
.unwrap_or_else(|| {
|
||||
panic!("could not find function {func_name:?} in dll {name:?}");
|
||||
}),
|
||||
LoadedDll::Real {
|
||||
name,
|
||||
img,
|
||||
edt: export_directory_table,
|
||||
export_names: names,
|
||||
} => {
|
||||
let idx = if names.get(hint) == Some(&func_name.to_owned()) {
|
||||
hint as usize
|
||||
} else {
|
||||
names
|
||||
.binary_search(&func_name.to_owned())
|
||||
.unwrap_or_else(|_| {
|
||||
panic!("could not find function {func_name:?} in dll {name}")
|
||||
})
|
||||
};
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#export-ordinal-table
|
||||
let ordinal_table = bytemuck::cast_slice::<u8, u16>(
|
||||
&img[export_directory_table.ordinal_table_rva as usize..]
|
||||
[..2 * export_directory_table.number_of_name_pointers as usize],
|
||||
);
|
||||
let unbiased_ordinal = ordinal_table[idx];
|
||||
|
||||
let export_rva =
|
||||
compute_export_rva(export_directory_table, unbiased_ordinal as usize, img);
|
||||
|
||||
img.base + export_rva as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_export_rva(
|
||||
export_directory_table: &ExportDirectoryTable,
|
||||
unbiased_ordinal: usize,
|
||||
img: &Image<'_>,
|
||||
) -> usize {
|
||||
let eat_addr_rva =
|
||||
export_directory_table.export_address_table_rva as usize + (unbiased_ordinal * 4);
|
||||
let export_rva = u32::from_ne_bytes(img[eat_addr_rva..][..4].try_into().unwrap());
|
||||
|
||||
if (img.opt_header.export_table.rva
|
||||
..(img.opt_header.export_table.rva + img.opt_header.export_table.size))
|
||||
.contains(&export_rva)
|
||||
{
|
||||
todo!("symbol forwarding")
|
||||
}
|
||||
|
||||
export_rva as usize
|
||||
}
|
||||
|
||||
fn load_dll(dll_name: &str, executable_path: &Path) -> Option<LoadedDll> {
|
||||
tracing::debug!("loading dll {dll_name}");
|
||||
|
||||
let already_loaded = GLOBAL_STATE
|
||||
|
|
@ -609,14 +657,17 @@ fn load_dll(dll_name: &str, executable_path: &Path) -> LoadedDll {
|
|||
.find(|(name, _)| name == dll_name)
|
||||
.map(Clone::clone);
|
||||
if let Some((_, already_loaded)) = already_loaded {
|
||||
return already_loaded;
|
||||
return Some(already_loaded);
|
||||
}
|
||||
|
||||
let dll = find_dll(&dll_name, executable_path);
|
||||
let dll = match dll {
|
||||
Some(DllLocation::Emulated) => {
|
||||
tracing::debug!("emulating {dll_name:?}");
|
||||
LoadedDll::Emulated
|
||||
LoadedDll::Emulated {
|
||||
name: dll_name.to_owned(),
|
||||
hmodule: GLOBAL_STATE.get_emulated_hmodule_idx(),
|
||||
}
|
||||
}
|
||||
Some(DllLocation::Found(path)) => {
|
||||
let file = std::fs::File::open(&path).unwrap();
|
||||
|
|
@ -659,10 +710,15 @@ fn load_dll(dll_name: &str, executable_path: &Path) -> LoadedDll {
|
|||
tracing::trace!(?name, "DLL {dll_name} has export");
|
||||
}
|
||||
|
||||
LoadedDll::Real(img, export_directory_table, names)
|
||||
LoadedDll::Real {
|
||||
name: dll_name.to_owned(),
|
||||
img,
|
||||
edt: export_directory_table,
|
||||
export_names: names,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
panic!("could not find dll {dll_name:?}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -672,8 +728,14 @@ fn load_dll(dll_name: &str, executable_path: &Path) -> LoadedDll {
|
|||
.unwrap()
|
||||
.loaded_libraries
|
||||
.push((dll_name.to_owned(), dll.clone()));
|
||||
GLOBAL_STATE
|
||||
.state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.hmodule_to_dll
|
||||
.insert(dll.hmodule(), dll.clone());
|
||||
|
||||
dll
|
||||
Some(dll)
|
||||
}
|
||||
|
||||
fn parse_header(pe: &[u8]) -> (&CoffHeader, usize) {
|
||||
|
|
|
|||
24
src/sys.rs
24
src/sys.rs
|
|
@ -56,11 +56,6 @@ mod imp {
|
|||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn call_entrypoint_via_stdcall(fnptr: *const ()) -> u32 {
|
||||
let fnptr = unsafe { std::mem::transmute::<_, unsafe extern "stdcall" fn() -> u32>(fnptr) };
|
||||
unsafe { fnptr() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
|
@ -91,25 +86,6 @@ mod imp {
|
|||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn call_entrypoint_via_stdcall(fnptr: usize) -> u32 {
|
||||
let mut out: u32;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
std::arch::asm!(
|
||||
"call {}",
|
||||
"mov {1:e}, eax",
|
||||
in(reg) fnptr,
|
||||
out(reg) out,
|
||||
);
|
||||
} else {
|
||||
compile_error!("unsupported architecture");
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use imp::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue