From dc6ef2108de6c6480b1b7d50d7300cbd68497b68 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 1 Feb 2025 14:37:46 +0100 Subject: [PATCH] fixes --- .envrc | 1 + .gitignore | 2 + Cargo.lock | 1 + Cargo.toml | 3 ++ shell.nix | 3 ++ src/lib.rs | 74 +++++++++++++++++++++++------------- src/main.rs | 14 +++---- src/sys.rs | 79 ++++++++++++++++++++++++++++++++++++--- test/build.sh | 3 ++ test/example_exe.exe | Bin 10240 -> 2048 bytes test/example_exe.rs | 5 ++- test/example_exe_crt.exe | Bin 0 -> 10240 bytes test/example_exe_crt.rs | 10 +++++ test2/Makefile | 16 ++++++++ test2/empty_exe.rs | 13 +++++++ test2/one_dll.rs | 18 +++++++++ test2/small_dll.rs | 18 +++++++++ 17 files changed, 221 insertions(+), 39 deletions(-) create mode 100644 .envrc create mode 100644 shell.nix create mode 100755 test/build.sh mode change 100644 => 100755 test/example_exe.exe create mode 100644 test/example_exe_crt.exe create mode 100644 test/example_exe_crt.rs create mode 100644 test2/Makefile create mode 100644 test2/empty_exe.rs create mode 100644 test2/one_dll.rs create mode 100644 test2/small_dll.rs diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore index 1d6d67b..0be2ae9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ *.exe *.pdb +*.dll +*.dll.lib !/test/*.exe diff --git a/Cargo.lock b/Cargo.lock index 7912ab6..fb11b9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,7 @@ version = "0.1.0" dependencies = [ "bitflags", "bytemuck", + "libc", "memmap2", "windows", ] diff --git a/Cargo.toml b/Cargo.toml index f58059f..5ec3bb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,6 @@ memmap2 = "0.9.5" [target.'cfg(windows)'.dependencies] windows = { version = "0.59.0", features = ["Win32_System_Memory", "Win32_Security", "Win32_System_SystemInformation"] } + +[target.'cfg(unix)'.dependencies] +libc = "0.2.169" diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..fa4398f --- /dev/null +++ b/shell.nix @@ -0,0 +1,3 @@ +{ pkgs ? import { } }: pkgs.mkShell { + nativeBuildInputs = with pkgs; [ lld_18 rustup ]; +} diff --git a/src/lib.rs b/src/lib.rs index c150f5f..18973bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,11 @@ mod emulated; mod sys; -use std::{ffi::CStr, fmt::Debug, path::PathBuf}; +use std::{ + ffi::CStr, + fmt::Debug, + path::{Path, PathBuf}, +}; #[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)] #[repr(C)] @@ -197,7 +201,7 @@ struct ImportDirectoryTableEntry { const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664; const IMAGE_FILE_MACHINE_ARM64: u16 = 0xaa64; -pub fn execute(pe: &[u8]) { +pub fn execute(pe: &[u8], executable_path: &Path) { let (header, after_header) = parse_header(pe); match (std::env::consts::ARCH, header.machine) { @@ -258,14 +262,12 @@ pub fn execute(pe: &[u8]) { assert_eq!(base & (allocation_granularity - 1), 0); - let total_size = section_table.last().unwrap().virtual_address as usize; + let last_section = section_table.last().unwrap(); + let total_size = (last_section.virtual_address as usize + last_section.virtual_size as usize) + .next_multiple_of(allocation_granularity); let a = unsafe { - crate::sys::anon_write_map( - total_size.next_multiple_of(allocation_granularity), - std::ptr::with_exposed_provenance(base), - ) - .unwrap() + crate::sys::anon_write_map(total_size, std::ptr::with_exposed_provenance(base)).unwrap() }; // allocate the sections. @@ -273,11 +275,10 @@ pub fn execute(pe: &[u8]) { if section.virtual_size > section.size_of_raw_data { todo!("zero padding") } + eprintln!("mapping section {:?}", section.name); let section_a = &mut a[section.virtual_address as usize..]; - dbg!(section); - section_a[..section.size_of_raw_data as usize].copy_from_slice( &pe[section.pointer_to_raw_data as usize..][..section.size_of_raw_data as usize], ); @@ -289,19 +290,21 @@ pub fn execute(pe: &[u8]) { ) .to_vec(); + eprintln!("checking imports"); for import_directory in import_directory_table { dbg!(import_directory); let dll_name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..]) .unwrap() .to_owned(); + let dll_name = dll_name.to_str().unwrap(); if dll_name.is_empty() { // Trailing null import directory. break; } - dbg!(&dll_name); + eprintln!("loading dll {dll_name}"); - let dll = find_dll(&dll_name); + let dll = find_dll(&dll_name, executable_path); match dll { Some(DllLocation::Emulated) => eprintln!(" emulating {dll_name:?}"), Some(DllLocation::Found(path)) => todo!("unsupported, loading dll at {path:?}"), @@ -329,11 +332,10 @@ pub fn execute(pe: &[u8]) { let func_name = CStr::from_bytes_until_nul(&a[hint_name_table_rva as usize + 2..]).unwrap(); 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:?}") - }); + let resolved_va = emulated::emulate(dll_name, 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::()..] @@ -343,6 +345,7 @@ pub fn execute(pe: &[u8]) { } } + eprintln!("applying section protections"); for section in section_table { let mode = if section .characteristics @@ -368,13 +371,13 @@ pub fn execute(pe: &[u8]) { .unwrap(); } - eprintln!("YOLO"); + let entrypoint = + optional_header.image_base as usize + optional_header.address_of_entry_point as usize; + eprintln!("YOLO to {:#x}", entrypoint); unsafe { - let entrypoint = std::mem::transmute:: !>( - optional_header.address_of_entry_point as usize, - ); - entrypoint(); + let result = sys::call_entrypoint_via_stdcall(entrypoint); + eprintln!("result: {result}"); }; } @@ -406,18 +409,39 @@ enum DllLocation { Found(PathBuf), } -fn find_dll(name: &CStr) -> Option { +fn find_dll(name: &str, executable_path: &Path) -> 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-") && 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 Some(DllLocation::Emulated); } - if emulated::supports_dll(name) { return Some(DllLocation::Emulated); } + let name_lowercase = name.to_lowercase(); + + let probe_path = |path: &Path| -> Option { + std::fs::read_dir(path) + .ok()? + .find(|entry| { + entry + .as_ref() + .map(|entry| { + entry + .file_name() + .to_str() + .is_some_and(|name| name.to_lowercase() == name_lowercase) + }) + .unwrap_or(false) + }) + .map(|entry| entry.unwrap().path()) + }; + + if let Some(path) = probe_path(executable_path.parent().unwrap()) { + return Some(DllLocation::Found(path)); + } + None } diff --git a/src/main.rs b/src/main.rs index 647eada..3be6eb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #[cfg(windows)] use std::os::windows::fs::OpenOptionsExt; +use std::path::Path; fn main() { let mut opts = std::fs::OpenOptions::new(); @@ -10,14 +11,11 @@ fn main() { windows::Win32::Foundation::GENERIC_EXECUTE.0 | windows::Win32::Foundation::GENERIC_READ.0, ); - let file = opts - .open( - std::env::args() - .nth(1) - .unwrap_or_else(|| "test/example_exe.exe".into()), - ) - .unwrap(); + let path = std::env::args() + .nth(1) + .unwrap_or_else(|| "test/example_exe.exe".into()); + let file = opts.open(&path).unwrap(); let map = unsafe { memmap2::Mmap::map(&file).unwrap() }; - portability::execute(&map); + portability::execute(&map, Path::new(&path)); } diff --git a/src/sys.rs b/src/sys.rs index 1979122..1893b1d 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -14,7 +14,8 @@ mod imp { Foundation::INVALID_HANDLE_VALUE, System::{ Memory::{ - FILE_MAP_EXECUTE, FILE_MAP_WRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS, PAGE_READONLY, PAGE_READWRITE + FILE_MAP_EXECUTE, FILE_MAP_WRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, + PAGE_PROTECTION_FLAGS, PAGE_READONLY, PAGE_READWRITE, }, SystemInformation::SYSTEM_INFO, }, @@ -51,8 +52,6 @@ mod imp { None, )?; - eprintln!("created {address:p} {size:x}"); - debug_assert_eq!(address.addr() & (allocation_granularity() - 1), 0); debug_assert_eq!(size & (allocation_granularity() - 1), 0); @@ -78,7 +77,7 @@ mod imp { pub(crate) fn protect(address: *const (), size: usize, mode: Mode) -> io::Result<()> { debug_assert_eq!(address.addr() & (page_size() - 1), 0); - let mut old= PAGE_PROTECTION_FLAGS::default(); + let mut old = PAGE_PROTECTION_FLAGS::default(); unsafe { windows::Win32::System::Memory::VirtualProtect( address.cast::(), @@ -93,11 +92,81 @@ 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)] mod imp { - compile_error!("no unix yet lol skill issue"); + use std::io; + + use super::Mode; + + pub(crate) fn allocation_granularity() -> usize { + unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } + } + + pub(crate) fn page_size() -> usize { + allocation_granularity() + } + + pub(crate) unsafe fn anon_write_map<'a>( + size: usize, + address: *const (), + ) -> io::Result<&'a mut [u8]> { + debug_assert_eq!(address.addr() & (allocation_granularity() - 1), 0); + debug_assert_eq!(size & (allocation_granularity() - 1), 0); + + let ret = libc::mmap( + address as _, + size, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, + -1, + 0, + ); + if ret == libc::MAP_FAILED { + Err(io::Error::last_os_error()) + } else if ret.addr() != address.addr() { + Err(io::Error::new( + io::ErrorKind::AlreadyExists, + "address already taken".to_owned(), + )) + } else { + Ok(std::slice::from_raw_parts_mut( + address.cast_mut().cast(), + size, + )) + } + } + + pub(crate) fn protect(address: *const (), size: usize, mode: super::Mode) -> io::Result<()> { + debug_assert_eq!(address.addr() & (page_size() - 1), 0); + let prot = match mode { + Mode::Read => libc::PROT_READ, + Mode::Write => libc::PROT_READ | libc::PROT_WRITE, + Mode::Execute => libc::PROT_READ | libc::PROT_EXEC, + }; + let ret = unsafe { libc::mprotect(address as _, size, prot) }; + if ret == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + pub(crate) unsafe fn call_entrypoint_via_stdcall(fnptr: usize) -> u32 { + // todo this might be correct or not idk??? is it close enough in this case maybe?? use asm probably. + let fnptr = unsafe { + std::mem::transmute::<*const (), unsafe extern "C" fn() -> u32>( + std::ptr::with_exposed_provenance(fnptr), + ) + }; + unsafe { fnptr() } + } } pub(crate) use imp::*; diff --git a/test/build.sh b/test/build.sh new file mode 100755 index 0000000..a726a47 --- /dev/null +++ b/test/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +rustc example_exe.rs --target x86_64-pc-windows-msvc -Cpanic=abort -Clinker=lld-link -Clink-arg=/entry:my_main -Clink-arg=/NODEFAULTLIB -Cdebuginfo=0 diff --git a/test/example_exe.exe b/test/example_exe.exe old mode 100644 new mode 100755 index 903f3c5e620cff61e7749a0990e15e0c277c73cb..1cf32cd82cbc9f35ef8f8bc87305d09b35cc80dc GIT binary patch literal 2048 zcmeZ`s$gJbU|?WjKm`t{T&%nb1_lN``CWVrTR6`u?qKves~D1zS*%b{l%HOdn5&SS zn3tDdqL7rTP*j?ykeR38;vcM#o1c=Zr^3Jx;L5;|(#FKVu<2<*^eU|=|WW)zIj5CA6;Xc-JDdNddq7-T?Y92)~eP_Rqzyx#R%Nq&bG`S`df h1h_cqfy&_2ip1Q4oYeT#id4OVlq9ebqr}h*0RR!y#Df3; literal 10240 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 -> ! { @@ -7,4 +8,6 @@ fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! { } #[no_mangle] -pub fn main() {} +pub extern "stdcall" fn my_main() -> u32 { + 42 +} diff --git a/test/example_exe_crt.exe b/test/example_exe_crt.exe new file mode 100644 index 0000000000000000000000000000000000000000..903f3c5e620cff61e7749a0990e15e0c277c73cb GIT binary patch literal 10240 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 -> ! { + loop {} +} + +#[no_mangle] +pub extern "stdcall" fn my_main() {} diff --git a/test2/Makefile b/test2/Makefile new file mode 100644 index 0000000..0faa087 --- /dev/null +++ b/test2/Makefile @@ -0,0 +1,16 @@ +RUSTC = rustc --target x86_64-pc-windows-msvc -Cpanic=abort -Clinker=lld-link -Clink-arg=/NODEFAULTLIB -Clink-arg=/debug:none -Cdebuginfo=0 + +build: empty_exe.exe one_dll.exe + +empty_exe.exe: empty_exe.rs + $(RUSTC) empty_exe.rs + +one_dll.exe: one_dll.rs small_dll.dll + $(RUSTC) one_dll.rs + +small_dll.dll: small_dll.rs + $(RUSTC) small_dll.rs + +.PHONY: clean +clean: + rm *.exe *.pdb *.dll diff --git a/test2/empty_exe.rs b/test2/empty_exe.rs new file mode 100644 index 0000000..4c5a380 --- /dev/null +++ b/test2/empty_exe.rs @@ -0,0 +1,13 @@ +#![no_std] +#![no_main] +#![windows_subsystem = "console"] + +#[panic_handler] +fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +#[no_mangle] +pub extern "stdcall" fn mainCRTStartup() -> u32 { + 42 +} diff --git a/test2/one_dll.rs b/test2/one_dll.rs new file mode 100644 index 0000000..503bc9a --- /dev/null +++ b/test2/one_dll.rs @@ -0,0 +1,18 @@ +#![no_std] +#![no_main] +#![windows_subsystem = "console"] + +#[link(name = "small_dll", kind = "raw-dylib")] +unsafe extern "C" { + safe fn my_export() -> u32; +} + +#[panic_handler] +fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +#[no_mangle] +pub extern "stdcall" fn mainCRTStartup() -> u32 { + my_export() +} diff --git a/test2/small_dll.rs b/test2/small_dll.rs new file mode 100644 index 0000000..494dac0 --- /dev/null +++ b/test2/small_dll.rs @@ -0,0 +1,18 @@ +#![no_std] +#![crate_type = "cdylib"] +#![windows_subsystem = "console"] + +#[panic_handler] +fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +#[no_mangle] +pub extern "C" fn my_export() -> u32 { + 42 +} + +#[no_mangle] +pub extern "stdcall" fn _DllMainCRTStartup() -> u32 { + 0 +}