mirror of
https://github.com/Noratrieb/portability.git
synced 2026-01-14 15:55:04 +01:00
magic
This commit is contained in:
commit
00afbbfea3
7 changed files with 660 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
|
||||
*.exe
|
||||
*.pdb
|
||||
219
Cargo.lock
generated
Normal file
219
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portability"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytemuck",
|
||||
"memmap2",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d08106ce80268c4067c0571ca55a9b4e9516518eaa1a1fe9b37ca403ae1d1a34"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b888f919960b42ea4e11c2f408fadb55f78a9f236d5eef084103c8ce52893491"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "portability"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bitflags = { version = "2.8.0", features = ["bytemuck"] }
|
||||
bytemuck = { version = "1.21.0", features = ["derive"] }
|
||||
memmap2 = "0.9.5"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { version = "0.59.0", features = ["Win32_System_Memory", "Win32_Security"] }
|
||||
312
src/lib.rs
Normal file
312
src/lib.rs
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
mod mmap;
|
||||
|
||||
use std::{ffi::CStr, fmt::Debug, fs::File};
|
||||
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(C)]
|
||||
struct CoffHeader {
|
||||
machine: u16,
|
||||
number_of_sections: u16,
|
||||
time_date_stamp: u32,
|
||||
pointer_to_symbol_table: u32,
|
||||
number_of_symbols: u32,
|
||||
size_of_optional_header: u16,
|
||||
characteristics: Characteristics,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(C)]
|
||||
struct OptionalHeader {
|
||||
// standard COFF
|
||||
magic: u16,
|
||||
major_linker_version: u8,
|
||||
minor_linker_version: u8,
|
||||
size_of_code: u32,
|
||||
size_of_initialized_data: u32,
|
||||
size_of_uninitialized_data: u32,
|
||||
address_of_entry_point: u32,
|
||||
base_of_code: u32,
|
||||
// Windows extension
|
||||
image_base: u64,
|
||||
section_alignment: u32,
|
||||
file_alignment: u32,
|
||||
major_operating_system_version: u16,
|
||||
minor_operating_system_version: u16,
|
||||
major_image_version: u16,
|
||||
minor_image_version: u16,
|
||||
major_subsystem_version: u16,
|
||||
minor_subsystem_version: u16,
|
||||
win32_version_value: u32,
|
||||
size_of_image: u32,
|
||||
size_of_headers: u32,
|
||||
check_sum: u32,
|
||||
subsystem: u16,
|
||||
dll_characteristics: DllCharacteristics,
|
||||
size_of_stack_reserve: u64,
|
||||
size_of_stack_commit: u64,
|
||||
size_of_heap_reserve: u64,
|
||||
sizeof_heap_commit: u64,
|
||||
loader_flags: u32,
|
||||
number_of_rva_and_sizes: u32,
|
||||
// Data directories
|
||||
export_table: DataDirectory,
|
||||
import_table: DataDirectory,
|
||||
resource_table: DataDirectory,
|
||||
exception_table: DataDirectory,
|
||||
certificate_table: DataDirectory,
|
||||
base_relocation_table: DataDirectory,
|
||||
debug: DataDirectory,
|
||||
architecture: DataDirectory,
|
||||
global_ptr: DataDirectory,
|
||||
tls_table: DataDirectory,
|
||||
load_config_table: DataDirectory,
|
||||
bound_import: DataDirectory,
|
||||
iat: DataDirectory,
|
||||
delay_import_descriptor: DataDirectory,
|
||||
clr_runtime_header: DataDirectory,
|
||||
_reserved: DataDirectory,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(C)]
|
||||
struct DataDirectory {
|
||||
// RVA
|
||||
virtual_address: u32,
|
||||
size: u32,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(transparent)]
|
||||
pub struct Characteristics: u16 {
|
||||
const IMAGE_FILE_RELOCS_STRIPPED = 0x0001; // Image only, Windows CE, and Microsoft Windows NT and later. This indicates that the file does not contain base relocations and must therefore be loaded at its preferred base address. If the base address is not available, the loader reports an error. The default behavior of the linker is to strip base relocations from executable (EXE) files.
|
||||
const IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002; // Image only. This indicates that the image file is valid and can be run. If this flag is not set, it indicates a linker error.
|
||||
const IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004; // COFF line numbers have been removed. This flag is deprecated and should be zero.
|
||||
const IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008; // COFF symbol table entries for local symbols have been removed. This flag is deprecated and should be zero.
|
||||
const IMAGE_FILE_AGGRESSIVE_WS_TRIM = 0x0010; // Obsolete. Aggressively trim working set. This flag is deprecated for Windows 2000 and later and must be zero.
|
||||
const IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020; // Application can handle > 2-GB addresses.
|
||||
const IMAGE_FILE_BYTES_REVERSED_LO = 0x0080; // Little endian: the least significant bit (LSB) precedes the most significant bit (MSB) in memory. This flag is deprecated and should be zero.
|
||||
const IMAGE_FILE_32BIT_MACHINE = 0x0100; // Machine is based on a 32-bit-word architecture.
|
||||
const IMAGE_FILE_DEBUG_STRIPPED = 0x0200; // Debugging information is removed from the image file.
|
||||
const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400; // If the image is on removable media, fully load it and copy it to the swap file.
|
||||
const IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800; // If the image is on network media, fully load it and copy it to the swap file.
|
||||
const IMAGE_FILE_SYSTEM = 0x1000; // The image file is a system file, not a user program.
|
||||
const IMAGE_FILE_DLL = 0x2000; // The image file is a dynamic-link library (DLL). Such files are considered executable files for almost all purposes, although they cannot be directly run.
|
||||
const IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000; // The file should be run only on a uniprocessor machine.
|
||||
const IMAGE_FILE_BYTES_REVERSED_HI = 0x8000; // Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero.
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(transparent)]
|
||||
pub struct DllCharacteristics: u16 {
|
||||
const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020; // Image can handle a high entropy 64-bit virtual address space.
|
||||
const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040; // DLL can be relocated at load time.
|
||||
const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080; // Code Integrity checks are enforced.
|
||||
const IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100; // Image is NX compatible.
|
||||
const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200; // Isolation aware, but do not isolate the image.
|
||||
const IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400; // Does not use structured exception (SE) handling. No SE handler may be called in this image.
|
||||
const IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800; // Do not bind the image.
|
||||
const IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000; // Image must execute in an AppContainer.
|
||||
const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000; // A WDM driver.
|
||||
const IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000; // Image supports Control Flow Guard.
|
||||
const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000; // Terminal Server aware.
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(C)]
|
||||
struct SectionHeader {
|
||||
name: SectionName,
|
||||
virtual_size: u32,
|
||||
virtual_address: u32,
|
||||
size_of_raw_data: u32,
|
||||
pointer_to_raw_data: u32,
|
||||
pointer_to_relocations: u32,
|
||||
pointer_to_linenumbers: u32,
|
||||
number_of_relocations: u16,
|
||||
number_of_linenumbers: u16,
|
||||
characteristics: SectionFlags,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(transparent)]
|
||||
struct SectionName([u8; 8]);
|
||||
impl Debug for SectionName {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = CStr::from_bytes_until_nul(&self.0).unwrap();
|
||||
f.write_str(s.to_str().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(transparent)]
|
||||
pub struct SectionFlags: u32 {
|
||||
const IMAGE_SCN_TYPE_NO_PAD = 0x00000008; // The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files.
|
||||
const IMAGE_SCN_CNT_CODE = 0x00000020; // The section contains executable code.
|
||||
const IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040; // The section contains initialized data.
|
||||
const IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080; // The section contains uninitialized data.
|
||||
const IMAGE_SCN_LNK_OTHER = 0x00000100; // Reserved for future use.
|
||||
const IMAGE_SCN_LNK_INFO = 0x00000200; // The section contains comments or other information. The .drectve section has this type. This is valid for object files only.
|
||||
const IMAGE_SCN_LNK_REMOVE = 0x00000800; // The section will not become part of the image. This is valid only for object files.
|
||||
const IMAGE_SCN_LNK_COMDAT = 0x00001000; // The section contains COMDAT data. For more information, see COMDAT Sections (Object Only). This is valid only for object files.
|
||||
const IMAGE_SCN_GPREL = 0x00008000; // The section contains data referenced through the global pointer (GP).
|
||||
const IMAGE_SCN_MEM_PURGEABLE = 0x00020000; // Reserved for future use.
|
||||
const IMAGE_SCN_MEM_16BIT = 0x00020000; // Reserved for future use.
|
||||
const IMAGE_SCN_MEM_LOCKED = 0x00040000; // Reserved for future use.
|
||||
const IMAGE_SCN_MEM_PRELOAD = 0x00080000; // Reserved for future use.
|
||||
const IMAGE_SCN_ALIGN_1BYTES = 0x00100000; // Align data on a 1-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_2BYTES = 0x00200000; // Align data on a 2-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_4BYTES = 0x00300000; // Align data on a 4-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_8BYTES = 0x00400000; // Align data on an 8-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_16BYTES = 0x00500000; // Align data on a 16-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_32BYTES = 0x00600000; // Align data on a 32-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_64BYTES = 0x00700000; // Align data on a 64-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_128BYTES = 0x00800000; // Align data on a 128-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_256BYTES = 0x00900000; // Align data on a 256-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_512BYTES = 0x00A00000; // Align data on a 512-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000; // Align data on a 1024-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000; // Align data on a 2048-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000; // Align data on a 4096-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000; // Align data on an 8192-byte boundary. Valid only for object files.
|
||||
const IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000; // The section contains extended relocations.
|
||||
const IMAGE_SCN_MEM_DISCARDABLE = 0x02000000; // The section can be discarded as needed.
|
||||
const IMAGE_SCN_MEM_NOT_CACHED = 0x04000000; // The section cannot be cached.
|
||||
const IMAGE_SCN_MEM_NOT_PAGED = 0x08000000; // The section is not pageable.
|
||||
const IMAGE_SCN_MEM_SHARED = 0x10000000; // The section can be shared in memory.
|
||||
const IMAGE_SCN_MEM_EXECUTE = 0x20000000; // The section can be executed as code.
|
||||
const IMAGE_SCN_MEM_READ = 0x40000000; // The section can be read.
|
||||
const IMAGE_SCN_MEM_WRITE = 0x80000000; // The section can be written to.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||
#[repr(C)]
|
||||
struct ImportDirectoryTableEntry {
|
||||
import_lookup_table_rva: u32,
|
||||
timestamp: u32,
|
||||
forwarder_chain: u32,
|
||||
name_rva: u32,
|
||||
import_address_table_rva: u32,
|
||||
}
|
||||
|
||||
const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
|
||||
const IMAGE_FILE_MACHINE_ARM64: u16 = 0xaa64;
|
||||
|
||||
pub fn execute(file: File, pe: &[u8]) {
|
||||
let (header, after_header) = parse_header(pe);
|
||||
|
||||
match (std::env::consts::ARCH, header.machine) {
|
||||
("x86_64", IMAGE_FILE_MACHINE_AMD64) => {}
|
||||
("aarch64", IMAGE_FILE_MACHINE_ARM64) => {}
|
||||
(arch, machine) => {
|
||||
panic!("unsupported, cannot execute PE for machine {machine:x} on {arch}")
|
||||
}
|
||||
}
|
||||
|
||||
if !header
|
||||
.characteristics
|
||||
.contains(Characteristics::IMAGE_FILE_EXECUTABLE_IMAGE)
|
||||
{
|
||||
panic!("unsupported, cannot execute invalid executable")
|
||||
}
|
||||
|
||||
if header
|
||||
.characteristics
|
||||
.contains(Characteristics::IMAGE_FILE_DLL)
|
||||
{
|
||||
panic!("unsupported, cannot execute DLL")
|
||||
}
|
||||
|
||||
if (header.size_of_optional_header as usize) < size_of::<OptionalHeader>() {
|
||||
panic!("file does not have enough of the required optional header (lol)");
|
||||
}
|
||||
|
||||
dbg!(header);
|
||||
|
||||
let optional_header: &OptionalHeader =
|
||||
&bytemuck::cast_slice(&pe[after_header..][..size_of::<OptionalHeader>()])[0];
|
||||
dbg!(optional_header);
|
||||
|
||||
if optional_header.magic != 0x20b {
|
||||
panic!("unsupported, only PE32+ is supported");
|
||||
}
|
||||
|
||||
if optional_header.subsystem != 3 {
|
||||
panic!("unsupported, only IMAGE_SUBSYSTEM_WINDOWS_CUI subsystem is supported");
|
||||
}
|
||||
|
||||
if optional_header.number_of_rva_and_sizes < 16 {
|
||||
panic!("unsupported, we want at least 16 data directories")
|
||||
}
|
||||
|
||||
let section_table_offset = after_header + header.size_of_optional_header as usize;
|
||||
let section_table: &[SectionHeader] = bytemuck::cast_slice(
|
||||
&pe[section_table_offset..]
|
||||
[..(header.number_of_sections as usize * size_of::<SectionHeader>())],
|
||||
);
|
||||
dbg!(section_table);
|
||||
|
||||
// just some arbitrary offset that probably won't collide with anything
|
||||
let base = optional_header.image_base as usize + 0xFFFFFF0000;
|
||||
|
||||
let map = unsafe { crate::mmap::map(file).unwrap() };
|
||||
|
||||
// allocate the sections.
|
||||
for section in section_table {
|
||||
if section.virtual_size > section.size_of_raw_data {
|
||||
todo!("zero padding")
|
||||
}
|
||||
|
||||
let mode = if section
|
||||
.characteristics
|
||||
.contains(SectionFlags::IMAGE_SCN_MEM_EXECUTE)
|
||||
{
|
||||
crate::mmap::Mode::Execute
|
||||
} else if section
|
||||
.characteristics
|
||||
.contains(SectionFlags::IMAGE_SCN_MEM_WRITE)
|
||||
{
|
||||
crate::mmap::Mode::Write
|
||||
} else {
|
||||
crate::mmap::Mode::Read
|
||||
};
|
||||
let address = std::ptr::with_exposed_provenance(base + section.virtual_address as usize);
|
||||
unsafe {
|
||||
map.view(
|
||||
mode,
|
||||
section.pointer_to_raw_data as u64,
|
||||
section.size_of_raw_data as usize,
|
||||
address,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
//let import_directory_table: &[ImportDirectoryTableEntry] = bytemuck::cast_slice(&file[optional_header.import_table.virtual_address as usize..][..optional_header.import_table.size as usize]);
|
||||
//dbg!(import_directory_table);
|
||||
}
|
||||
|
||||
fn parse_header(pe: &[u8]) -> (&CoffHeader, usize) {
|
||||
// After the MS-DOS stub, at the file offset specified at offset 0x3c,
|
||||
// is a 4-byte signature that identifies the file as a PE format image file.
|
||||
// This signature is "PE\0\0" (the letters "P" and "E" followed by two null bytes).
|
||||
let signature_pointer = u32::from_le_bytes(pe[0x3c..][..4].try_into().unwrap());
|
||||
let signature = &pe[(signature_pointer as usize)..][..4];
|
||||
assert_eq!(signature, b"PE\0\0");
|
||||
|
||||
// At the beginning of an object file, or immediately after the signature of an image file,
|
||||
// is a standard COFF file header in the following format.
|
||||
// Note that the Windows loader limits the number of sections to 96.
|
||||
|
||||
let header = &bytemuck::cast_slice(
|
||||
&pe[(signature_pointer as usize) + 4..][..std::mem::size_of::<CoffHeader>()],
|
||||
)[0];
|
||||
(
|
||||
header,
|
||||
(signature_pointer as usize) + 4 + std::mem::size_of::<CoffHeader>(),
|
||||
)
|
||||
}
|
||||
23
src/main.rs
Normal file
23
src/main.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#[cfg(windows)]
|
||||
use std::os::windows::fs::OpenOptionsExt;
|
||||
|
||||
fn main() {
|
||||
let mut opts = std::fs::OpenOptions::new();
|
||||
opts.read(true);
|
||||
#[cfg(windows)]
|
||||
OpenOptionsExt::access_mode(
|
||||
&mut opts,
|
||||
windows::Win32::Foundation::GENERIC_EXECUTE.0 | windows::Win32::Foundation::GENERIC_READ.0,
|
||||
);
|
||||
|
||||
let file = opts
|
||||
.open(
|
||||
std::env::args()
|
||||
.nth(1)
|
||||
.unwrap_or_else(|| "example_exe.exe".into()),
|
||||
)
|
||||
.unwrap();
|
||||
let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
|
||||
|
||||
portability::execute(file, &map);
|
||||
}
|
||||
80
src/mmap.rs
Normal file
80
src/mmap.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
//! memmap2 doesn't support MAP_FIXED so here's our own!
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub(crate) struct MapView(*const ());
|
||||
|
||||
pub(crate) enum Mode {
|
||||
Read,
|
||||
Write,
|
||||
Execute,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
use std::{ffi::c_void, fs::File, io, os::windows::io::AsRawHandle, u32};
|
||||
|
||||
use windows::Win32::{
|
||||
Foundation::HANDLE,
|
||||
System::Memory::{FILE_MAP_COPY, FILE_MAP_EXECUTE, FILE_MAP_READ, PAGE_EXECUTE_READ},
|
||||
};
|
||||
|
||||
use super::{MapView, Mode};
|
||||
|
||||
pub(crate) struct Map(HANDLE);
|
||||
|
||||
pub(crate) unsafe fn map(file: File) -> io::Result<Map> {
|
||||
windows::Win32::System::Memory::CreateFileMappingA(
|
||||
HANDLE(file.as_raw_handle()),
|
||||
None,
|
||||
PAGE_EXECUTE_READ,
|
||||
0,
|
||||
0,
|
||||
None,
|
||||
)
|
||||
.map(Map)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
impl Map {
|
||||
pub(crate) unsafe fn view(
|
||||
&self,
|
||||
mode: Mode,
|
||||
file_offset: u64,
|
||||
size: usize,
|
||||
address: *const (),
|
||||
) -> Result<MapView, io::Error> {
|
||||
let addr = unsafe {
|
||||
windows::Win32::System::Memory::MapViewOfFileEx(
|
||||
self.0,
|
||||
match mode {
|
||||
Mode::Read => FILE_MAP_READ,
|
||||
Mode::Write => FILE_MAP_READ | FILE_MAP_COPY,
|
||||
Mode::Execute => FILE_MAP_READ | FILE_MAP_EXECUTE,
|
||||
},
|
||||
(file_offset << 32) as u32,
|
||||
file_offset as u32,
|
||||
size,
|
||||
Some(address as *const c_void),
|
||||
)
|
||||
};
|
||||
|
||||
if addr.Value.is_null() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(MapView(addr.Value as *const ()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Map {
|
||||
fn drop(&mut self) {
|
||||
let _ = unsafe { windows::Win32::Foundation::CloseHandle(self.0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(unix)]
|
||||
mod imp {
|
||||
compile_error!("no unix yet lol skill issue");
|
||||
}
|
||||
|
||||
pub(crate) use imp::*;
|
||||
10
test/example_exe.rs
Normal file
10
test/example_exe.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[panic_handler]
|
||||
fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue