Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

seaextract

Extract source code from Node.js Single Executable Applications (SEA) and Bun standalone binaries — ELF (Linux) and PE (Windows).

Installation

Requires Python 3.14+.

Install from source:

git clone https://github.com/L5Z12/seaextract.git
cd seaextract
uv sync

Usage

# Extract source code from a Node.js SEA binary
seaextract myapp

# Extract to a specific directory
seaextract myapp -o output/

# Show binary info without extracting
seaextract myapp --info

# Dump raw SEA blob to stdout
seaextract myapp --raw > blob.bin

# Repack modified files back into a binary
seaextract myapp --repack output/ -o myapp.repacked

# Pack from scratch — inject a fresh SEA blob into a plain node.exe
seaextract node.exe --repack src/ --format sea -o myapp.exe

# Pack from scratch — inject a fresh Bun payload into a plain bun runtime
seaextract bun.exe --repack src/ --format bun -o myapp.exe

# SEA-only shortcut: replace just the main JS source
seaextract myapp --source patched.js -o myapp.repacked

Supported formats

Node.js SEA

  • Legacy (raw JS blob) and v2 (magic + flags) formats
  • JavaScript source extraction
  • V8 heap snapshot detection
  • Code cache extraction
  • Embedded asset extraction
  • SEA fuse state detection
  • UPX compression warning

Bun standalone

  • Module graph extraction with original file paths
  • Loader and module format metadata (ESM/CJS)
  • Entry point identification
  • Support for all Bun loader types (js, ts, jsx, tsx, json, toml, css, wasm, native, etc.)

Development

uv sync
uv run pytest
uv run ruff check .
uv run ruff format .

Repacking and packing from scratch

The --repack DIR flag reads modified files from an extracted directory and produces a new binary. It works in two modes:

  • Repack: the base binary already contains a SEA/Bun payload — used as a template so metadata (flags, code_path, module ordering, loaders, entry index) is preserved. Format is auto-detected.
  • Pack from scratch: the base binary is a plain runtime (node.exe, bun, unmodified from official downloads) with no existing payload. Pass --format {sea,bun} to disambiguate. Defaults are chosen to match what postject and bun build --compile produce.

Behaviour per (format × container):

  • PE SEA: repack in place when the new blob fits the original resource slot; otherwise rewrite the entire .rsrc resource tree and relocate the section past all others (postject's approach). The section table is re-sorted by virtual address and the vacated section is filled to keep the loader happy. The SEA fuse (:0/:1) is flipped automatically on fresh packs. Works end-to-end against a plain node.exe.
  • PE Bun: repack in place when a valid .bun section already holds a Bun standalone payload; otherwise add a new .bun section header (needs a free slot in the header page — most bun/node runtimes have that). Content goes at EOF, SizeOfImage grows to cover it. Works end-to-end against a plain bun.exe.
  • ELF Bun: repack in place when the existing .bun section already holds a standalone; otherwise (fresh bun runtime) append content, repurpose the existing .bun section header with an updated sh_offset / sh_addr, and extend the last PT_LOAD segment so the new virtual address is mapped — while preserving the original p_memsz so Bun's BSS-mapped data isn't shrunk. Writes a pointer at the original .bun file location so Bun's runtime lookup finds the payload. Works end-to-end against a plain linux bun.
  • ELF SEA: repack rewrites the containing PT_NOTE segment in place, preserving co-tenant notes (build-id, annobin, etc.) byte-for-byte. Fresh pack requires an existing PT_NOTE with enough padding to hold the new note; a plain node binary typically doesn't have that slack, so the fresh path errors out clearly. Same-size and shrink still work for repack.
  • Bun bytecode: precompiled bytecode is dropped on any Bun repack (it would be stale against modified source); Bun's runtime re-parses the JS at startup.
  • Signed binaries: repacking invalidates Authenticode signatures on PE. Trailing signature overlays are dropped from PE Bun binaries.

Limitations

  • ELF (Linux) and PE (Windows) binaries are supported. Mach-O (macOS) is not yet implemented.
  • V8 heap snapshots embedded via useSnapshot cannot be converted back to JavaScript.
  • ELF SEA fresh packing is only possible when an existing PT_NOTE segment has enough padding (~300 bytes for a minimal blob). A plain Linux node binary does not — postject handles this by extending the containing PT_LOAD, which this tool doesn't yet do.
  • Repacking SEA to a larger payload than the original resource slot on PE falls back to the fresh-pack path (which relocates .rsrc). On ELF, PT_NOTE growth is rejected with a clear error.

License

GNU General Public License 3.0. See LICENSE.

About

Extract source code from Node.js Single Executable Applications (SEA) and Bun standalone ELF binaries.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages