[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DB29M218VJDTZAPFEN1VJK":3,"skill-same:01M6DB29M218VJDTZAPFEN1VJK":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":14,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M6DB29M218VJDTZAPFEN1VJK","bc-update-survival",null,"Use when a Battle Cats (EN, jp.co.ponos.battlecatsen) update relinks lib\u002Fx86_64\u002Flibnative-lib.so and your pinned RVAs go stale — the toolpack that RETIRES hardcoded offsets. AOB wildcard-signature resolver (author a byte pattern that wildcards only the reloc-sensitive bytes, then re-locate the function by pattern via offline .so scan or live `frida search_memory`\u002FMemory.scan — survives relink where a fixed RVA does not); ghidriff one-command cross-version .so diff that AUTO-PORTS the whole offset table old→new; and a per-version-bump update-triage (extract + sha-compare + diff APK\u002FDAT\u002F.so). Ships a SHADOW-mode drift gate (observe + log only, never blocks). Use before trusting any bc-drive \u002F battlecats-event-unlock offset after a version bump. NOT for save-file edits (bcsfe-save-roundtrip) or live UI driving (bc-drive).","Prekzursil\u002Fagent-skills-toolchain","Prekzursil","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F54636077?v=4","01M6DACZ1PCQHD99SCR1YXG28B","Andrei Mihai Visalon","01M6DACZ670WZF535V3WYYSS4Z",0,"MIT","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fbc-update-survival\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"update","bc update survival","only","memory","jp","drift","scan","observe","bump","en","log","search","never","auto","diff","version","use","ports","APK","file","2026-11-10 10:12:30",false,"---\nname: bc-update-survival\ndescription: Use when a Battle Cats (EN, jp.co.ponos.battlecatsen) update relinks lib\u002Fx86_64\u002Flibnative-lib.so and your pinned RVAs go stale — the toolpack that RETIRES hardcoded offsets. AOB wildcard-signature resolver (author a byte pattern that wildcards only the reloc-sensitive bytes, then re-locate the function by pattern via offline .so scan or live `frida search_memory`\u002FMemory.scan — survives relink where a fixed RVA does not); ghidriff one-command cross-version .so diff that AUTO-PORTS the whole offset table old→new; and a per-version-bump update-triage (extract + sha-compare + diff APK\u002FDAT\u002F.so). Ships a SHADOW-mode drift gate (observe + log only, never blocks). Use before trusting any bc-drive \u002F battlecats-event-unlock offset after a version bump. NOT for save-file edits (bcsfe-save-roundtrip) or live UI driving (bc-drive).\n---\n\n# bc-update-survival — survive BC updates automatically\n\nBattle Cats ships an update, `lib\u002Fx86_64\u002Flibnative-lib.so` is recompiled and\n**relinked**, and every hardcoded RVA in your offset tables (`bc-drive`,\n`battlecats-event-unlock`) is now wrong. **Acting on a stale offset is the worst\nfailure mode** — a call to the wrong address crashes BC or trips the HGT anti-\ntamper trap. This toolpack re-derives the offsets automatically instead.\n\nThe core idea: a function's **opcodes are stable across an update even when its\naddress moves**. Pin functions by a wildcard **byte signature (AOB)** — fixing\nthe opcodes, wildcarding the bytes that move on relink (rel32 call\u002Fjump\ndisplacements, RIP-relative `disp32`, reloc'd immediates) — and re-locate them\nby pattern after every update. A signature survives; an RVA does not.\n\n## Files\n- `aob_resolver.py` — the AOB signature engine: parse\u002Fmatch, author (single-\n  version heuristic **or** robust cross-version byte-diff), offline `.so` scan,\n  live Frida `Memory.scan`, and a SHADOW drift gate.\n- `ghidriff_port.py` — cross-version `.so` diff + **auto-port the offset table**\n  (AOB re-scan, primary; ghidriff function-matching, cross-check) + the\n  version-bump `triage` orchestration (handles `.apk` inputs).\n- `SKILL.md` — this file.\n\n## BC ground truth (EN 15.4.1)\n- `lib\u002Fx86_64\u002Flibnative-lib.so` has **imagebase 0x0**, so **RVA == file offset**\n  (per `battlecats-event-unlock`). `--imagebase 0` (the default) is exact for BC;\n  runtime address = `module.base + RVA`.\n- `so_sha256 = 9605648b86c9176283f620b638f80e171b1df5731fdc3bed3295201883257676`,\n  `so_size 12 666 808`, build-id `d907e66ecce8388948f9ff4cde96a93735acbe92`.\n- **Real seed signature** — `getGlobal()` fingerprint: `48 8D 05 ?? ?? ?? ?? C3`\n  (`lea rax,[rip+disp]; ret`; the 4 `disp` bytes are wildcarded because they\n  point at a data pointer table that moves on relink). This is the exemplar the\n  whole approach is built on and is covered by the module selftest.\n\n## The offset table (single source of truth)\nA JSON file keyed by function name; each entry carries the pinned `rva` **and**\nits AOB `sig`. Save it under whichever consumer owns it (e.g.\n`tools\u002Foffsets\u002Fen-15.4.1.json`). Schema:\n\n```json\n{\n  \"so\": \"libnative-lib.so\",\n  \"version\": \"15.4.1\",\n  \"sha256\": \"9605648b86c9176283f620b638f80e171b1df5731fdc3bed3295201883257676\",\n  \"offsets\": {\n    \"getGlobal\":  { \"rva\": \"0x65D900\", \"sig\": \"48 8D 05 ?? ?? ?? ?? C3\", \"note\": \"getGlobal() -> MyApplication*\" },\n    \"getScene\":   { \"rva\": \"0x668910\", \"sig\": \"\",                        \"note\": \"author me from the pinned .so\" },\n    \"touchDispatch\": { \"rva\": \"0x668C70\", \"sig\": \"\", \"note\": \"vtable[+0x40]\" }\n  }\n}\n```\n`sig: \"\"` means \"not signatured yet\" — author it once from the pinned `.so`\n(below); thereafter every future update ports automatically by pattern.\n\n## aob_resolver.py — author & resolve signatures\n```\n# Author a bullet-proof cross-version sig by byte-diffing the SAME function in\n# two versions (needs the addr in both, e.g. from a ghidriff match). Wildcards\n# EXACTLY the bytes that differ -> matches both by construction. No disassembler.\npython aob_resolver.py author-diff old.so new.so 0x668910 0x669120 --name getScene\n\n# Author a single-version sig at an RVA (capstone if importable, else a\n# conservative rel32\u002FRIP-disp32 heuristic; extends until unique).\npython aob_resolver.py author libnative-lib.so 0x668910 --name getScene\n\n# Resolve one signature (or a whole table) against a .so -> RVA(s).\npython aob_resolver.py resolve new.so \"48 8D 05 ?? ?? ?? ?? C3\"\npython aob_resolver.py resolve new.so --table tools\u002Foffsets\u002Fen-15.4.1.json\n\n# List every match (uniqueness check).\npython aob_resolver.py scan libnative-lib.so \"48 8D 05 ?? ?? ?? ?? C3\"\n\n# Emit a Frida agent that Memory.scan's the live module for a table's sigs.\npython aob_resolver.py gen-agent tools\u002Foffsets\u002Fen-15.4.1.json --module libnative-lib.so\n```\nResolution status is `ok` (one match), `missing` (zero → relinked away \u002F bad\nsig), or `ambiguous` (>1 → sig not specific enough; re-author longer).\n\n## Live resolution (Frida `search_memory`)\nFor a running BC on rooted BlueStacks (frida-server up; see `bc-drive`):\n```\npython aob_resolver.py live jp.co.ponos.battlecatsen tools\u002Foffsets\u002Fen-15.4.1.json\n```\nThis attaches, injects the generated agent, and returns each function's live\nruntime address **and** its `rva` (addr − module base). Runtime-resolving by AOB\nmeans you never hardcode a base+RVA again — the search survives the relink at\nruntime, the same way the offline scan does on disk. (Read-only scan; no per-\nframe hook — obeys the bc-drive hot-path rule.)\n\n## ghidriff_port.py — auto-port the whole table across an update\n```\n# PRIMARY, no Ghidra: re-scan the new .so for each entry's sig, write new RVAs.\npython ghidriff_port.py port-aob tools\u002Foffsets\u002Fen-15.4.1.json new.so \\\n    --out tools\u002Foffsets\u002Fen-15.5.0.json\n#   entries lacking a sig are auto-authored from --old-so first:\npython ghidriff_port.py port-aob table.json new.so --old-so old.so --out new.json\n\n# Cross-check via ghidriff (Ghidra BinDiff-style function matching).\n#   1) produce the diff (LONG — Ghidra analysis, minutes; wrap with longrun):\npython ghidriff_port.py diff old.so new.so --out ghidriff-out\n#   2) port the table from ghidriff's matched pairs (pure logic):\npython ghidriff_port.py port-ghidriff table.json ghidriff-out\u002F*.ghidriff.json \\\n    --ghidra-base 0x100000 --out new.json\n```\n`--ghidra-base` subtracts Ghidra's load base so emitted RVAs stay file-relative\n(BC base 0x0 usually loads at Ghidra `0x100000`). The **AOB path is base-\nindependent** (it scans the raw file) — prefer it; use ghidriff to cross-check\nand to bulk-author sigs for functions you have not pinned yet.\n\n## Update-triage workflow (per version bump)\n```\n# One command: extract the .so from each APK (or pass .so directly),\n# sha-compare, and — if the native code changed — port the table via AOB\n# (and cross-check with ghidriff if --ghidriff).\npython ghidriff_port.py triage bc-15.4.1.apk bc-15.5.0.apk \\\n    --table tools\u002Foffsets\u002Fen-15.4.1.json --out tools\u002Foffsets\u002Fen-15.5.0.json\n```\n`triage` pulls `lib\u002Fx86_64\u002Flibnative-lib.so` out of the APK (an APK is a zip — no\napktool needed for the native lib), sha256-compares, and only ports when the\n`.so` actually changed (`native code UNCHANGED` → your pinned offsets are still\nvalid, zero work). Full per-bump checklist:\n\n1. **Grab both builds** — old (pinned) APK + new APK.\n2. **Native diff** (this tool) — `triage` → if unchanged, done; else it ports\n   the offset table by AOB and (optionally) cross-checks with ghidriff.\n3. **Verify moved offsets** — any `missing`\u002F`ambiguous` entry needs a re-authored\n   sig (open old+new in `ida-multi-mcp` → `similar_functions` re-finds the moved\n   function name-independently → `author-diff` a fresh cross-version sig).\n4. **Resource \u002F DAT diff** (out-of-band for offsets, in-scope for behavior) —\n   `apktool d bc-15.5.0.apk` on both, then diff `res\u002F`, `assets\u002F`, smali, and the\n   `AndroidManifest` `clientVersion`; decrypt\u002Fcompare event `DAT` packs with the\n   BC pack tooling (see `battlecats-event-unlock` for the schedule-band format).\n5. **Bump the pinned table** — save the ported table as `en-\u003Cnewver>.json`, set\n   its `version` + `sha256`, and point `bc-drive` \u002F `battlecats-event-unlock` at\n   it. Record the old version in the table `changelog` (don't delete it).\n\n## SHADOW drift gate (council C5 — never blocks, never nags)\nA safety net that catches \"you are about to act on stale offsets\":\n```\npython aob_resolver.py verify tools\u002Foffsets\u002Fen-15.4.1.json \u002Fpath\u002Fto\u002Flive\u002Flibnative-lib.so\n```\nIt re-resolves every pinned sig in the given `.so` and compares to the pinned\nRVA. Drift (a moved\u002Fmissing\u002Fambiguous function, or a changed `so_sha256`) is\n**observed and logged only** — appended to a bounded, auto-rotating sink\n(`~\u002F.claude\u002Flogs\u002Fbc-update-survival-drift.log`, cap 256 KB + one rotation;\noverride with `$BC_DRIFT_SINK`). It **always exits 0**, prints advisory `advice`,\nand never blocks or fails a caller. This is the shadow-first, reversible path the\ncouncil mandated for new gates: the loud \"offsets stale — re-port before trusting\nRVAs\" is a suggestion, not an interrupt. The companion always-on module\n`bc_offset_guard` (E.2, folded into the harness) is the graduation target; this\nskill's gate stays project-scoped and observe-only.\n\n## Requirements \u002F optional deps\n- **AOB offline path + porting + triage:** pure Python, **no third-party deps**.\n- `frida` (installed, 17.x) — only for the `live` backend + a running device.\n- `capstone` (optional) — sharpens single-version `author`; the byte heuristic is\n  the fallback and matches the real getGlobal sig.\n- `pyelftools` (optional, installed) — sharpens `--elf-sections` for a general\n  ELF; unnecessary for BC (imagebase 0 → RVA == offset).\n- `ghidriff` (installed, 1.0.0) + `GHIDRA_INSTALL_DIR` — only for `diff` \u002F\n  `port-ghidriff`; missing toolchain degrades gracefully to the AOB path.\n\n## Verify it works\nBoth modules ship a real offline selftest (no device needed):\n```\npython aob_resolver.py selftest     # 27 checks incl. the relink-survival proof\npython ghidriff_port.py selftest    # 21 checks incl. AOB + ghidriff + APK triage\n```\nThe keystone check builds two synthetic `.so`s where a function is relinked to a\nnew offset, authors a signature on v1, and proves it re-locates the function at\nits new address in v2 — the whole reason the toolpack exists.\n\n## Safety & honest limits\n- **Read-only \u002F additive.** Scans files and (read-only) live memory; never writes\n  the game, never patches, never spends currency. The drift gate never blocks.\n- **AOB is only as good as the sig.** A too-short sig → `ambiguous`; over-\n  wildcarding → `ambiguous`; under-wildcarding a reloc byte → breaks on relink.\n  `author-diff` (byte-diff of two known versions) is bullet-proof; the single-\n  version heuristic is best-effort (prefer capstone, and always verify uniqueness\n  with `scan`).\n- **ghidriff addresses carry Ghidra's image base** — use `--ghidra-base`. The AOB\n  path avoids this entirely.\n- **Not a decompiler \u002F not a save editor \u002F not a UI driver.** Pair with:\n  `game-re-binary`, `ida-multi-mcp` (BCSD re-find), `ghidra-mcp`, `frida` (RE);\n  `bc-drive` (live canvas driving); `battlecats-event-unlock` (event offsets);\n  `bcsfe-save-roundtrip` (saves).\n\n## Evidence\nMASTER-DECISION-QUEUE §E.2 (V×E H×M, BUILD, verified): \"AOB wildcard-signature\nresolver (retire hardcoded RVAs; survive relink via `frida search_memory`) ·\nghidriff (one-command cross-version `.so` diff → auto-port the offset table) · BC\nupdate-triage skill (decode+diff APK\u002FDAT\u002F.so per version bump).\" Shadow-gate\ndiscipline per COUNCIL-VERDICT §C5. BC ground truth from `battlecats-event-unlock`\n+ `bc-drive` (both EN 15.4.1, x86_64, imagebase 0).\n","# bc-update-survival — survive BC updates automatically\n\nBattle Cats ships an update, `lib\u002Fx86_64\u002Flibnative-lib.so` is recompiled and\n**relinked**, and every hardcoded RVA in your offset tables (`bc-drive`,\n`battlecats-event-unlock`) is now wrong. **Acting on a stale offset is the worst\nfailure mode** — a call to the wrong address crashes BC or trips the HGT anti-\ntamper trap. This toolpack re-derives the offsets automatically instead.\n\nThe core idea: a function's **opcodes are stable across an update even when its\naddress moves**. Pin functions by a wildcard **byte signature (AOB)** — fixing\nthe opcodes, wildcarding the bytes that move on relink (rel32 call\u002Fjump\ndisplacements, RIP-relative `disp32`, reloc'd immediates) — and re-locate them\nby pattern after every update. A signature survives; an RVA does not.\n\n## Files\n- `aob_resolver.py` — the AOB signature engine: parse\u002Fmatch, author (single-\n  version heuristic **or** robust cross-version byte-diff), offline `.so` scan,\n  live Frida `Memory.scan`, and a SHADOW drift gate.\n- `ghidriff_port.py` — cross-version `.so` diff + **auto-port the offset table**\n  (AOB re-scan, primary; ghidriff function-matching, cross-check) + the\n  version-bump `triage` orchestration (handles `.apk` inputs).\n- `SKILL.md` — this file.\n\n## BC ground truth (EN 15.4.1)\n- `lib\u002Fx86_64\u002Flibnative-lib.so` has **imagebase 0x0**, so **RVA == file offset**\n  (per `battlecats-event-unlock`). `--imagebase 0` (the default) is exact for BC;\n  runtime address = `module.base + RVA`.\n- `so_sha256 = 9605648b86c9176283f620b638f80e171b1df5731fdc3bed3295201883257676`,\n  `so_size 12 666 808`, build-id `d907e66ecce8388948f9ff4cde96a93735acbe92`.\n- **Real seed signature** — `getGlobal()` fingerprint: `48 8D 05 ?? ?? ?? ?? C3`\n  (`lea rax,[rip+disp]; ret`; the 4 `disp` bytes are wildcarded because they\n  point at a data pointer table that moves on relink). This is the exemplar the\n  whole approach is built on and is covered by the module selftest.\n\n## The offset table (single source of truth)\nA JSON file keyed by function name; each entry carries the pinned `rva` **and**\nits AOB `sig`. Save it under whichever consumer owns it (e.g.\n`tools\u002Foffsets\u002Fen-15.4.1.json`). Schema:\n\n```json\n{\n  \"so\": \"libnative-lib.so\",\n  \"version\": \"15.4.1\",\n  \"sha256\": \"9605648b86c9176283f620b638f80e171b1df5731fdc3bed3295201883257676\",\n  \"offsets\": {\n    \"getGlobal\":  { \"rva\": \"0x65D900\", \"sig\": \"48 8D 05 ?? ?? ?? ?? C3\", \"note\": \"getGlobal() -> MyApplication*\" },\n    \"getScene\":   { \"rva\": \"0x668910\", \"sig\": \"\",                        \"note\": \"author me from the pinned .so\" },\n    \"touchDispatch\": { \"rva\": \"0x668C70\", \"sig\": \"\", \"note\": \"vtable[+0x40]\" }\n  }\n}\n```\n`sig: \"\"` means \"not signatured yet\" — author it once from the pinned `.so`\n(below); thereafter every future update ports automatically by pattern.\n\n## aob_resolver.py — author & resolve signatures\n```\n# Author a bullet-proof cross-version sig by byte-diffing the SAME function in\n# two versions (needs the addr in both, e.g. from a ghidriff match). Wildcards\n# EXACTLY the bytes that differ -> matches both by construction. No disassembler.\npython aob_resolver.py author-diff old.so new.so 0x668910 0x669120 --name getScene\n\n# Author a single-version sig at an RVA (capstone if importable, else a\n# conservative rel32\u002FRIP-disp32 heuristic; extends until unique).\npython aob_resolver.py author libnative-lib.so 0x668910 --name getScene\n\n# Resolve one signature (or a whole table) against a .so -> RVA(s).\npython aob_resolver.py resolve new.so \"48 8D 05 ?? ?? ?? ?? C3\"\npython aob_resolver.py resolve new.so --table tools\u002Foffsets\u002Fen-15.4.1.json\n\n# List every match (uniqueness check).\npython aob_resolver.py scan libnative-lib.so \"48 8D 05 ?? ?? ?? ?? C3\"\n\n# Emit a Frida agent that Memory.scan's the live module for a table's sigs.\npython aob_resolver.py gen-agent tools\u002Foffsets\u002Fen-15.4.1.json --module libnative-lib.so\n```\nResolution status is `ok` (one match), `missing` (zero → relinked away \u002F bad\nsig), or `ambiguous` (>1 → sig not specific enough; re-author longer).\n\n## Live resolution (Frida `search_memory`)\nFor a running BC on rooted BlueStacks (frida-server up; see `bc-drive`):\n```\npython aob_resolver.py live jp.co.ponos.battlecatsen tools\u002Foffsets\u002Fen-15.4.1.json\n```\nThis attaches, injects the generated agent, and returns each function's live\nruntime address **and** its `rva` (addr − module base). Runtime-resolving by AOB\nmeans you never hardcode a base+RVA again — the search survives the relink at\nruntime, the same way the offline scan does on disk. (Read-only scan; no per-\nframe hook — obeys the bc-drive hot-path rule.)\n\n## ghidriff_port.py — auto-port the whole table across an update\n```\n# PRIMARY, no Ghidra: re-scan the new .so for each entry's sig, write new RVAs.\npython ghidriff_port.py port-aob tools\u002Foffsets\u002Fen-15.4.1.json new.so \\\n    --out tools\u002Foffsets\u002Fen-15.5.0.json\n#   entries lacking a sig are auto-authored from --old-so first:\npython ghidriff_port.py port-aob table.json new.so --old-so old.so --out new.json\n\n# Cross-check via ghidriff (Ghidra BinDiff-style function matching).\n#   1) produce the diff (LONG — Ghidra analysis, minutes; wrap with longrun):\npython ghidriff_port.py diff old.so new.so --out ghidriff-out\n#   2) port the table from ghidriff's matched pairs (pure logic):\npython ghidriff_port.py port-ghidriff table.json ghidriff-out\u002F*.ghidriff.json \\\n    --ghidra-base 0x100000 --out new.json\n```\n`--ghidra-base` subtracts Ghidra's load base so emitted RVAs stay file-relative\n(BC base 0x0 usually loads at Ghidra `0x100000`). The **AOB path is base-\nindependent** (it scans the raw file) — prefer it; use ghidriff to cross-check\nand to bulk-author sigs for functions you have not pinned yet.\n\n## Update-triage workflow (per version bump)\n```\n# One command: extract the .so from each APK (or pass .so directly),\n# sha-compare, and — if the native code changed — port the table via AOB\n# (and cross-check with ghidriff if --ghidriff).\npython ghidriff_port.py triage bc-15.4.1.apk bc-15.5.0.apk \\\n    --table tools\u002Foffsets\u002Fen-15.4.1.json --out tools\u002Foffsets\u002Fen-15.5.0.json\n```\n`triage` pulls `lib\u002Fx86_64\u002Flibnative-lib.so` out of the APK (an APK is a zip — no\napktool needed for the native lib), sha256-compares, and only ports when the\n`.so` actually changed (`native code UNCHANGED` → your pinned offsets are still\nvalid, zero work). Full per-bump checklist:\n\n1. **Grab both builds** — old (pinned) APK + new APK.\n2. **Native diff** (this tool) — `triage` → if unchanged, done; else it ports\n   the offset table by AOB and (optionally) cross-checks with ghidriff.\n3. **Verify moved offsets** — any `missing`\u002F`ambiguous` entry needs a re-authored\n   sig (open old+new in `ida-multi-mcp` → `similar_functions` re-finds the moved\n   function name-independently → `author-diff` a fresh cross-version sig).\n4. **Resource \u002F DAT diff** (out-of-band for offsets, in-scope for behavior) —\n   `apktool d bc-15.5.0.apk` on both, then diff `res\u002F`, `assets\u002F`, smali, and the\n   `AndroidManifest` `clientVersion`; decrypt\u002Fcompare event `DAT` packs with the\n   BC pack tooling (see `battlecats-event-unlock` for the schedule-band format).\n5. **Bump the pinned table** — save the ported table as `en-\u003Cnewver>.json`, set\n   its `version` + `sha256`, and point `bc-drive` \u002F `battlecats-event-unlock` at\n   it. Record the old version in the table `changelog` (don't delete it).\n\n## SHADOW drift gate (council C5 — never blocks, never nags)\nA safety net that catches \"you are about to act on stale offsets\":\n```\npython aob_resolver.py verify tools\u002Foffsets\u002Fen-15.4.1.json \u002Fpath\u002Fto\u002Flive\u002Flibnative-lib.so\n```\nIt re-resolves every pinned sig in the given `.so` and compares to the pinned\nRVA. Drift (a moved\u002Fmissing\u002Fambiguous function, or a changed `so_sha256`) is\n**observed and logged only** — appended to a bounded, auto-rotating sink\n(`~\u002F.claude\u002Flogs\u002Fbc-update-survival-drift.log`, cap 256 KB + one rotation;\noverride with `$BC_DRIFT_SINK`). It **always exits 0**, prints advisory `advice`,\nand never blocks or fails a caller. This is the shadow-first, reversible path the\ncouncil mandated for new gates: the loud \"offsets stale — re-port before trusting\nRVAs\" is a suggestion, not an interrupt. The companion always-on module\n`bc_offset_guard` (E.2, folded into the harness) is the graduation target; this\nskill's gate stays project-scoped and observe-only.\n\n## Requirements \u002F optional deps\n- **AOB offline path + porting + triage:** pure Python, **no third-party deps**.\n- `frida` (installed, 17.x) — only for the `live` backend + a running device.\n- `capstone` (optional) — sharpens single-version `author`; the byte heuristic is\n  the fallback and matches the real getGlobal sig.\n- `pyelftools` (optional, installed) — sharpens `--elf-sections` for a general\n  ELF; unnecessary for BC (imagebase 0 → RVA == offset).\n- `ghidriff` (installed, 1.0.0) + `GHIDRA_INSTALL_DIR` — only for `diff` \u002F\n  `port-ghidriff`; missing toolchain degrades gracefully to the AOB path.\n\n## Verify it works\nBoth modules ship a real offline selftest (no device needed):\n```\npython aob_resolver.py selftest     # 27 checks incl. the relink-survival proof\npython ghidriff_port.py selftest    # 21 checks incl. AOB + ghidriff + APK triage\n```\nThe keystone check builds two synthetic `.so`s where a function is relinked to a\nnew offset, authors a signature on v1, and proves it re-locates the function at\nits new address in v2 — the whole reason the toolpack exists.\n\n## Safety & honest limits\n- **Read-only \u002F additive.** Scans files and (read-only) live memory; never writes\n  the game, never patches, never spends currency. The drift gate never blocks.\n- **AOB is only as good as the sig.** A too-short sig → `ambiguous`; over-\n  wildcarding → `ambiguous`; under-wildcarding a reloc byte → breaks on relink.\n  `author-diff` (byte-diff of two known versions) is bullet-proof; the single-\n  version heuristic is best-effort (prefer capstone, and always verify uniqueness\n  with `scan`).\n- **ghidriff addresses carry Ghidra's image base** — use `--ghidra-base`. The AOB\n  path avoids this entirely.\n- **Not a decompiler \u002F not a save editor \u002F not a UI driver.** Pair with:\n  `game-re-binary`, `ida-multi-mcp` (BCSD re-find), `ghidra-mcp`, `frida` (RE);\n  `bc-drive` (live canvas driving); `battlecats-event-unlock` (event offsets);\n  `bcsfe-save-roundtrip` (saves).\n\n## Evidence\nMASTER-DECISION-QUEUE §E.2 (V×E H×M, BUILD, verified): \"AOB wildcard-signature\nresolver (retire hardcoded RVAs; survive relink via `frida search_memory`) ·\nghidriff (one-command cross-version `.so` diff → auto-port the offset table) · BC\nupdate-triage skill (decode+diff APK\u002FDAT\u002F.so per version bump).\" Shadow-gate\ndiscipline per COUNCIL-VERDICT §C5. BC ground truth from `battlecats-event-unlock`\n+ `bc-drive` (both EN 15.4.1, x86_64, imagebase 0).\n",{"name":5,"description":7},"main","a298c929b6cbd662e1fce54302ce520d5ceea1a5",".agents\u002Fskills\u002Fbc-update-survival","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain","https:\u002F\u002Fgithub.com\u002FPrekzursil","2026-11-02 14:30:57",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add Prekzursil\u002Fagent-skills-toolchain --skill bc-update-survival",{"tool":56,"command":57},"bunx","bunx skills add Prekzursil\u002Fagent-skills-toolchain --skill bc-update-survival",{"tool":59,"command":60},"pnpm","pnpm dlx skills add Prekzursil\u002Fagent-skills-toolchain --skill bc-update-survival","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fbc-update-survival\u002FSKILL.md",true,[64,70],{"path":65,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":68,"sourceHtmlUrl":69},"aob_resolver.py","SCRIPT","脚本",38961,"https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fbc-update-survival\u002Faob_resolver.py",{"path":71,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":72,"sourceHtmlUrl":73},"ghidriff_port.py",26974,"https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fbc-update-survival\u002Fghidriff_port.py",[75,95,126,153,167,183],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":39},"01M6DF7D7478R55P46REYH4QAC","clarify-requirements","Resolve genuine pre-execution ambiguity by scanning repo context, generating 1-6 grounded options, and asking 1-3 focused questions via AskUserQuestion. NOT for mid-task use (injection risk); NOT when the goal is already unambiguous; use to disambiguate vague prompts before any file edits.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fworkspace-hooks\u002Fskills\u002Fclarify-requirements\u002FSKILL.md",[],[82,83,84,85,86,87,88,89,90,35,91,92,93,94,38],"clarify requirements","clarify","requirements","risk","options","task","prompts","goal","scanning","context","repo","injection","execution",{"skillNo":96,"name":97,"nameZh":6,"description":98,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":106,"publishedAt":39},"01M6DF79CA4BHJS66J8EZDBPWJ","openmm-md","Run FREE, open-source, Windows-native GPU molecular dynamics via the openmm-md MCP (OpenMM + CUDA on the local NVIDIA GPU). Use for protein \u002F protein-ligand MD when you want a free stack or are on Windows without a Schrodinger license. Covers the full workflow (prepare, solvate, minimize, equilibrate, production, analyze, mmgbsa) AND an honest decision guide vs Schrodinger Desmond, including how to run Desmond legitimately on Linux or a cloud GPU with a real license. This is a deliberately LESSER free alternative and does NOT replace the schrodinger MCP tools. Do NOT use it to pick a free tool when a validated FEP+, WaterMap, IFD-MD, or Prime MM-GBSA result is actually required.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fmcp\u002Fopenmm-md-mcp\u002Fskill\u002Fopenmm-md\u002FSKILL.md",[101],{"categoryNo":102,"categoryName":103,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[107,108,109,110,111,112,113,114,115,116,117,118,119,120,35,121,122,123,124,125],"openmm md","how","decision","pick","linux","analyze","tool","stack","open","NVIDIA","gpu","license","workflow","windows","free","molecular dynamics","local","do","MCP",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":138,"publishedAt":39},"01M6DF76C1MG85VEWP8VZCBNMN","visual-review","Take screenshots of web pages and UI using Playwright for visual review and iteration","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fvisual-review\u002FSKILL.md",[132,135],{"categoryNo":133,"categoryName":134,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":136,"categoryName":137,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000008","测试与质量",[139,140,141,142,143,144,145,146,147,148,108,149,150,151,152],"review","visual","visual review","pages","web","false","iteration","take","check","slides","ui","screenshot","playwright","screenshots",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":159,"publishedAt":39},"01M6DF73AQVCBZKEN0YXEX9FXP","status","Diagnostic status report — shows metaswarm installation state, project setup, and potential issues","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstatus\u002FSKILL.md",[],[155,160,161,162,163,164,165,166],"setup","report","project","installation","project setup","issues","state",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":174,"publishedAt":39},"01M6DF6X6C2XB0P6GX76P7TTYV","start","Use when starting work on any task, when the user mentions metaswarm, or when the user wants to begin tracked development work","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstart\u002FSKILL.md",[173],{"categoryNo":102,"categoryName":103,"taxonomyType":104,"taxonomyTypeDesc":105},[169,175,87,176,177,178,35,179,180,181,182],"start issue","issue","ready","work on issue","user","work","work on","development",{"skillNo":184,"name":160,"nameZh":6,"description":185,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":186,"categories":187,"keywords":188,"publishedAt":39},"01M6DF6QMJ9AJKFKHHKRT005PQ","Interactive project setup — detects your project, configures metaswarm, writes project-local files","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fsetup\u002FSKILL.md",[],[160,162,123,189,164,190],"files","interactive"]