Skip to content

chore/fix: align build with KiouForge + make 1.0.2 chinlan actually work#44

Open
tkgstrator wants to merge 8 commits into
developfrom
feat/align-with-kiouforge
Open

chore/fix: align build with KiouForge + make 1.0.2 chinlan actually work#44
tkgstrator wants to merge 8 commits into
developfrom
feat/align-with-kiouforge

Conversation

@tkgstrator

@tkgstrator tkgstrator commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

KiouForge/KIOU-Hook ツリーと足並みを揃える build/tooling 整合と、1.0.2 chinlan build を実機で完動させるための修正一式。 元は Makefile align だけの PR だったが、実機 deploy → login → account switch まで通す過程で 1.0.2 側の未解決バグ 3 系統を潰したので同じ PR に載せた。

Commits

1. Align 系(Makefile / submodule / rename)

  • 51a6026vendor/KIOU-Hook を submodule として追加(Chinlan / Kanade と同じ寄せ方)。 catalog 共有の下準備。
  • a29b311 — Makefile を KiouForge 形に整合:
    • make deploy target(scp → trollstorehelper install force → 再起動)
    • BUNDLE_ID_SUFFIX / IPA_OUT / --output / --bundle-id-suffix
    • KIOU_HOOK_DIR + -Ivendor/KIOU-Hook
    • Sources/Chinlan/chinlan.m を FILES に追加
    • TARGET_VERSION ?= 1.0.2
    • -DKIOU_CHINLAN=1-DIPA_CHINLAN=1 + KEB 全 15 ソースの KIOU_CHINLANIPA_CHINLAN 一括 rename(KIOU-Hook / Chinlan / KiouForge と共通化)
  • fc5bfb7 — Kanade submodule を c29a372 に bump(--bundle-id-suffix サポートのため。 KiouForge と同じ pin)
  • 3df07bd / 0aa727dfix/v1_0_2-cave-region の 2 fix を cherry-pick(recipes/v1_0_2.py の CAVE_REGION を __eh_frame から外し、ENTRY_SLOT_BASE を __bss に移す)

2. 1.0.2 chinlan 完動化

  • 36c375cfix(chinlan/1.0.2): sync C-side slot/entry/cave RVAs with recipe fixfix/v1_0_2-cave-region が recipe だけ 1.0.2 に更新してた片手落ち fix。 Internal.hKIOU_BR_HOOK_SLOT_RVA / KIOU_BR_ENTRY_SLOT_BASE_RVA / KIOU_BR_CAVE_REGION_START を recipe と同じ 1.0.2 値に。 これがないと cave が publish 先を見つけられずに BLR NULL → SIGSEGV。
  • 76a6c03fix(chinlan/1.0.2): update BackToTitleSequence.RunAsync RVA + MethodInfo* ABI — 2 バグ複合。 (a) 1.0.1 の 0x5CF712C を 1.0.2 の 0x5CFC394 に。 (b) il2cpp static method の hidden MethodInfo *mi を signature に追加 ((ct)(ct, mi)) して fn(NULL, NULL) で呼ぶ。 chinlan では JB の trampoline を経由しないので X1 の register 残骸を渡すと即クラッシュしていた。
  • 768c9f7feat(chinlan/1.0.2): port HeaderProvider hook to swap x-user-id (fixes -40004) — KEB の x-user-id swap は HttpMessageInvoker.SendAsync hook body 内で行っていたが、1.0.2 build 12 の Yaha (Cysharp) borrow-tracker と相互作用して silent Rust panic を起こす。 KIOU-Hook が既に採用している「managed 層の Project.Network.HeaderProvider.SetOrUpdateHeader (RVA 0x5BD9EE8) で swap、SendAsync は passthrough」パターンを KEB へ移植:
    • enum + entry slot + recipe SITES 行(common.py / v1_0_1.py / v1_0_2.py すべてに追加、1.0.1 用 RVA 0x5BD4C80 も同時追加)
    • HookHeaderProviderSetOrUpdateEntry 実装(value il2cpp-string を差し替える)
    • ChinlanDispatcher.m に entry slot publish 行を追加
    • HookHttpMsgInvokerSendAsyncEntry から swapUserIdHeader を除去して bare passthrough に

Test evidence(実機 1.0.2 build 12 chinlan / iPhone10,1 iOS 16.7.16 TrollStore)

  • make chinlan / make all / make jailed — link clean
  • make deploy TARGET_VERSION=1.0.2 DECRYPTED_IPA=<path> — 完走
  • login → 成功、AccountExists / LoginArgs.Create / GrpcLogging hook 発火
  • Settings modal → 別アカウント選択 → 切り替え → "タイトルに戻りますか?" ダイアログ表示 → タイトル遷移成功
  • account switch 中に [HEADER] x-user-id swapped → <target-user-id> livelog、-40004 は 0 件
  • 新規 .ips なし(deploy 前の KIOU-2026-07-02-025417.ips が最新のまま)

