mirror of
https://git.ely.my.id/Tenshi/Hi3-Patcher
synced 2026-11-04 21:46:48 +01:00
38 lines
1.8 KiB
Markdown
38 lines
1.8 KiB
Markdown
# ACE patch (Windows, clients ≤ 8.9)
|
|
|
|
Builds a patched `BH3.exe` from a capture of the clean client's
|
|
initialized state. Only `BH3.exe` is written, without a backup. 9.0+
|
|
clients use HoYoKProtect instead.
|
|
|
|
## Discovery (`ace/discovery.rs`)
|
|
|
|
Read-only; all checks must pass:
|
|
|
|
| File | Required layout |
|
|
| --- | --- |
|
|
| `BH3.exe` | 7 sections all named `.ace*`, 4 KiB section alignment, no TLS directory, entry calls the `BH3Base.dll` ordinal-1 import |
|
|
| `BH3_Data/sharedassets0.assets` | `ChannelConfig` resolves to a known region |
|
|
| `UnityPlayer.dll` | exports `UnityMain`; three writable decoder globals found via a `.text` code pattern |
|
|
| `BH3_Data/Native/UserAssembly.dll` | exports `il2cpp_get_api_table`; executable `.tvm0` section with a virtual tail larger than its raw size |
|
|
|
|
## Capture (`ace/capture.rs`, `ace/process.rs`)
|
|
|
|
After confirmation, launches the client (Windows directly; Linux via
|
|
`umu-run` + Proton) and reads its memory read-only — no injection or
|
|
protection tampering. Once the state is stable for 2 s (120 s timeout),
|
|
it captures the `.tvm0` section, the three decoder states and the
|
|
committed private executable allocations.
|
|
|
|
## Normalize and rebuild (`ace/runtime.rs`, `ace/generate.rs`)
|
|
|
|
`runtime.rs` checks the captured `.tvm0` against the original after PE
|
|
relocations, resolves `FF 25` jump slots against the captured
|
|
allocations, and emits a position-independent blob and two thunk tables.
|
|
`generate.rs` appends `.bh3code` (the `bootstrap.bin` stub, patched with
|
|
the discovered RVAs/sizes per `bootstrap.json`) and `.bh3imp` (imports,
|
|
decoder states and the runtime blob), then repoints the entry point.
|
|
|
|
A `HI3AUTO1` receipt with SHA-256 hashes of the patched image,
|
|
`UnityPlayer.dll` and `UserAssembly.dll` is appended; a repeat run that
|
|
validates it is a no-op. Written via `util::replace::verified`.
|