mirror of
https://github.com/Noratrieb/portability.git
synced 2026-01-14 15:55:04 +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;
|
mod sys;
|
||||||
|
|
||||||
use std::{
|
use std::{ffi::CStr, fmt::Debug, path::PathBuf};
|
||||||
ffi::CStr,
|
|
||||||
fmt::Debug,
|
|
||||||
fs::File,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||||
#[repr(C)]
|
#[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],
|
&pe[section.pointer_to_raw_data as usize..][..section.size_of_raw_data as usize],
|
||||||
);
|
);
|
||||||
|
|
||||||
//crate::sys::protect(
|
// NOTE: we might actually want to do this later in the process?
|
||||||
// section_a.as_ptr().cast(),
|
// also it doesn't work on windows right now for some reason.
|
||||||
// section.virtual_size as usize,
|
if false {
|
||||||
// mode,
|
crate::sys::protect(
|
||||||
//)
|
section_a.as_ptr().cast(),
|
||||||
//.unwrap();
|
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..]
|
&a[optional_header.import_table.virtual_address as usize..]
|
||||||
[..optional_header.import_table.size as usize],
|
[..optional_header.import_table.size as usize],
|
||||||
);
|
)
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
for import_directory in import_directory_table {
|
for import_directory in import_directory_table {
|
||||||
dbg!(import_directory);
|
dbg!(import_directory);
|
||||||
|
|
||||||
let name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..]).unwrap();
|
let dll_name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..])
|
||||||
if name.is_empty() {
|
.unwrap()
|
||||||
|
.to_owned();
|
||||||
|
if dll_name.is_empty() {
|
||||||
// Trailing null import directory.
|
// Trailing null import directory.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dbg!(name);
|
dbg!(&dll_name);
|
||||||
|
|
||||||
let dll = find_dll(name);
|
let dll = find_dll(&dll_name);
|
||||||
match dll {
|
match dll {
|
||||||
Some(path) => eprintln!(" found {name:?} at {path:?}"),
|
Some(DllLocation::Emulated) => eprintln!(" emulating {dll_name:?}"),
|
||||||
None => eprintln!(" COULD NOT FIND {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>(
|
let import_lookups = bytemuck::cast_slice::<u8, u64>(
|
||||||
&a[import_directory.import_lookup_table_rva as usize..],
|
&a[import_directory.import_address_table_rva as usize..],
|
||||||
);
|
)
|
||||||
for import_lookup in import_lookups {
|
.to_vec();
|
||||||
if *import_lookup == 0 {
|
for (i, import_lookup) in import_lookups.iter().enumerate() {
|
||||||
|
let import_lookup = *import_lookup;
|
||||||
|
if import_lookup == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let ordinal_name_flag = import_lookup >> 63;
|
let ordinal_name_flag = import_lookup >> 63;
|
||||||
if ordinal_name_flag == 1 {
|
if ordinal_name_flag == 1 {
|
||||||
let ordinal_number = import_lookup & 0xFFFF;
|
let ordinal_number = import_lookup & 0xFFFF;
|
||||||
eprintln!(" import by ordinal: {ordinal_number}");
|
eprintln!(" import by ordinal: {ordinal_number}");
|
||||||
|
todo!("unsupported, import by ordinal");
|
||||||
} else {
|
} else {
|
||||||
let hint_name_table_rva = import_lookup & 0xFFFF_FFFF;
|
let hint_name_table_rva = import_lookup & 0xFFFF_FFFF;
|
||||||
let hint =
|
let hint =
|
||||||
bytemuck::cast_slice::<u8, u16>(&a[hint_name_table_rva as usize..][..2])[0];
|
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();
|
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
|
// https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
|
||||||
let name = name.to_str().unwrap();
|
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
|
// This is an API set, essentially a virtual alias
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets
|
// https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets
|
||||||
return None;
|
return Some(DllLocation::Emulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
let system = sys::system_directory().unwrap();
|
if emulated::supports_dll(name) {
|
||||||
eprintln!(" searching {system:?} for {name}");
|
return Some(DllLocation::Emulated);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
|
||||||
15
src/sys.rs
15
src/sys.rs
|
|
@ -94,21 +94,8 @@ mod imp {
|
||||||
.map_err(Into::into)
|
.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)]
|
#[cfg(unix)]
|
||||||
mod imp {
|
mod imp {
|
||||||
compile_error!("no unix yet lol skill issue");
|
compile_error!("no unix yet lol skill issue");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue