From 5595df224957fa3cc0827f3fdeadf0622e89034a Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Fri, 31 Jan 2025 17:41:36 +0100 Subject: [PATCH] test --- .gitignore | 2 ++ README.md | 3 ++- src/lib.rs | 57 ++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 2 +- src/sys.rs | 28 ++++++++++++++++++--- test/example_exe.exe | Bin 0 -> 10240 bytes 6 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 test/example_exe.exe diff --git a/.gitignore b/.gitignore index d8ba7bb..1d6d67b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ *.exe *.pdb + +!/test/*.exe diff --git a/README.md b/README.md index 18fd8a7..f928617 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,5 @@ a PE loader for educational purposes. - https://learn.microsoft.com/en-us/windows/win32/debug/pe-format - https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail -- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2 \ No newline at end of file +- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2 +- https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order diff --git a/src/lib.rs b/src/lib.rs index ff49b95..a8a1761 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,11 @@ mod sys; -use std::{ffi::CStr, fmt::Debug, fs::File}; +use std::{ + ffi::CStr, + fmt::Debug, + fs::File, + path::{Path, PathBuf}, +}; #[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)] #[repr(C)] @@ -250,8 +255,8 @@ pub fn execute(pe: &[u8]) { ); dbg!(section_table); - // just some arbitrary offset that probably won't collide with anything - let base = optional_header.image_base as usize + 0xFFFFFF0000; + // let's always load it at the image base for now... + let base = optional_header.image_base as usize; let allocation_granularity = crate::sys::allocation_granularity(); @@ -312,8 +317,18 @@ pub fn execute(pe: &[u8]) { dbg!(import_directory); let name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..]).unwrap(); + if name.is_empty() { + // Trailing null import directory. + break; + } dbg!(name); + let dll = find_dll(name); + match dll { + Some(path) => eprintln!(" found {name:?} at {path:?}"), + None => eprintln!(" COULD NOT FIND {name:?}"), + } + let import_lookups = bytemuck::cast_slice::( &a[import_directory.import_lookup_table_rva as usize..], ); @@ -335,6 +350,15 @@ pub fn execute(pe: &[u8]) { } } } + + eprintln!("YOLO"); + + unsafe { + let entrypoint = std::mem::transmute:: !>( + optional_header.address_of_entry_point as usize, + ); + entrypoint(); + }; } fn parse_header(pe: &[u8]) -> (&CoffHeader, usize) { @@ -357,3 +381,30 @@ fn parse_header(pe: &[u8]) -> (&CoffHeader, usize) { (signature_pointer as usize) + 4 + std::mem::size_of::(), ) } + +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-") { + // This is an API set, essentially a virtual alias + // https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets + return None; + } + + 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()); + } + + None +} diff --git a/src/main.rs b/src/main.rs index f06f452..647eada 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ fn main() { .open( std::env::args() .nth(1) - .unwrap_or_else(|| "example_exe.exe".into()), + .unwrap_or_else(|| "test/example_exe.exe".into()), ) .unwrap(); let map = unsafe { memmap2::Mmap::map(&file).unwrap() }; diff --git a/src/sys.rs b/src/sys.rs index 679cd4c..e24afd1 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -8,13 +8,16 @@ pub(crate) enum Mode { #[cfg(windows)] mod imp { - use std::{ffi::c_void, io, u32}; + use std::{ffi::c_void, io, path::PathBuf, u32}; use windows::Win32::{ Foundation::INVALID_HANDLE_VALUE, System::{ - Memory::{FILE_MAP_EXECUTE, FILE_MAP_WRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PAGE_READWRITE}, - SystemInformation::SYSTEM_INFO, + Memory::{ + FILE_MAP_EXECUTE, FILE_MAP_WRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, + PAGE_READONLY, PAGE_READWRITE, + }, + SystemInformation::{GetSystemDirectoryW, SYSTEM_INFO}, }, }; @@ -36,7 +39,10 @@ mod imp { info.dwPageSize as usize } - pub(crate) unsafe fn anon_write_map<'a>(size: usize, address: *const ()) -> io::Result<&'a mut [u8]> { + pub(crate) unsafe fn anon_write_map<'a>( + size: usize, + address: *const (), + ) -> io::Result<&'a mut [u8]> { let map = windows::Win32::System::Memory::CreateFileMappingA( INVALID_HANDLE_VALUE, None, @@ -88,6 +94,20 @@ 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 { diff --git a/test/example_exe.exe b/test/example_exe.exe new file mode 100644 index 0000000000000000000000000000000000000000..903f3c5e620cff61e7749a0990e15e0c277c73cb GIT binary patch literal 10240 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