mirror of
https://github.com/Noratrieb/portability.git
synced 2026-01-14 07:55:00 +01:00
emulation
This commit is contained in:
parent
5595df2249
commit
38797253f6
3 changed files with 283 additions and 56 deletions
227
src/emulated.rs
Normal file
227
src/emulated.rs
Normal file
|
|
@ -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<usize> {
|
||||
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<usize> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
);
|
||||
97
src/lib.rs
97
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::<u8, u64>(
|
||||
&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::<u8, u16>(&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::<usize>(), size_of::<u64>());
|
||||
a[import_directory.import_address_table_rva as usize..][i * size_of::<u64>()..]
|
||||
[..size_of::<u64>()]
|
||||
.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<PathBuf> {
|
||||
#[derive(Debug)]
|
||||
enum DllLocation {
|
||||
Emulated,
|
||||
#[expect(dead_code)]
|
||||
Found(PathBuf),
|
||||
}
|
||||
|
||||
fn find_dll(name: &CStr) -> Option<DllLocation> {
|
||||
// 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
|
||||
|
|
|
|||
15
src/sys.rs
15
src/sys.rs
|
|
@ -94,21 +94,8 @@ mod imp {
|
|||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn system_directory() -> io::Result<PathBuf> {
|
||||
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::<String>()
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod imp {
|
||||
compile_error!("no unix yet lol skill issue");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue