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).
5.1 KiB
AGENTS.md
Guidance for AI coding agents (and human contributors) working in this repo.
Project
Senbei is a static unpacker for Crackproof-protected PE files and protected
Android (AArch64) shared libraries: a Cargo workspace with a pure, panic-free,
no-I/O PE unpacker core (senbei-pe/, built on senbei-crypto/), il2cpp
metadata de-obfuscators (senbei-metadata/ for the Windows structural
variant, senbei-android-metadata/ for the Android seeded-permutation and
embedded-blob variants), the native-only Android pipeline
(senbei-android-crypto/, senbei-android-engine/, senbei-android-elf/),
filesystem/CLI orchestration (senbei-io/, including the Android
single-library/package glue in senbei-io/src/android.rs), the senbei
binary (senbei-cli/), WebAssembly bindings (senbei-wasm/, outside the
workspace; builds into web/pkg/), and the static browser frontend assets
(web/). Read docs/design.md first.
Commands
cargo build --release :: CLI (default member: senbei-cli)
cargo test --release --workspace :: full suite (golden corpus: samples/, git-ignored)
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all
cd senbei-wasm && wasm-pack build --target web --release --out-dir ../web/pkg :: browser build
The samples/ corpus is user-managed and absent on CI; without it the
samples test is a no-op pass. SENBEI_REQUIRE_SAMPLES=1 makes an absent
corpus fail (use this on a private CI that does have the corpus). The
Android corpus lives in samples/android/ (one extracted app tree per
subdirectory) and is covered by tests/android_samples.rs;
SENBEI_ANDROID_SAMPLES overrides that location. Do not
delete samples/ with rm -rf — it may be a junction; use git
worktree-aware cleanup.
Hard rules
- The PE unpacker core stays pure:
senbei-peandsenbei-cryptohave no file I/O, nounsafe, no panics across the public boundary, no platform-specific code. Everythingsenbei-wasmcompiles must keep building forwasm32-unknown-unknown(cargo check --target wasm32-unknown-unknownat the workspace root covers it — the Android crates do compile to wasm, but nothing on the wasm path calls them). - The Android crates are native-only orchestration-style crates:
senbei-android-engine/senbei-android-elfmemory-map inputs and write a module workspace to disk (the restore is a two-phase design consuming that workspace). Keep them off the web app's code paths;senbei-io'sandroid.rsis the only caller the CLI uses. catch_unwinddoes not work on wasm (the prebuilt std can't unwind; a caught panic becomes a fatalunreachabletrap). Native code may rely oncatch_unpack, but any routing decision must also work without a catchable panic: spliced companion inputs route straight to the EXE pipeline, and the web app isolates every unpack in a disposable Web Worker, retrying trapped DLLs withjob::unpack_bytes_force_exe. Never make correctness on wasm depend on catching a panic.- Byte-identical output is the contract. Any pipeline change must re-run the full golden corpus; a byte mismatch on any golden is a regression.
- Trial-and-validate, never trust a heuristic. A silently wrong offset produces a silently broken binary — worse than an error. Every layout candidate must be validated (checksum / structural oracle) with fall-through to the next candidate.
- Determinism under parallelism. Block fan-out must stay byte-identical
regardless of thread count (
SENBEI_THREADS=1is the sequential reference). - Folder scanning: deny-list, never allow-list. Targets are recognised by content, not extension, and can carry arbitrary names — there is no closed set of target extensions an allow-list could enumerate. Only known bulk-asset formats are excluded.
- No binaries in the repo — not as fixtures, not in commits. The only
corpus is the local git-ignored
samples/. (Issue attachments of protected inputs are fine when the user is authorized to share them, but never commit them.)
Public-repo hygiene (important)
This is a public research repository. In code comments, docs, tests, and commit messages:
- Never name specific games, publishers, or product codenames. Refer to build families generically ("older EXE-64 builds", "the marker-less layout", "external-companion builds"). Keep offsets/numbers — drop names.
- Never name specific protected filenames from real distributions. Test
fixtures use generic names (
app.exe,managed.dll,daemon.exe). Exceptions (platform-standard technology names, allowed):il2cpp,Unity,global-metadata.dat, the Crackproof magicKONN. - Never reference other tools, projects, implementations, or paths outside this repo. Describe behavior and layout directly; do not mention prior art, porting, or where any algorithm came from.
Conventions
- Comments explain why (layout rationale, observed variants, failure modes), not what.
- Rust 2024 edition; clippy-clean at
-D warnings; rustfmt default style. - CLI behavior (flags, exit codes, output naming) is documented in
docs/usage.md— update the doc when changing behavior.