Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

exe_packer

A single-file, self-extracting executable packer for Windows. It bundles a folder of files into one .exe that, when run, decompresses everything to a temporary directory, launches a configured entry point, waits for it to finish, and cleans up after itself.

Typical use: ship an application plus all its loose dependencies (DLLs, data files, a setup script, etc.) as a single portable .exe.

How it works

The project builds two binaries from one crate:

Binary Source Role
pack src/bin/pack.rs Compresses packer_files/ into data.bin.
stub src/main.rs The self-extractor. Embeds data.bin and runs it.

The build is a two-step process because the stub embeds the payload at compile time:

  1. Packpack walks the input directory, brotli-compresses every file in parallel (with an MD5 digest per file), and writes them into data.bin in the binary format documented in src/format.rs.
  2. Compilestub pulls in data.bin via include_bytes!, so it must be built after data.bin exists. At runtime the stub verifies each file's MD5, extracts to %TEMP%\exe_packer_run, launches the entry point, waits for it to close, and then removes the temp directory once no extracted files are still locked.

The final .exe is renamed to <name>.exe from the config and requests administrator elevation (set in build.rs).

Requirements

  • Windows (uses the Win32 manifest, cmd, and winres — this is Windows-only).
  • Rust toolchain with the x86_64-pc-windows-msvc target (install via rustup).
  • assets/logo.ico (optional)build.rs embeds this as the exe icon. If it's missing, the build generates a plain placeholder icon automatically (and prints a warning), so a fresh clone builds without extra setup. Drop in your own assets/logo.ico for a custom icon.

Quick start

  1. Create the input folder and drop in everything you want to bundle:

    packer_files/
      run.exe
      some.dll
      data/config.json
    
  2. (Optional) Add an icon at assets/logo.ico. If you skip this, a placeholder icon is generated automatically at build time.

  3. Configure packer.toml:

    name = "Application"      # output exe name + version info + SmartScreen name
    entry_point = "run.exe"   # the file (relative to packer_files/) to launch
    brotli_level = 11         # 0-11, higher = smaller + slower
    input_dir = "packer_files"
    output = "data.bin"
    show_console = true       # true = show a window, false = run hidden (GUI apps)
    powershell = "windows"    # host for a .ps1 entry point: "windows" (5.1) or "pwsh" (7+)
  4. Build. Run the interactive menu:

    build.bat
    

    or directly:

    powershell -ExecutionPolicy Bypass -File build.ps1
    

    Choose Full Build to pack and compile in one go. The finished Application.exe (named after name) is written to the project root.

Building manually

If you'd rather skip the menu:

cargo run --bin pack            # step 1: writes data.bin
cargo build --release --bin stub   # step 2: compiles the self-extractor

The stub lands at target/release/stub.exe; rename/copy it as you like.

The build menu

build.ps1 provides a small keyboard-driven menu:

  • Build Type — Full Build / Pack Only / Compile Only
  • Profile — Release / Dev
  • Clean — Build / Clean + Build
  • C show config, E edit config, F open packer_files, R reset name/entry_point/show_console, Q quit

Configuration reference

All settings live in packer.toml:

Key Default Meaning
name Application Output exe filename, embedded product/version info.
entry_point run.exe File launched after extraction (relative to input_dir). Can be an .exe, .bat, or .ps1.
brotli_level 11 Brotli quality, 0–11.
input_dir packer_files Folder whose contents get bundled.
output data.bin Intermediate payload path.
show_console true true shows a terminal window (CLI apps/scripts); false runs the entry point hidden with no window (GUI apps/scripts).
powershell windows Which host runs a .ps1 entry point: windows = Windows PowerShell 5.1 (powershell.exe), pwsh = PowerShell 7+ (pwsh.exe). Ignored for .exe/.bat.

Entry point types

  • .exe — launched directly.
  • .bat / .cmd — run through cmd.
  • .ps1 — run through <host> -ExecutionPolicy Bypass -File, so PowerShell scripts work as a first-class entry point (double-clicking a .ps1 normally opens an editor instead of running it — the stub handles this for you). The powershell setting picks the host: windows for Windows PowerShell 5.1 or pwsh for PowerShell 7+. Use pwsh if your script relies on 7+ syntax or modules — but note pwsh.exe isn't installed by default, so the target machine must have it.

Use show_console = false for a .ps1 (or .exe) that puts up its own GUI, so no PowerShell/console window flashes behind it. Keep it true for console scripts whose output you want to see. Because this setting is baked into the stub at compile time, changing it requires recompiling (Full Build or Compile Only).

Runtime behavior & troubleshooting

  • The stub (the extractor itself) always runs hidden and requires administrator elevation. Whether the launched entry point shows a window is controlled by show_console.
  • Extraction target: %TEMP%\exe_packer_run.
  • A log is written to %TEMP%\exe_packer_stub.log on every run — check it first if a packed exe misbehaves (it records extraction, the resolved entry point, passed arguments, exit code, and cleanup).
  • Arguments passed to the packed exe are forwarded to the entry point.
  • Cleanup waits (polling up to 12 hours) until no extracted .exe/.dll/.sys files are still locked, so the temp dir isn't removed out from under a running app.

Repository layout

src/main.rs        stub / self-extractor (the runtime)
src/bin/pack.rs    packer (builds data.bin)
src/format.rs      shared data.bin binary format + parser
build.rs           embeds icon, version info, admin manifest
build.ps1          interactive build menu
build.bat          launches build.ps1
packer.toml        configuration
pack_bin.py        reference Python packer (extra: partial/merge/list modes)

pack_bin.py is a standalone Python implementation of the same format. It isn't part of the Rust build, but it's handy for inspecting a bin (python pack_bin.py --list data.bin) or for advanced workflows like caching dependencies separately and merging partials.

Note for contributors

packer_files/, assets/, and data.bin are gitignored — they're user-supplied payload, not source. To produce a working packed exe you'll:

  1. create packer_files/ with at least one file, and
  2. run a pack (or a Full Build) to generate data.bin.

assets/logo.ico is optional — if absent, a placeholder icon is generated at build time. A Full Build does both the pack and the compile in one step.

About

Wraps anything (bat, exe, files) into a single self-extracting exe

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages