diff --git a/src/emulated.rs b/src/emulated.rs new file mode 100644 index 0000000..c3e7eca --- /dev/null +++ b/src/emulated.rs @@ -0,0 +1,227 @@ +macro_rules! define_emulation_entry { + ($($name:ident,)*) => { + pub(crate) fn supports_dll(dll_name: &str) -> bool { + [ + $($name::DLL_NAME,)* + ] + .contains(&dll_name.to_lowercase().as_str()) + } + + pub(crate) fn emulate(dll_name: &str, function_name: &str) -> Option { + None + $(.or($name::emulate(dll_name, function_name)))* + } + }; +} + +define_emulation_entry!( + kernel32, + vcruntime140, + api_ms_win_crt_runtime_l1_1_0, + api_ms_win_crt_math_l1_1_0, + api_ms_win_crt_stdio_l1_1_0, + api_ms_win_crt_locale_l1_1_0, + api_ms_win_crt_heap_l1_1_0, +); + +macro_rules! emulate { + ($dllname:literal, mod $modname:ident { + $( + fn $name:ident($($args:tt)*) $(-> $ret:ty)? { + $($body:tt)* + } + )* + }) => { + mod $modname { + pub(super) const DLL_NAME: &str = $dllname; + pub(super) fn emulate(dll_name: &str, function_name: &str) -> Option { + if dll_name.to_lowercase() != $dllname { + return None; + } + + $( + if function_name == stringify!($name) { + unsafe { + return Some(std::mem::transmute($name as extern "system" fn())); + } + } + )* + + None + } + + $( + // TODO: Windows API adapter... + #[allow(non_snake_case)] + extern "system" fn $name($($args)*) $(-> $ret)? { + $($body)* + } + )* + } + }; +} + +emulate!( + "kernel32.dll", + mod kernel32 { + fn QueryPerformanceCounter() { + todo!("QueryPerformanceCounter") + } + fn GetCurrentProcessId() { + todo!("GetCurrentProcessId") + } + fn GetCurrentThreadId() { + todo!("GetCurrentThreadId") + } + fn GetSystemTimeAsFileTime() { + todo!("GetSystemTimeAsFileTime") + } + fn InitializeSListHead() { + todo!("InitializeSListHead") + } + fn RtlCaptureContext() { + todo!("RtlCaptureContext") + } + fn RtlLookupFunctionEntry() { + todo!("RtlLookupFunctionEntry") + } + fn RtlVirtualUnwind() { + todo!("RtlVirtualUnwind") + } + fn IsDebuggerPresent() { + todo!("IsDebuggerPresent") + } + fn UnhandledExceptionFilter() { + todo!("UnhandledExceptionFilter") + } + fn SetUnhandledExceptionFilter() { + todo!("SetUnhandledExceptionFilter") + } + fn IsProcessorFeaturePresent() { + todo!("IsProcessorFeaturePresent") + } + fn GetModuleHandleW() { + todo!("GetModuleHandleW") + } + } +); + +emulate!( + "vcruntime140.dll", + mod vcruntime140 { + fn __C_specific_handler() { + todo!("__C_specific_handler") + } + fn __current_exception() { + todo!("__current_exception") + } + fn __current_exception_context() { + todo!("__current_exception_context") + } + fn memset() { + todo!("memset") + } + fn memcpy() { + todo!("memcpy") + } + } +); + +emulate!( + "api-ms-win-crt-runtime-l1-1-0.dll", + mod api_ms_win_crt_runtime_l1_1_0 { + fn _initterm_e() { + todo!("_initterm_e") + } + fn exit() { + todo!("exit") + } + fn _exit() { + todo!("_exit") + } + fn _initterm() { + todo!("_initterm") + } + fn __p___argc() { + todo!("__p___argc") + } + fn __p___argv() { + todo!("__p___argv") + } + fn _initialize_narrow_environment() { + todo!("_initialize_narrow_environment") + } + fn _c_exit() { + todo!("_c_exit") + } + fn _register_thread_local_exe_atexit_callback() { + todo!("_register_thread_local_exe_atexit_callback") + } + fn _seh_filter_exe() { + todo!("_seh_filter_exe") + } + fn _configure_narrow_argv() { + todo!("_configure_narrow_argv") + } + fn _set_app_type() { + todo!("_set_app_type") + } + fn _initialize_onexit_table() { + todo!("_initialize_onexit_table") + } + fn _register_onexit_function() { + todo!("_register_onexit_function") + } + fn _crt_atexit() { + todo!("_crt_atexit") + } + fn terminate() { + todo!("terminate") + } + fn _cexit() { + todo!("_cexit") + } + fn _get_initial_narrow_environment() { + todo!("_get_initial_narrow_environment") + } + } +); + +emulate!( + "api-ms-win-crt-math-l1-1-0.dll", + mod api_ms_win_crt_math_l1_1_0 { + fn __setusermatherr() { + todo!("__setusermatherr") + } + } +); + +emulate!( + "api-ms-win-crt-stdio-l1-1-0.dll", + mod api_ms_win_crt_stdio_l1_1_0 { + fn _set_fmode() { + todo!("_set_fmode") + } + fn __p__commode() { + todo!("__p__commode") + } + } +); + +emulate!( + "api-ms-win-crt-locale-l1-1-0.dll", + mod api_ms_win_crt_locale_l1_1_0 { + fn _configthreadlocale() { + todo!("_configthreadlocale") + } + } +); + +emulate!( + "api-ms-win-crt-heap-l1-1-0.dll", + mod api_ms_win_crt_heap_l1_1_0 { + fn _set_new_mode() { + todo!("_set_new_mode") + } + } +); diff --git a/src/lib.rs b/src/lib.rs index a8a1761..a34461f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,7 @@ +mod emulated; mod sys; -use std::{ - ffi::CStr, - fmt::Debug, - fs::File, - path::{Path, PathBuf}, -}; +use std::{ffi::CStr, fmt::Debug, path::PathBuf}; #[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)] #[repr(C)] @@ -300,53 +296,74 @@ pub fn execute(pe: &[u8]) { &pe[section.pointer_to_raw_data as usize..][..section.size_of_raw_data as usize], ); - //crate::sys::protect( - // section_a.as_ptr().cast(), - // section.virtual_size as usize, - // mode, - //) - //.unwrap(); + // NOTE: we might actually want to do this later in the process? + // also it doesn't work on windows right now for some reason. + if false { + crate::sys::protect( + section_a.as_ptr().cast(), + section.virtual_size as usize, + mode, + ) + .unwrap(); + } } - let import_directory_table: &[ImportDirectoryTableEntry] = bytemuck::cast_slice( + let import_directory_table = bytemuck::cast_slice::<_, ImportDirectoryTableEntry>( &a[optional_header.import_table.virtual_address as usize..] [..optional_header.import_table.size as usize], - ); + ) + .to_vec(); for import_directory in import_directory_table { dbg!(import_directory); - let name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..]).unwrap(); - if name.is_empty() { + let dll_name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..]) + .unwrap() + .to_owned(); + if dll_name.is_empty() { // Trailing null import directory. break; } - dbg!(name); + dbg!(&dll_name); - let dll = find_dll(name); + let dll = find_dll(&dll_name); match dll { - Some(path) => eprintln!(" found {name:?} at {path:?}"), - None => eprintln!(" COULD NOT FIND {name:?}"), + Some(DllLocation::Emulated) => eprintln!(" emulating {dll_name:?}"), + Some(DllLocation::Found(path)) => todo!("unsupported, loading dll at {path:?}"), + None => panic!("could not find dll {dll_name:?}"), } let import_lookups = bytemuck::cast_slice::( - &a[import_directory.import_lookup_table_rva as usize..], - ); - for import_lookup in import_lookups { - if *import_lookup == 0 { + &a[import_directory.import_address_table_rva as usize..], + ) + .to_vec(); + for (i, import_lookup) in import_lookups.iter().enumerate() { + let import_lookup = *import_lookup; + if import_lookup == 0 { break; } let ordinal_name_flag = import_lookup >> 63; if ordinal_name_flag == 1 { let ordinal_number = import_lookup & 0xFFFF; eprintln!(" import by ordinal: {ordinal_number}"); + todo!("unsupported, import by ordinal"); } else { let hint_name_table_rva = import_lookup & 0xFFFF_FFFF; let hint = bytemuck::cast_slice::(&a[hint_name_table_rva as usize..][..2])[0]; - let name = + let func_name = CStr::from_bytes_until_nul(&a[hint_name_table_rva as usize + 2..]).unwrap(); - eprintln!(" import by name: hint={hint} name={name:?}"); + eprintln!(" import by name: hint={hint} name={func_name:?}"); + let resolved_va = + emulated::emulate(dll_name.to_str().unwrap(), func_name.to_str().unwrap()) + .unwrap_or_else(|| { + panic!("could not find function {func_name:?} in dll {dll_name:?}") + }); + + assert_eq!(size_of::(), size_of::()); + a[import_directory.import_address_table_rva as usize..][i * size_of::()..] + [..size_of::()] + .copy_from_slice(&resolved_va.to_ne_bytes()); } } } @@ -382,28 +399,24 @@ fn parse_header(pe: &[u8]) -> (&CoffHeader, usize) { ) } -fn find_dll(name: &CStr) -> Option { +#[derive(Debug)] +enum DllLocation { + Emulated, + #[expect(dead_code)] + Found(PathBuf), +} + +fn find_dll(name: &CStr) -> Option { // https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order let name = name.to_str().unwrap(); - if name.starts_with("api-") { + if name.starts_with("api-") && emulated::supports_dll(name) { // This is an API set, essentially a virtual alias // https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets - return None; + return Some(DllLocation::Emulated); } - let system = sys::system_directory().unwrap(); - eprintln!(" searching {system:?} for {name}"); - let from_system = std::fs::read_dir(system).unwrap().find(|child| { - child - .as_ref() - .unwrap() - .file_name() - .to_str() - .unwrap() - .eq_ignore_ascii_case(name) - }); - if let Some(from_system) = from_system { - return Some(from_system.unwrap().path()); + if emulated::supports_dll(name) { + return Some(DllLocation::Emulated); } None diff --git a/src/sys.rs b/src/sys.rs index e24afd1..827ed84 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -94,21 +94,8 @@ mod imp { .map_err(Into::into) } } - - pub(crate) fn system_directory() -> io::Result { - let mut buf = vec![0; 1024]; - let ret = unsafe { GetSystemDirectoryW(Some(&mut buf)) }; - if ret == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(std::char::decode_utf16(buf) - .map(Result::unwrap) - .take_while(|c| *c != '\0') - .collect::() - .into()) - } - } } + #[cfg(unix)] mod imp { compile_error!("no unix yet lol skill issue");