This commit is contained in:
nora 2025-01-31 17:41:36 +01:00
parent 389721d5d0
commit 5595df2249
6 changed files with 83 additions and 9 deletions

2
.gitignore vendored
View file

@ -2,3 +2,5 @@
*.exe
*.pdb
!/test/*.exe

View file

@ -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
- 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

View file

@ -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::<u8, u64>(
&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::<usize, unsafe fn() -> !>(
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::<CoffHeader>(),
)
}
fn find_dll(name: &CStr) -> Option<PathBuf> {
// 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
}

View file

@ -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() };

View file

@ -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<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 {

BIN
test/example_exe.exe Normal file

Binary file not shown.