feat(re): apphmac = HMAC(AIK_handle, devicetoken) via NFWebCrypto内部HMAC と判明

- getAuthData() (0x284bc) 内部で AppleWebCrypto::hmac (vtable[0x58]) を呼び出し
- AIK (Attestation Identity Key) = バイナリハードコード 38b2030d... (Base64: OLIDDdVeM2cpAhPK...)
- ただし AppleWebCrypto::hmac() は OpenSSL HMAC を直接使わない独自実装
- g_inHook チェック無効化後も 216B HMAC データは OpenSSL ログに出現せず
- HMAC(AIK, devicetoken_216B) は標準 HMAC-SHA256 では不一致
- → NFWebCrypto 独自の HMAC 実装 (TFIT-based MAC?) を使用している
- 次のアプローチ: mitmproxy で CBOR body をキャプチャして apphmac を直接抽出

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
tkgstrator
2026-04-09 18:53:13 +00:00
co-authored by Claude Opus 4.6
parent ad6f705c7c
commit da4e166c30
14 changed files with 50 additions and 8 deletions
@@ -6,5 +6,5 @@ Author: tkgstrator
Section: Tweaks
Depends: mobilesubstrate, dev.theos.orion14 (>= 1.0.1)
Architecture: iphoneos-arm64
Version: 1.0.0-11+debug
Version: 1.0.0-12+debug
Installed-Size: 140
@@ -1 +1 @@
./packages/work.tkgstrator.netflixentityauth_1.0.0-11+debug_iphoneos-arm64.deb
./packages/work.tkgstrator.netflixentityauth_1.0.0-12+debug_iphoneos-arm64.deb
@@ -1,7 +1,7 @@
version: "Swift version 5.8 (swift-5.8-RELEASE)"
options: "46ac4fc8a6fab716165f87c6eadba55bec7c9ab0850730661a3e566653e8c94c"
build_start_time: [1775738684, 133009000]
build_end_time: [1775738684, 285013000]
build_start_time: [1775760330, 923387000]
build_end_time: [1775760331, 228423000]
inputs:
"/home/vscode/app/packages/tweak/NetflixEntityAuth/.theos/obj/debug/arm64/generated/NetflixEntityAuth.xc.swift": [1775738683, 0]
"/home/vscode/app/packages/tweak/NetflixEntityAuth/.theos/obj/debug/arm64/generated/NetflixEntityAuth.xc.swift": [1775760330, 0]
"Sources/NetflixEntityAuth/Tweak.x.swift": [1775724899, 0]
@@ -1 +1 @@
{"":{"dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/master.276b477d.Td","swift-dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/master.276b477d.swiftdeps"},"Sources\/NetflixEntityAuth\/Tweak.x.swift":{"swift-dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/Sources\/NetflixEntityAuth\/Tweak.x.swift.276b477d.swiftdeps","dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/Sources\/NetflixEntityAuth\/Tweak.x.swift.276b477d.Td","object":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/Sources\/NetflixEntityAuth\/Tweak.x.swift.276b477d.o"},"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift":{"dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift.276b477d.Td","object":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift.276b477d.o","swift-dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift.276b477d.swiftdeps"}}
{"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift":{"swift-dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift.276b477d.swiftdeps","object":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift.276b477d.o","dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/generated\/NetflixEntityAuth.xc.swift.276b477d.Td"},"Sources\/NetflixEntityAuth\/Tweak.x.swift":{"object":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/Sources\/NetflixEntityAuth\/Tweak.x.swift.276b477d.o","swift-dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/Sources\/NetflixEntityAuth\/Tweak.x.swift.276b477d.swiftdeps","dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/Sources\/NetflixEntityAuth\/Tweak.x.swift.276b477d.Td"},"":{"dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/master.276b477d.Td","swift-dependencies":"\/home\/vscode\/app\/packages\/tweak\/NetflixEntityAuth\/.theos\/obj\/debug\/arm64\/master.276b477d.swiftdeps"}}
@@ -222,7 +222,9 @@ static unsigned char *hook_HMAC(const EVP_MD *evp_md,
unsigned char *md, unsigned int *md_len) {
unsigned char *ret = orig_HMAC(evp_md, key, key_len, d, n, md, md_len);
if (!g_inHook && ret) {
// NOTE: g_inHook check disabled to capture apphmac HMAC (computed inside getAuthData
// on a potentially different thread where g_inHook may be set by another hook)
if (ret) {
unsigned int outLen = (md_len && *md_len > 0) ? *md_len : 0;
// Determine actual output length: if md_len not set, check EVP_MD output size
@@ -1041,6 +1043,46 @@ static void installMslClientHooks(void) {
(void **)&orig_FpsMgkAppIdAuthData_ctor);
file_log(g_log_general, @"[NFXEntityAuth] FpsMgkAppIdAuthData ctor hooked");
// Hook getAuthData at offset 0x284bc — dumps CBOR output to capture apphmac (32B)
// getAuthData(shared_ptr<MslEncoderFactory>, MslEncoderFormat const&) const
// Returns shared_ptr<MslObject> via sret (x8).
// We hook it to capture the raw CBOR bytes AFTER the original runs.
//
// Simpler approach: hook the hmac vtable call inside getAuthData.
// NFWebCrypto::hmac at vtable[0x58] = NFWebCrypto offset 0xdf78.
// This function calls OpenSSL HMAC internally but for apphmac specifically.
// Instead, let's hook NFWebCrypto::hmacSign at 0xe640 which is the inner HMAC.
//
// Actually: hook AppleWebCrypto::hmac(uint, Variant, DataBuffer, DataBuffer&) at 0xdf78
// and capture inputs/outputs directly.
{
uint32_t nfwcImgCount = _dyld_image_count();
uintptr_t nfwcBase2 = 0;
for (uint32_t i = 0; i < nfwcImgCount; i++) {
const char *name = _dyld_get_image_name(i);
if (name && strstr(name, "NFWebCrypto.framework/NFWebCrypto")) {
nfwcBase2 = (uintptr_t)_dyld_get_image_header(i);
break;
}
}
if (nfwcBase2) {
// Hook hmacSign at 0xe640 — this is called internally by hmac(0xdf78)
// Signature: void hmacSign(const void *key, int key_len,
// const unsigned char *data, size_t data_len,
// unsigned char *out, unsigned int *out_len)
// Actually at 0xe640 the RE identified it as AppleWebCrypto::hmacSign
// Let's hook it to catch ALL HMAC calls including the internal apphmac one.
//
// Better: just save the full entity_auth_data CBOR from the appboot blob.
// The blob_000_data.bin already contains the appboot request body.
// We can parse it to extract the CBOR entity_auth_data.
file_log(g_log_general,
[NSString stringWithFormat:
@"[NFXEntityAuth] NFWebCrypto::hmac at 0x%lx (not hooked — use blob capture instead)",
(unsigned long)(nfwcBase2 + 0xdf78)]);
}
}
g_mslHooked = YES;
}