mirror of
https://github.com/Noratrieb/winning.git
synced 2026-01-14 17:55:02 +01:00
init
This commit is contained in:
parent
850f324c7b
commit
3319d701a3
7 changed files with 803 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use nix
|
||||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
/target
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.o
|
||||||
370
Cargo.lock
generated
Normal file
370
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,370 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "array-init"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.75"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||||
|
dependencies = [
|
||||||
|
"addr2line",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide",
|
||||||
|
"object",
|
||||||
|
"rustc-demangle",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "binrw"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81419ff39e6ed10a92a7f125290859776ced35d9a08a665ae40b23e7ca702f30"
|
||||||
|
dependencies = [
|
||||||
|
"array-init",
|
||||||
|
"binrw_derive",
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "binrw_derive"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "376404e55ec40d0d6f8b4b7df3f87b87954bd987f0cf9a7207ea3b6ea5c9add4"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"owo-colors",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color-eyre"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"color-spantrace",
|
||||||
|
"eyre",
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
"owo-colors",
|
||||||
|
"tracing-error",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color-spantrace"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"owo-colors",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-error",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eyre"
|
||||||
|
version = "0.6.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
|
||||||
|
dependencies = [
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.31.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indenter"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.172"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||||
|
dependencies = [
|
||||||
|
"adler2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.36.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "owo-colors"
|
||||||
|
version = "4.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.95"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-error"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db"
|
||||||
|
dependencies = [
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||||
|
dependencies = [
|
||||||
|
"sharded-slab",
|
||||||
|
"thread_local",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
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.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winning"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"binrw",
|
||||||
|
"bitflags",
|
||||||
|
"color-eyre",
|
||||||
|
]
|
||||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "winning"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
binrw = "0.15.0"
|
||||||
|
bitflags = "2.9.1"
|
||||||
|
color-eyre = "0.6.4"
|
||||||
5
shell.nix
Normal file
5
shell.nix
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{ pkgs ? import <nixpkgs> { } }: pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
llvmPackages_20.clang-unwrapped
|
||||||
|
];
|
||||||
|
}
|
||||||
414
src/main.rs
Normal file
414
src/main.rs
Normal file
|
|
@ -0,0 +1,414 @@
|
||||||
|
use std::{
|
||||||
|
ffi::CStr,
|
||||||
|
fmt::Debug,
|
||||||
|
io::{self, Write},
|
||||||
|
str::Utf8Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use binrw::{BinRead, BinWrite};
|
||||||
|
use color_eyre::{
|
||||||
|
Result,
|
||||||
|
eyre::{Context, bail},
|
||||||
|
};
|
||||||
|
|
||||||
|
const MSDOS_STUB: &[u8] = include_bytes!("msdos-stub.bin");
|
||||||
|
|
||||||
|
#[derive(Debug, BinRead, BinWrite)]
|
||||||
|
#[br(little)]
|
||||||
|
#[bw(little)]
|
||||||
|
#[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,
|
||||||
|
#[br(map = |val: u16| Characteristics::from_bits_retain(val))]
|
||||||
|
#[bw(map = |val| val.bits())]
|
||||||
|
characteristics: Characteristics,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BinWrite)]
|
||||||
|
#[bw(little)]
|
||||||
|
#[bw(magic = b"\x0b\x02")]
|
||||||
|
#[repr(C)]
|
||||||
|
struct OptionalHeader {
|
||||||
|
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: u16,
|
||||||
|
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(Default, BinWrite)]
|
||||||
|
#[bw(little)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct DataDirectory {
|
||||||
|
virtual_address: u32,
|
||||||
|
size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct SectionFlags: u32 {
|
||||||
|
/// 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_TYPE_NO_PAD = 0x00000008;
|
||||||
|
/// The section contains executable code.
|
||||||
|
const IMAGE_SCN_CNT_CODE = 0x00000020;
|
||||||
|
/// The section contains initialized data.
|
||||||
|
const IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
|
||||||
|
/// The section contains uninitialized data.
|
||||||
|
const IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080;
|
||||||
|
/// Reserved for future use.
|
||||||
|
const IMAGE_SCN_LNK_OTHER = 0x00000100;
|
||||||
|
/// The section contains comments or other information. The .drectve section has this type. This is valid for object files only.
|
||||||
|
const IMAGE_SCN_LNK_INFO = 0x00000200;
|
||||||
|
/// The section will not become part of the image. This is valid only for object files.
|
||||||
|
const IMAGE_SCN_LNK_REMOVE = 0x00000800;
|
||||||
|
/// The section contains COMDAT data. For more information, see COMDAT Sections (Object Only). This is valid only for object files.
|
||||||
|
const IMAGE_SCN_LNK_COMDAT = 0x00001000;
|
||||||
|
/// The section contains data referenced through the global pointer (GP).
|
||||||
|
const IMAGE_SCN_GPREL = 0x00008000;
|
||||||
|
/// Reserved for future use.
|
||||||
|
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;
|
||||||
|
/// Align data on a 1-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_1BYTES = 0x00100000;
|
||||||
|
/// Align data on a 2-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_2BYTES = 0x00200000;
|
||||||
|
/// Align data on a 4-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_4BYTES = 0x00300000;
|
||||||
|
/// Align data on an 8-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_8BYTES = 0x00400000;
|
||||||
|
/// Align data on a 16-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_16BYTES = 0x00500000;
|
||||||
|
/// Align data on a 32-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_32BYTES = 0x00600000;
|
||||||
|
/// Align data on a 64-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_64BYTES = 0x00700000;
|
||||||
|
/// Align data on a 128-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_128BYTES = 0x00800000;
|
||||||
|
/// Align data on a 256-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_256BYTES = 0x00900000;
|
||||||
|
/// Align data on a 512-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_512BYTES = 0x00A00000;
|
||||||
|
/// Align data on a 1024-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000;
|
||||||
|
/// Align data on a 2048-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000;
|
||||||
|
/// Align data on a 4096-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000;
|
||||||
|
/// Align data on an 8192-byte boundary. Valid only for object files.
|
||||||
|
const IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000;
|
||||||
|
/// The section contains extended relocations.
|
||||||
|
const IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
|
||||||
|
/// The section can be discarded as needed.
|
||||||
|
const IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
|
||||||
|
/// The section cannot be cached.
|
||||||
|
const IMAGE_SCN_MEM_NOT_CACHED = 0x04000000;
|
||||||
|
/// The section is not pageable.
|
||||||
|
const IMAGE_SCN_MEM_NOT_PAGED = 0x08000000;
|
||||||
|
/// The section can be shared in memory.
|
||||||
|
const IMAGE_SCN_MEM_SHARED = 0x10000000;
|
||||||
|
/// The section can be executed as code.
|
||||||
|
const IMAGE_SCN_MEM_EXECUTE = 0x20000000;
|
||||||
|
/// The section can be read.
|
||||||
|
const IMAGE_SCN_MEM_READ = 0x40000000;
|
||||||
|
/// The section can be written to.
|
||||||
|
const IMAGE_SCN_MEM_WRITE = 0x80000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const IMAGE_SUBSYSTEM_WINDOWS_CUI: u16 = 3;
|
||||||
|
|
||||||
|
#[derive(Debug, BinRead, BinWrite)]
|
||||||
|
#[br(little)]
|
||||||
|
#[bw(little)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct SectionHeader {
|
||||||
|
#[br(try_map = |val: [u8; 8]| parse_section_header_name(val))]
|
||||||
|
#[bw(map = |val| encode_section_header_name(val))]
|
||||||
|
name: String,
|
||||||
|
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,
|
||||||
|
#[br(map = |val: u32| SectionFlags::from_bits_retain(val))]
|
||||||
|
#[bw(map = |val| val.bits())]
|
||||||
|
characteristics: SectionFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
|
||||||
|
|
||||||
|
#[derive(Debug, BinRead)]
|
||||||
|
#[br(little)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct SymbolTableEntry {
|
||||||
|
name: SymbolName,
|
||||||
|
value: u32,
|
||||||
|
section_number: u16,
|
||||||
|
r#type: u16,
|
||||||
|
storage_class: u8,
|
||||||
|
number_of_aux_symbols: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BinRead)]
|
||||||
|
#[br(little)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct SymbolName {
|
||||||
|
bytes: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SymbolNameRepr {
|
||||||
|
Short(String),
|
||||||
|
Long(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymbolName {
|
||||||
|
fn repr(&self) -> Result<SymbolNameRepr, Utf8Error> {
|
||||||
|
if self.bytes[..4].iter().all(|&v| v == 0) {
|
||||||
|
Ok(SymbolNameRepr::Long(u32::from_le_bytes(
|
||||||
|
self.bytes[4..].try_into().unwrap(),
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(SymbolNameRepr::Short(parse_section_header_name(
|
||||||
|
self.bytes,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for SymbolName {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self.repr() {
|
||||||
|
Ok(SymbolNameRepr::Short(name)) => write!(f, "{name:?}"),
|
||||||
|
Ok(SymbolNameRepr::Long(offset)) => f
|
||||||
|
.debug_struct("SymbolName")
|
||||||
|
.field("offset", &offset)
|
||||||
|
.finish(),
|
||||||
|
Err(err) => f.debug_struct("SymbolName").field("err", &err).finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let objects = std::env::args().skip(1);
|
||||||
|
|
||||||
|
for obj in objects {
|
||||||
|
process_object(&obj).wrap_err_with(|| format!("reading {obj}"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_object(path: &str) -> Result<()> {
|
||||||
|
let mut outfile_buf = Vec::<u8>::new();
|
||||||
|
let outfile = &mut io::Cursor::new(&mut outfile_buf);
|
||||||
|
|
||||||
|
let file = std::fs::read(&path)?;
|
||||||
|
let header = CoffHeader::read(&mut io::Cursor::new(&file))?;
|
||||||
|
dbg!(&header);
|
||||||
|
|
||||||
|
let string_table_start = header.pointer_to_symbol_table
|
||||||
|
+ header.number_of_symbols * 18;
|
||||||
|
|
||||||
|
if header.machine != IMAGE_FILE_MACHINE_AMD64 {
|
||||||
|
bail!("object file is not x86-64");
|
||||||
|
}
|
||||||
|
if header.size_of_optional_header > 0 {
|
||||||
|
bail!("COFF object has optional header");
|
||||||
|
}
|
||||||
|
|
||||||
|
outfile.write_all(MSDOS_STUB)?;
|
||||||
|
|
||||||
|
CoffHeader {
|
||||||
|
machine: IMAGE_FILE_MACHINE_AMD64,
|
||||||
|
number_of_sections: 0,
|
||||||
|
time_date_stamp: 0,
|
||||||
|
pointer_to_symbol_table: 0,
|
||||||
|
number_of_symbols: 0,
|
||||||
|
size_of_optional_header: size_of::<OptionalHeader>().try_into().unwrap(),
|
||||||
|
characteristics: Characteristics::IMAGE_FILE_EXECUTABLE_IMAGE,
|
||||||
|
}
|
||||||
|
.write(outfile)?;
|
||||||
|
|
||||||
|
OptionalHeader {
|
||||||
|
major_linker_version: 1,
|
||||||
|
minor_linker_version: 1,
|
||||||
|
size_of_code: 0,
|
||||||
|
size_of_initialized_data: 0,
|
||||||
|
size_of_uninitialized_data: 0,
|
||||||
|
address_of_entry_point: 0,
|
||||||
|
base_of_code: 0,
|
||||||
|
image_base: 0,
|
||||||
|
section_alignment: 8,
|
||||||
|
file_alignment: 8,
|
||||||
|
major_operating_system_version: 1,
|
||||||
|
minor_operating_system_version: 1,
|
||||||
|
major_image_version: 1,
|
||||||
|
minor_image_version: 1,
|
||||||
|
major_subsystem_version: 1,
|
||||||
|
minor_subsystem_version: 1,
|
||||||
|
win32_version_value: 0,
|
||||||
|
size_of_image: 0,
|
||||||
|
size_of_headers: 0,
|
||||||
|
check_sum: 0,
|
||||||
|
subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI,
|
||||||
|
dll_characteristics: 0,
|
||||||
|
size_of_stack_reserve: 1 << 20,
|
||||||
|
size_of_stack_commit: 1 << 10,
|
||||||
|
size_of_heap_reserve: 0,
|
||||||
|
sizeof_heap_commit: 0,
|
||||||
|
loader_flags: 0,
|
||||||
|
number_of_rva_and_sizes: 16,
|
||||||
|
export_table: DataDirectory::default(),
|
||||||
|
import_table: DataDirectory::default(),
|
||||||
|
resource_table: DataDirectory::default(),
|
||||||
|
exception_table: DataDirectory::default(),
|
||||||
|
certificate_table: DataDirectory::default(),
|
||||||
|
base_relocation_table: DataDirectory::default(),
|
||||||
|
debug: DataDirectory::default(),
|
||||||
|
architecture: DataDirectory::default(),
|
||||||
|
global_ptr: DataDirectory::default(),
|
||||||
|
tls_table: DataDirectory::default(),
|
||||||
|
load_config_table: DataDirectory::default(),
|
||||||
|
bound_import: DataDirectory::default(),
|
||||||
|
iat: DataDirectory::default(),
|
||||||
|
delay_import_descriptor: DataDirectory::default(),
|
||||||
|
clr_runtime_header: DataDirectory::default(),
|
||||||
|
_reserved: DataDirectory::default(),
|
||||||
|
}
|
||||||
|
.write(outfile)?;
|
||||||
|
|
||||||
|
let cursor = &mut io::Cursor::new(&file);
|
||||||
|
cursor.set_position(size_of::<CoffHeader>() as u64);
|
||||||
|
|
||||||
|
for _ in 0..header.number_of_sections {
|
||||||
|
let section = SectionHeader::read(cursor)?;
|
||||||
|
let after_section_pos = cursor.position();
|
||||||
|
|
||||||
|
dbg!(§ion);
|
||||||
|
|
||||||
|
cursor.set_position(after_section_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.set_position(header.pointer_to_symbol_table.into());
|
||||||
|
let mut remaining_aux = 0;
|
||||||
|
for _ in 0..header.number_of_symbols {
|
||||||
|
let sym = SymbolTableEntry::read(cursor)?;
|
||||||
|
let pos = cursor.position();
|
||||||
|
|
||||||
|
if remaining_aux > 0 {
|
||||||
|
remaining_aux -= 1;
|
||||||
|
eprintln!(" AUX {sym:?}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining_aux = sym.number_of_aux_symbols;
|
||||||
|
|
||||||
|
let name = match sym.name.repr()? {
|
||||||
|
SymbolNameRepr::Short(name) => name,
|
||||||
|
SymbolNameRepr::Long(offset) => {
|
||||||
|
cursor.set_position((string_table_start + offset).into());
|
||||||
|
let name = binrw::NullString::read(cursor)?;
|
||||||
|
let len = name.len();
|
||||||
|
String::from_utf8(name.0)
|
||||||
|
.wrap_err_with(|| format!("invalid symbol long string of len {}", len))?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
eprintln!("sym: {name: <20} {sym:?}");
|
||||||
|
|
||||||
|
cursor.set_position(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::write("out.exe", outfile_buf)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_section_header_name(name: [u8; 8]) -> Result<String, Utf8Error> {
|
||||||
|
let end = name.iter().position(|&d| d == 0).unwrap_or(7);
|
||||||
|
let slice = &name[..end];
|
||||||
|
std::str::from_utf8(slice).map(ToOwned::to_owned)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_section_header_name(name: &str) -> [u8; 8] {
|
||||||
|
let mut bytes = [0; 8];
|
||||||
|
bytes[..name.len()].copy_from_slice(name.as_bytes());
|
||||||
|
bytes
|
||||||
|
}
|
||||||
BIN
src/msdos-stub.bin
Normal file
BIN
src/msdos-stub.bin
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue