Files
Senbei/web
Momoko-Ayase dc6e72a8bb Split the Exe kind into NativeExe / ManagedExe
The detector already used the CLR data-directory RVA to split DLLs into
NativeDll / ManagedDll; EXEs were a single undifferentiated Exe kind.
Apply the same CLR check to EXEs so callers can tell a protected .NET
executable from a native one without unpacking. Routing is unchanged:
both EXE kinds go to the EXE pipeline.

- CLI per-file lines and the run log now print NativeExe / ManagedExe
  (the kind comes from the same Debug formatting as the DLL variants).
- The web API's detect()/unpack_file() kind strings become
  'native-exe' / 'managed-exe'; the web UI gains matching labels, and
  the trap-retry guard (DLL-probe recovery) keys off both EXE kinds.

Golden corpus unchanged (35/35 byte-identical); kind is classification
only and never affects output bytes.
2026-08-16 05:47:16 +08:00
..
2026-08-09 00:08:31 +08:00
2026-08-09 00:08:31 +08:00
2026-08-09 00:08:31 +08:00
2026-08-09 00:08:31 +08:00
2026-08-09 00:08:31 +08:00
2026-08-09 00:08:31 +08:00
2026-08-09 00:08:31 +08:00

Senbei web

Senbei running in the browser: the unpacker core compiled to WebAssembly, wrapped in a small static page. Everything is client-side — files are read into the page, unpacked locally, and offered back as downloads. Nothing is uploaded; there is no server component.

Features

  • A legal notice is shown as a blocking dialog on page open; the tool is unusable until it is acknowledged.
  • Dropped files land in a file list, not unpacked immediately: review the batch, remove mistakes, then press Unpack. A module and its ._ companion can be dropped in any order (or in separate drops) — companions auto-pair by name (Foo.dll._Foo.dll) and show as a badge on the module's row; removing a module removes its companion too.
  • Rows show state at a glance: black while staged, an animated blue bar while unpacking, green on success (with a download button) and red on failure.
  • Drop one or more protected .exe / .dll modules → get <name>.unpack.* downloads.
  • Drop an il2cpp global-metadata.dat → de-obfuscated global-metadata.unpack.dat (only when tokens actually change).
  • Each output passes the same static integrity check as the CLI; suspect outputs are flagged with the specific defects found.

Architecture notes

  • Every unpack runs in a disposable Web Worker (fresh wasm instance per file): the UI stays responsive on 100 MB+ modules, and a wasm trap is isolated to that worker.
  • Why workers matter for correctness: the DLL-first routing probe relies on catch_unwind to reject EXE-shell-layout DLLs, and panics cannot be caught in WebAssembly — the probe traps the whole call. When a DLL unpack traps, the app retries once in a new worker with the forced-EXE pipeline (unpack_file_force_exe), reproducing the CLI's dll-first/exe-fallback outcome. Spliced companion inputs skip the probe entirely (they are always EXE-shell layout), exactly like the CLI.
  • Rust panic messages are forwarded to the browser console (console_error_panic_hook) — check devtools when reporting an issue.

Building

Requires a Rust toolchain (rust-toolchain.toml in the repo root pins one, including the wasm32-unknown-unknown target) and wasm-pack.

cd web
wasm-pack build --target web --release

This produces web/pkg/ (git-ignored). Then serve the web/ directory with any static file server and open index.html:

python -m http.server -d web 8000
:: -> http://localhost:8000

(Opening index.html via file:// won't work — ES modules require HTTP.)

Layout

web/
├── Cargo.toml     senbei-web cdylib crate (depends on the senbei lib)
├── src/lib.rs     #[wasm_bindgen] bindings: detect / unpack_file /
│                  unpack_file_force_exe / deobfuscate_metadata
├── index.html     the page
├── app.js         dropzone, file list, worker orchestration, downloads
├── worker.js      one-shot unpack worker (fresh wasm instance per file)
├── style.css
└── pkg/           wasm-pack output (git-ignored)