What's still NOT in

  • KEB の 37 個の KIOU_BR_HOOK_* catalog を KIOU-Hook 側の共有 catalog にマージする作業は別 PR(KIOU-Hook 側 catalog 拡張とセットで扱う話)。
  • 1.0.2 サポートの Internal.h RVA を per-version マクロで分岐する仕組み(今回は 1.0.2 値に上書き済み。 1.0.1 chinlan は build するが cave 座標が合わなくなるはず)。 これも別 PR ネタ。
  • fix/v1_0_2-cave-region / feat/deploy-target の open ブランチはこの PR に取り込み済みなので、マージ後 close で OK。

🤖 Generated with Claude Code

tkgstrator and others added 8 commits July 1, 2026 17:36
Sets up vendor/KIOU-Hook (IPA-Patch/KIOU-Hook) alongside the existing
Chinlan and Kanade submodules. Nothing in the current tree consumes it
yet — this only makes the shared IPA-Patch hook catalog/library
available for future incremental adoption. Matches the KiouForge tree
shape so shared code can be picked up without extra setup.
… IPA_CHINLAN

- Adopts KiouForge's Makefile shape so the two IPA-Patch tweaks share
  the same build surface:
    * make deploy target (scp + trollstorehelper install force + relaunch)
    * BUNDLE_ID_SUFFIX for installing alongside the original app
    * IPA_OUT / --output / --bundle-id-suffix wired into build_patched_ipa.sh
    * KIOU_HOOK_DIR pointer at vendor/KIOU-Hook and -Ivendor/KIOU-Hook
      in CFLAGS so future incremental adoption of the shared catalog
      is drop-in.
    * Sources/Chinlan/chinlan.m compiled in (IPAChinlanFindImage /
      IPAChinlanResolveOrig — the generic runtime side of Chinlan;
      currently unused by KEB, will be picked up as caves migrate).
    * TARGET_VERSION default bumped to 1.0.2 (the current shipped
      build) so a plain 'make ipa' targets the version most users
      have.

- Renames the KEB-local KIOU_CHINLAN compile flag to the shared
  IPA_CHINLAN flag that KIOU-Hook, Chinlan, and KiouForge already use.
  Purely mechanical rename across Sources/KiouEngineBridge; no
  behaviour change. Without this, dropping any KIOU-Hook or Chinlan
  source file into the KEB tree would require rewriting its #if
  guards, which defeats the point of the shared catalog.

Verified: make chinlan, make all, make jailed all link clean.
Picks up 'feat(build): --bundle-id-suffix flag on build_patched_ipa.sh'
(IPA-Patch/Kanade feat/bundle-id-suffix branch, same commit KiouForge
pins). Required by the make deploy path — the Makefile now passes
--bundle-id-suffix through, but the previous shared pin (v0.1.2)
didn't know that flag.
1.0.2's __TEXT,__eh_frame grew to 0x81ACE58..0x826F5E8, fully covering
the inherited 1.0.1 CAVE_REGION (0x826A000..0x826C000). Writing caves
there clobbered DWARF CFI bytes and verify_patches refused every site
with 'cave was not zero-fill nor the matching payload'.

Move CAVE_REGION to the verified-zero tail after __oslogstring at
0x8270040..0x8272040 (8 KB; UnityFramework section tail). lief-verified
all-zero; B reach from the farthest site (0x6082AC0) is well within
the +/-128 MB AArch64 limit.

Verified end-to-end: make ipa TARGET_VERSION=1.0.2 now succeeds and
produces Kiou-1.0.2-patched.ipa.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ENTRY_SLOT_BASE_RVA (0x091E91B8) inherited from 1.0.1 lands in
__DATA,__common in 1.0.2 — that section is pre-initialised, so the
recipe's 32-slot block is non-zero on disk. At runtime an entry cave's
BLR through the slot loads that garbage as a function pointer and
crashes (Login, AccountExists, ...).

