mirror of
https://github.com/Momoko-Ayase/Senbei.git
synced 2026-09-19 03:57:59 -04:00
Adds the Android protection-scheme pipeline: hollowed ELF64/AArch64 libraries are restored statically (stage-1/stage-2 module extraction, container decode, dynamic-linker table rebuild), with app-package (.apk/.apks/.xapk) container handling, cross-source content dedup, and il2cpp metadata support for the Android variants (seeded RID permutation; embedded XOR-wrapped blob extraction). The single senbei CLI now routes single .so files, packages, and folders by content; outputs follow the existing .unpack-infix naming under <root>/unpack or --out. PE behavior is unchanged (35/35 goldens).
164 lines
7.7 KiB
Markdown
164 lines
7.7 KiB
Markdown
# Usage
|
|
|
|
```
|
|
senbei <file|folder> [--out DIR] [-v|--verbose] [-q|--quiet]... [--scan-all]
|
|
[--no-log] [--no-pause] [-V|--version] [-h|--help]
|
|
```
|
|
|
|
Real runs print `Senbei <version>` once at start. Use `-V` / `--version` to
|
|
print the version and exit.
|
|
|
|
## Single file
|
|
|
|
The decrypted image is written under `<parent>/unpack/` with `.unpack` inserted
|
|
before the extension. A `senbei-<timestamp>.log` is written in the same
|
|
directory. With `--out DIR`, both the output and the log go into `DIR` instead:
|
|
|
|
```cmd
|
|
senbei app.exe
|
|
:: -> unpack\app.unpack.exe
|
|
:: -> unpack\senbei-YYYYMMDD-HHMMSS.log
|
|
|
|
senbei app.exe --out C:\out
|
|
:: -> C:\out\app.unpack.exe
|
|
:: -> C:\out\senbei-YYYYMMDD-HHMMSS.log
|
|
```
|
|
|
|
Pointing senbei directly at an il2cpp `global-metadata.dat` rewrites its
|
|
obfuscated method tokens back to the contiguous per-module range il2cpp
|
|
expects; the output is `global-metadata.unpack.dat`, written only when tokens
|
|
actually changed. Only metadata format version 31 is rewritten; other versions
|
|
are reported and left untouched.
|
|
|
|
## Android targets
|
|
|
|
Senbei also restores Android (AArch64) protected shared libraries and app
|
|
packages:
|
|
|
|
- **`.so`** — a protected library is hollowed out on disk: its original
|
|
sections live in an encrypted payload appended to the file, and senbei
|
|
rebuilds the static image from it. Output: `libil2cpp.unpack.so`.
|
|
- **`.apk`** — entries are extracted to a temporary workspace and
|
|
content-probed like loose files; protected libraries and metadata blobs
|
|
inside are restored to `<out>/<apk name>/<entry path>`.
|
|
- **`.apks` / `.xapk`** — split-package bundles; each nested `.apk` is opened
|
|
and searched the same way, under `<out>/<bundle name>/<split name>/...`.
|
|
|
|
When a restored il2cpp library carries its metadata embedded in its data
|
|
section (no standalone `global-metadata.dat` in the app at all), senbei
|
|
unwraps the blob and writes it next to the library as
|
|
`global-metadata.unpack.dat`. One observed packaging variant wraps the blob in
|
|
a per-word XOR layer whose keys are generated at runtime and stored nowhere;
|
|
senbei ships the keystream recovered from the one build known to use it and
|
|
content-probes for it — builds with a different keystream are silently
|
|
skipped (the library itself is still fully restored).
|
|
|
|
The same content may appear loose in a folder, in its `.apk`, and in a bundle
|
|
side by side: identical content is restored once, at the loose file's
|
|
destination. A restored library is validated structurally by the restore
|
|
itself (the rebuild refuses inconsistent layouts); a protected library that
|
|
fails validation counts as an error, not a suspect.
|
|
|
|
## Folder mode
|
|
|
|
Senbei walks the directory recursively, skips any subdirectory literally named
|
|
`unpack`, and unpacks every file it recognises as protected (by content, not
|
|
extension — renamed files and `.bak` backups are still found; packages are the
|
|
one exception, recognised by extension plus the zip magic because they are
|
|
containers). Results land under `<root>/unpack/` (or `--out DIR`), mirroring
|
|
the input tree's relative paths. The run log is written **in that same out
|
|
directory**:
|
|
|
|
```cmd
|
|
senbei "C:\Games\MyGame"
|
|
:: -> C:\Games\MyGame\unpack\...
|
|
:: -> C:\Games\MyGame\unpack\senbei-YYYYMMDD-HHMMSS.log
|
|
```
|
|
|
|
Folder mode also picks up `global-metadata.dat` files and external-companion
|
|
`._` payloads: a module whose `<name>._` sibling matches its header region is
|
|
spliced with the companion automatically (no flag needed) and unpacked as one
|
|
image, with the output named for the stub.
|
|
|
|
Each file is processed in isolation: an error or panic on one file is caught,
|
|
counted, and logged, and the run continues. Folder mode finishes with a summary
|
|
line, then duration:
|
|
|
|
```
|
|
12 unpacked · 3 skipped · 0 errors · 1 suspect · 2 metadata
|
|
done in 1234 ms
|
|
```
|
|
|
|
The `packages` count appears (as `· N packages`) only when Android app
|
|
packages were processed.
|
|
|
|
## Integrity check
|
|
|
|
(PE outputs only — Android restores carry their own structural validation; see
|
|
[Android targets](#android-targets).)
|
|
|
|
A successful unpack is not always a runnable one: a layout heuristic can pick
|
|
the wrong offset and leave the entry-point stub or import strings encrypted, so
|
|
the pipeline reports success but the OS loader faults at runtime (typically
|
|
`0xC0000005`, STATUS_ACCESS_VIOLATION). To catch this, senbei runs a static
|
|
sanity check over every output it produces — inspecting the bytes alone, with
|
|
no reference image and no execution.
|
|
|
|
It flags only defects that cannot occur in a correctly unpacked image:
|
|
|
|
- malformed DOS/PE headers, bad optional-header magic, implausible section
|
|
count, zero `SizeOfImage`, or section raw-data ranges that run past EOF;
|
|
- an entry point that doesn't map into a section, isn't in an executable
|
|
section, or whose stub is all zeros or all `0xCC` int3 padding (the classic
|
|
left-encrypted symptom);
|
|
- a native (unmanaged) DLL with no base-relocation directory — it cannot
|
|
survive being mapped at a non-preferred base;
|
|
- **any** import descriptor whose DLL name doesn't resolve or isn't readable
|
|
ASCII (imports left encrypted) — the whole table is walked, not just the
|
|
first entry;
|
|
- for a managed assembly, a COR20 header whose `cb` isn't `0x48` or a
|
|
MetaData stream missing its `BSJB` signature (the CLR would reject the
|
|
image outright).
|
|
|
|
The entry-point and import checks are skipped for managed assemblies, whose
|
|
native EP and import stub are legitimately not what the native loader expects.
|
|
|
|
The check is deliberately conservative: a clean report is **not** a proof of
|
|
correctness, but a non-clean report is a reliable "this is broken" signal. A
|
|
suspect file is still written (the bytes are the best available) and flagged —
|
|
single-file mode prints a warning to stderr, folder mode prints a yellow `!`
|
|
line, adds a `SUSPECT` entry to the run log, and counts it in the summary's
|
|
`suspect` total (which is additive to `unpacked`).
|
|
|
|
## Flags
|
|
|
|
| Flag | Behavior |
|
|
| --- | --- |
|
|
| `--out DIR` | Write outputs (and the log, unless `--no-log`) under `DIR`. |
|
|
| `-v`, `--verbose` | Print detailed per-stage progress (and the destination path) for each file — `[N/9]` stages for PE targets, container/segment lines for Android libraries. In folder mode this replaces the progress bar. |
|
|
| `-q`, `--quiet` | Once: hide progress bar and per-file lines; keep banner, summary, and duration. Twice (`-q -q`): suppress all stdio (exit code only). |
|
|
| `--no-log` | Do not write `senbei-*.log`. Console output is unchanged by this flag alone. |
|
|
| `--scan-all` | Probe every file in a folder, including ones the scan pre-filter skips (under 4128 bytes, or a bulk-asset extension like `.ab`/`.xml`/`.acb`). Much slower on large game trees; finds the same targets in practice. |
|
|
| `--no-pause` | Skip the "Press Enter to exit" prompt (for scripted runs). |
|
|
| `-V`, `--version` | Print `Senbei <version>` and exit. |
|
|
| `-h`, `--help` | Show usage. |
|
|
|
|
On Windows, when launched from Explorer (the process owns its console) senbei
|
|
pauses for Enter before exiting so the window doesn't vanish. `--no-pause`
|
|
disables this; it has no effect when stdout is piped or run from another
|
|
process.
|
|
|
|
## Exit codes
|
|
|
|
| Code | Meaning |
|
|
| --- | --- |
|
|
| `0` | Success (single file restored, or folder run with no errors). |
|
|
| `1` | At least one file failed, a scan probe was unreadable, or a single-file unpack errored. |
|
|
| `2` | Usage error: no path given, unknown option, missing `--out` value, or multiple input paths (help printed). |
|
|
|
|
A folder run also fails with `1` when parts of the tree could not be scanned
|
|
(unreadable directory entries or files that failed the content probe) — those
|
|
are potential missed targets, not clean skips. An il2cpp metadata blob whose
|
|
format version senbei does not handle is *not* an error: it is reported, left
|
|
untouched, and counted as skipped.
|