Relocate to the verified-zero tail of __DATA,__bss at 0x8F9D3B8
(0x100 = 32 slots * 8 B, fits ahead of PROBED_HOOK_SLOT_RVA). bss is
guaranteed zero on launch, so cave -> BLR through an unpublished slot
is harmless until the dylib publishes the hook fn ptr.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The prior fix/v1_0_2-cave-region cherry-picks relocated CAVE_REGION,
HOOK_SLOT_RVA, and ENTRY_SLOT_BASE_RVA on the Python side (recipes/
v1_0_2.py) but left the matching C-side constants pointing at the
1.0.1 offsets. That was silent-catastrophic:

  * KIOU_BR_HOOK_SLOT_RVA — the recipe patches cave stubs to LDR from
    unityBase + 0x8F9D4B8, but KEBBridgeChinlanPublish wrote the
    dispatcher pointer to unityBase + 0x8F90CC0 (1.0.1's __bss slot,
    which il2cpp overwrites during lazy init). Cave read NULL → BLR 0
    → SIGSEGV on the first SendAsync fire during login.

  * KIOU_BR_ENTRY_SLOT_BASE_RVA — same story for the entry-slot table:
    caves LDR from unityBase + 0x8F9D3B8, publish wrote to
    unityBase + 0x091E91B8 (1.0.1's __common region, which carries
    live KIOU data on 1.0.2). Every CAVE_ENTRY hook BLR'd garbage.

  * KIOU_BR_CAVE_REGION_START — the cave-bypass entry addresses that
    kiou_bridge_bypass_entry_for_hook() computes (used for injection
    orig-chain fallbacks) landed in __eh_frame instead of the real
    cave region. Any hook body that touched g_inject_entry[i] would
    BLR into DWARF CFI bytes.

All three now match recipes/v1_0_2.py. Verified live on 1.0.2 build
12 (see the log line 'cave_start=0x8270040 cave_size=84 count=37').
…nfo* ABI

Two bugs in one path made 'switch account' silent-crash on 1.0.2:

  1. RVA drift — the 1.0.1 RVA (0x5CF712C) was carried forward without
     a version guard. On 1.0.2 that address is a different function,
     so KEBNavigateToTitleScene's raw-address fallback (used on
     chinlan, where the JB suppress hook isn't installed) BLR'd into
     the wrong body. Updated to the 1.0.2 RVA (0x5CFC394), verified
     against assets/1.0.2/dump.cs.

  2. Missing MethodInfo* in the typedef — il2cpp-generated static
     methods take (args..., MethodInfo *mi) with mi in the last arg
     register. On JB the caller supplied a real mi in X1, which flowed
     through MSHookFunction's trampoline verbatim, so the 1-arg
     typedef 'happened to work' by silently ignoring X1. On chinlan
     when we call the raw method directly, X1 is register garbage —
     the method dereferences it early and faults with no .ips.

Both KEBNavigateToTitleScene and the JB suppress hook now use the
2-arg signature (ct, mi) and pass NULL for mi. RunAsync is a plain
static (not shared-generic), so NULL mi is safe — this matches
KIOU-Hook's KIOUNavigateToTitleScene (vendor/KIOU-Hook/Hook/
AccountObserve.m:352) which uses the same call shape.

Verified live: 'switch account' → 'BackToTitleSequence.RunAsync
invoked' → back-to-title dialog.
…s -40004)

On 1.0.2 build 12 the previous x-user-id swap site
(HttpMessageInvoker.SendAsync) is inside Yaha's borrow scope — even
just reading the request-headers dictionary crashes the process
silently (Rust panic → SIGABRT, no .ips). Without a working swap the
server rejects account-switch logins with -40004 because LoginArgs
now says 'deviceId=<new>' but the auth header still names the
previous user.

KIOU-Hook already ships the proven fix: swap at the managed-only
Project.Network.HeaderProvider.SetOrUpdateHeader site (called well
before HttpMessageInvoker) and keep SendAsync as a bare passthrough.
This commit ports the same pattern into KEB:

  * enum + entry-slot for KIOU_BR_HOOK_HEADER_PROVIDER_SET_OR_UPDATE_HEADER
    (Internal.h)
  * recipe row wired for both 1.0.1 (0x5BD4C80) and 1.0.2 (0x5BD9EE8)
    — CAVE_ENTRY, same 'f657bda9' prologue on both builds
  * HookHeaderProviderSetOrUpdateEntry body — inspects the key
    il2cpp-string, replaces the value with a fresh il2cpp-string
    naming the pending account's user id, then forwards to bypass
  * ChinlanDispatcher wires the new entry slot at publish time
  * HookHttpMsgInvokerSendAsyncEntry drops swapUserIdHeader — it is
    now a bare passthrough that never touches request/self

Verified live on 1.0.2 build 12: 'switch account' now logs
'[HEADER] x-user-id swapped → <target-user-id>' at 03:42:57 and
proceeds through login instead of dying with -40004.
@tkgstrator tkgstrator changed the title chore(build): align Makefile / Chinlan / KIOU-Hook usage with KiouForge chore/fix: align build with KiouForge + make 1.0.2 chinlan actually work Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant