diff --git a/docs/HUYA_HDID_ALGORITHM_GEN.md b/docs/HUYA_HDID_ALGORITHM_GEN.md index 3f53267..75fb571 100644 --- a/docs/HUYA_HDID_ALGORITHM_GEN.md +++ b/docs/HUYA_HDID_ALGORITHM_GEN.md @@ -1101,3 +1101,23 @@ dfpReport: tReq = [10B 魔数 57 18 82 cf 66 4b b3 94 01 ee][3988B 加密采 - tools/frida/hook_dfp_java.js (Java 全量 hook — 太重, 会闪退, 弃用) - /tmp/turing/: mpdc1/ga2/tur 数据存档 - 建议: turing-dfp 立为独立子项目 (证据链齐全); 或轻量运行时 trace 追 tReq 装配点 + +--- + +## §11.47 R17: dfpReport 密文体实时捕获成功 (2026-08-29) — turing 加密体现场! + +### 捕获 (SSL_write 明文扫描, hook_ssl_magic.js) +- 端点: **POST wsapi.huya.com** (okhttp) — 非 udbdf 域名! +- 3798B 请求: hyudbwebuif/dfpReport WUP -> tReq{tag6="android-", tag1=[0dcb]3531B = [10B魔数 571882cf664bb39401ee] + 密文} +- 证据: evidence/dfp_live/dfpReport_post_full.bin (完整 3798B HTTP POST) +- 组件: libturingmfa.so(v87, tss;rfr;ite) + libturingga.so(v2.92.2) 动态插件 (app_dynamic_so_64/) +- 密钥材料: mpdc_108298_1=32hex(0399ED0B...), getDfpConfig tRsp=81B密文配置, ga2(1860B), .turing.dat(64B) + +### 触发方法 (重注册) +- 备份 tar (604MB) -> 清 app_turingdfp/app_turingfd/resinfo -> 启动 -> 自动重注册 -> SSL_write 命中 -> 状态已再生 (ga2/resinfo 恢复) +- 无副作用 (备份在 /data/local/tmp/dfp_backup.tar) + +### 下一步 (turing-dfp 独立子项目) +- 解析 WUP 完整结构 + 抓 SSL_read 响应 +- 破 getDfpConfig 81B 配置 (含加密钥?) -> 破 dfpReport 密文 +- 或运行时 trace 密文装配点 (SSL_magic 命中时刻的调用者) diff --git a/evidence/dfp_live/dfpReport_post_full.bin b/evidence/dfp_live/dfpReport_post_full.bin new file mode 100644 index 0000000..75a232b Binary files /dev/null and b/evidence/dfp_live/dfpReport_post_full.bin differ diff --git a/evidence/dfp_live/libturingmfa.so b/evidence/dfp_live/libturingmfa.so new file mode 100644 index 0000000..2db698a Binary files /dev/null and b/evidence/dfp_live/libturingmfa.so differ diff --git a/evidence/dfp_live/turingga.so b/evidence/dfp_live/turingga.so new file mode 100644 index 0000000..cbdae34 Binary files /dev/null and b/evidence/dfp_live/turingga.so differ diff --git a/tools/frida/capture_20260829_060053.jsonl b/tools/frida/capture_20260829_060053.jsonl new file mode 100644 index 0000000..e69de29 diff --git a/tools/frida/capture_20260829_060242.jsonl b/tools/frida/capture_20260829_060242.jsonl new file mode 100644 index 0000000..d8882d6 --- /dev/null +++ b/tools/frida/capture_20260829_060242.jsonl @@ -0,0 +1 @@ +{"event": "treq-hooks", "installed": 2} diff --git a/tools/frida/capture_20260829_060425.jsonl b/tools/frida/capture_20260829_060425.jsonl new file mode 100644 index 0000000..d8882d6 --- /dev/null +++ b/tools/frida/capture_20260829_060425.jsonl @@ -0,0 +1 @@ +{"event": "treq-hooks", "installed": 2} diff --git a/tools/frida/capture_20260829_060708.jsonl b/tools/frida/capture_20260829_060708.jsonl new file mode 100644 index 0000000..d8882d6 --- /dev/null +++ b/tools/frida/capture_20260829_060708.jsonl @@ -0,0 +1 @@ +{"event": "treq-hooks", "installed": 2} diff --git a/tools/frida/capture_20260829_060855.jsonl b/tools/frida/capture_20260829_060855.jsonl new file mode 100644 index 0000000..d8882d6 --- /dev/null +++ b/tools/frida/capture_20260829_060855.jsonl @@ -0,0 +1 @@ +{"event": "treq-hooks", "installed": 2} diff --git a/tools/frida/capture_20260829_061130.jsonl b/tools/frida/capture_20260829_061130.jsonl new file mode 100644 index 0000000..d8882d6 --- /dev/null +++ b/tools/frida/capture_20260829_061130.jsonl @@ -0,0 +1 @@ +{"event": "treq-hooks", "installed": 2} diff --git a/tools/frida/capture_20260829_061225.jsonl b/tools/frida/capture_20260829_061225.jsonl new file mode 100644 index 0000000..1b05dbd --- /dev/null +++ b/tools/frida/capture_20260829_061225.jsonl @@ -0,0 +1,12 @@ +{"event": "ssl-hook", "module": "libjavacrypto.so"} +{"event": "ssl-hook", "module": "libssl.so"} +{"event": "ssl-hook", "module": "libhyssl.so"} +{"event": "ssl-hook", "module": "libmarsstn.so"} +{"event": "ssl-hook", "module": "libhyquic.so"} +{"event": "ssl-hook", "module": "libngtcp2_crypto_boringssl.so"} +{"event": "ssl-hook", "module": "libposix_quic_ngtcp.so"} +{"event": "ssl-hook", "module": "libhysignalcore.so"} +{"event": "ssl-hook", "module": "libhymediatrans.so"} +{"event": "ssl-hook", "module": "libYCloudLive.so"} +{"event": "ssl-hook", "module": "libhydt.so"} +{"event": "ssl-magic", "module": "libjavacrypto.so", "num": 4201, "off": 257, "head": "571882cf664bb39401ee7cda1189c1750c9c4d56ddf3a91b0881cc464cb378e0397bdaa32175b402f2fa7ca4ad383247925ee3e31158ad8b6631b964f9c12ee6475e037bc5508deb6de633ac5100c8fde3b712b36cd6b570ec55131e60a866817e5e29da3128d1ef2eb49b88a9c1da529e208e3be6ae1383583aba1490d4643a06386723d5e2134f81830671d9ad1bfce909530228c2f84e9133a501a5486fd7", "bt": ""} diff --git a/tools/frida/capture_20260829_061332.jsonl b/tools/frida/capture_20260829_061332.jsonl new file mode 100644 index 0000000..a3f5426 --- /dev/null +++ b/tools/frida/capture_20260829_061332.jsonl @@ -0,0 +1,12 @@ +{"event": "ssl-hook", "module": "libjavacrypto.so"} +{"event": "ssl-hook", "module": "libssl.so"} +{"event": "ssl-hook", "module": "libhyssl.so"} +{"event": "ssl-hook", "module": "libmarsstn.so"} +{"event": "ssl-hook", "module": "libhyquic.so"} +{"event": "ssl-hook", "module": "libngtcp2_crypto_boringssl.so"} +{"event": "ssl-hook", "module": "libposix_quic_ngtcp.so"} +{"event": "ssl-hook", "module": "libhysignalcore.so"} +{"event": "ssl-hook", "module": "libhymediatrans.so"} +{"event": "ssl-hook", "module": "libYCloudLive.so"} +{"event": "ssl-hook", "module": "libhydt.so"} +{"event": "ssl-magic", "module": "libjavacrypto.so", "num": 3798, "off": 257, "full": "504f5354202f20485454502f312e310d0a692d7665723a20310d0a436f6e74656e742d547970653a206170706c69636174696f6e2f6f637465742d73747265616d0d0a436f6e74656e742d4c656e6774683a20333631310d0a486f73743a2077736170692e687579612e636f6d0d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a20677a69700d0a557365722d4167656e743a206f6b687474702f332e31342e390d0a0d0a00000e1b10032c3c4c560c68757961756462776562756966096466705265706f72747d00010def0800010604745265711d00010de10a06001607616e64726f69642d00010dcb571882cf664bb39401ee7cda1169c9f5289c4d46956f2110bb80cc5dca8b41e06166444cb511a6d25ddc01a1f17e7f57f340c1f0c75046be06ed3ff3684cadc034ddc0e95c781f5ad5c60d52164e9cfba35fbd482635216a2568befee8d280b1b381ed1f5e1f1abc376d98b0b80d8addb653b8510b628b7f0d775c1e70271c3ad1f2f45ef8d6c092883c20ac9b9170f44a65b5fc8fb0fcc0585741bafc566ef49fbdd693d75a6ebe787880290190473a3eb561b2c901b5bedc67b2eee7b3d16ccb88af875240f09ef846c18ccf245dcedcba5d2835677d6fb8a0224df85cdcaa553e38cc0906f2947f71c99b7b6ea2027bb6aec86444056359ac6bab72b8abf3c64bbd859f260a41ac21b91559612b20b157b31c4937d8f2974ee32a4153fd63e0f34e589c206545e6507b89eed848ef91540efd0d44260915c574329b32eecf26abc0cf67ac889f354b7beda653b51914f22e5b78b194a5df0787ff90d2a178d6b5ac4d472c0023cf5be33ab93569d356da4ea281e9ba327a80adc5111f24637f0de07911e2f225c8feeafb98fe08fb36009ab7fbaac4553475ce6cb3e501bbb0db9afa36f9bcdcf1a2d69f0436c807ac5c65df88fd649682d29644dc7c035b96098bc799570865d8a1e9601c9c9a8ff115bd124d46b3e830e18203561b4f22a06b34a7a5b1578ee9717d0e9a195fa3ef8f99c3bad34697f762bb334f3cfb1df295385c38792afa5997fd9f27dd2796789f15e85e6f4666a737bc7ba027000aaa44defc652445edc0c02ec40dbe13b4ced8e9affbb4de8ba43100772f64f915410b5cee55f57a624e1f4c00b8c1ca2aeddc2f367250adccabe1e9c18bbbdc78681a371d85c48ebe1c7d0a2e9c49a41fa59034bafbaabb78e7a2248c51863827c3682d903e26f01b30ed0ed7c3ee32161497167dc236b1930ab85bc04386e696e80608f43fbe40f9546e21349ab6575286c76491b2ea6e072c881087dddb68e58976d21d4ff5861d2a5eb7b0a7f0d5ee3abf8e02179af4432788996ff58ab721a6a34626a7347ac57fb095ed1fd8129779ac3a4bc39129c249a76a131d1479c0dcf02036c954ba2f183c9d47d86f11db4a9f1191f90f494974df1f16efdf35abfea4829fa7b7bd08f8d9ed8104bb2c6e674083c7d0c3582f895ce28b3cf92296639941e65cb8d3a3b7e9d249078f8c1d2f728612f8cb7fa0828efec4c6813a908db80252412034de3d11b3fb20a704764c243229d2985c936470c8fe10797a8cc84b77ad57812f727e616cb8b53f7da2a53fb3d4cf9fcc87567dabb8b4223d81f39e0fd8a52cb363ac5e54840c0d8fac7196dfeebf34e876c52de40bfcc6b9b4235e2a30710c79cb4333e8c8526213e82a271a9a63c72fafebb85199d06afb8629cd82255e1d3dce290c1eb10f006615dd11e398f958f9f49f442aa812dbe76e531ac4b889e885326a850404e36315aee7bd25fa685135f1b579109abfc82b93eb529c84d54d678d7f30ac61bfe5606c60bb584b76db621063960e8a97914fbc108f8d0481682a067ee6a2712979c83e198c5c840f82f140c3aec39e27cb940b146954a6c2ef4459870dad4753b59d082da4b2da47e34a8468a3876f00d682c85aed95bc4d8a576aa2dc611707db51ef6523d816fc67b9bd225f328228c0fe8e85841feaac731209bf66dde5d2b87e22a9c85e57331eed8aae134e848da318065b086836dbecb098d27fe766604f04efabb7e5a1b5583727131672db046394eadf9d31f394b9c8f114514176fd53b91f69352cf2d3324cb60e7eafaaa197765106eeb011d5ec6f19f2cfb738d773333c5084afeafcbc0f771dd98a2609b37b97089d5f21f3fdfe258eae5bada739760adc2939045270a4b7ac536f19266ff790443fed92f94428a32c030e237564fece2f9b5561ea3bcae32c297b46625113b932167336ac78bfa8a25d6d99ea5d938406bfc6d02f35eb53f9b024a6bbdcb9c76486bea6f72a708969870cb1b7bcaff56ffc0f8da3ae9b00514dc3d457e36607f0e03b2389fc7b58029b15abbe3d4035853585384f6919cb510110e3837cb3d1303ef1c9af7d8d9e9be7c15e2c960501e6400680b6cf05e53c21e96d985d0d017a59cc2887e5f64e3796329a1de1c0bbdf6a434651654bf038b3273cf3f6ad2b838a1bb06b397bdf65a0cfe92d45f1e23ddf1dfde5b176fe987603bacd1690f9789929a367a037e6636de83d2b5692586b78aed491bf482e745283cfd8f164c3a1e54f9829f22d1222c73d15e73a662549af5cc2febc33388f87b002d0c24e79c63a38238e06283088fcb472f2bee37cfee86bbf436ddb3eb87d53a5528e463164c0b9851ad962035b9cf4e301bf5e704179b0c60fd1657a45d039c1859e822fa1f179bce86492a960c76611c95d626dcec7700df8efbb835ea901635eadad1f21390848d75a942604a20b83a8b925bc68667257d9945f51af7cd2d91cb43057b78a0cfa2e6cdd3228323974d1073f6c1c597fc117fc6532a6eb61a886bf33543760daa39ed0d9c7a49bf824f680e51de7f83a327f3d0bffd76cefbe49cf51c0a745d224728e48adf71e4cb4aaff58e8e6d36375ec329d7410854e7720f7f746c8721a4dde9c26f0d92f088f2892eefef90a67ab1c65bf435448705811a8e848ab5a3ef454fa04a2c22bd115a950535d017d43a578795c1b28f4cb6e7ef9b600d5eaeb6fc0484c527b799532211dc9d296e90a9b6cddda3fe1fdf6e8747798860d294c1daa583cc9eac1e5cd195402b9ee099ffe811ca12664c128edba8940f280bd964b8cff053f6e3b86f1803c67530ed5618a425de48d3314d2218068249248250ba565e4c449d62e512bdd87532d79d6e9d25d406f1ea850cc743e6054384d16d47e5488bd9682dde3a4890aae07965fff34cc87dee1e3f1b3f94890319f79105609fcaef315bbd5dfe9b270861a7483a652617943342e0c34e50bd1c018ccf462a97db5b4b9dacbfadf345033acb8cf7b4f9b074620d4d48037c218bba59ca9065762331897cdef62ddd4ae8517b02f6f07975561a0e020c2fd46b6fb7088c43293a8a7eed52865c223b7b15855c4df5813662bc11b8106e1f454758bf2f545b8dbb2b0e96830e0b712c6f721845d43c0ac8d59da8da018d38201559adb3df23cc625c544da5207cad3b21baa708c7a3b6afd49563411ee061429b250264793531b8ba3491e99c8d9175ab361777034598a2b391481b0b6c23d1dc32b34ff8bfbcb988dd33de54e140b821528e362c3205841962ba73a5c114836b0a1261c3de8c95d888f39c9497768b2f0c06c7ce3385fe629c5d5f5a8a43e5d84a4c2aa5b8b49cdbc07e911b53e2eb176dd6a6fafc367282a20d9cacfdfcddcddf021cc3e5c7d1e3fe736fe3b68ebdfba1d82b4444833b3554583715c05f884f222eff1a98aa1838293c08f913d1c043264d0a277202e06c77ec1cdba5db402177342f5c7c6217f84ba52a292163d5b026ac2071443f0a178cea666cb37a44d4a97647c6f08667ec1b708913e9c6be8096adab7fad90a0ccb98b317b990558a9dc68c245c0a41246dd26f966195c2b0733e7b7aed70c8b62e1cc5adaeb9fb02cabf5c045fcef6d8ba49b87dfba683b9632af6e821f2bb0f95e410671b086dbe14ad473d754761b5101e6978381e6467d35f7630d7fbca66ddaf90cfbf530ad40f6fa79cc7e29cc60a853474404b36c764c8509782a53c20a36412256f9d205005e0cae2997d956196abce23a225ef32960323eadbfc485e5f037cbbb9de0cea010cd4be7124781a57a812fc4f21fb85597a7fad4126a5c4d93381cc6cacd1e7212055fea9ed1a502a856f24dc2de7fa8463f8e0a805b1ef876c27627bbab82d5dd7e8ff950fb8cd876651dbb03ecf9339786520df3c38566369f75e0aa672eb13b224800a33d9c7dcdab5c10772b356cf67dfbc38a9e9ef7ebd1ed5329104798f7bf6d031d0864d94ba11e2471167851d8e70f9660a6c872705d1d4fe2216aa2a11b060c83d3ff5726bd993f0c6f66084f7a94d160bb015e9bd083376f84b88f4a7ee660ba5d7ffd7bcfe2881c874722b11ecc56c7814b8813c79c8c5530fb4642855b1df67c335a69a52921005504d6b1fdb951eacdca997db80a03b8585bab8ea85a3c5084131b1b6423f27ca43cd16e40a82e99dc44c00e08f5568af4dd656a6031df477416fa71d54dd7ae747905b4b00b5b1306e40e97ab82158aaf9c8bed034e7866c62baa82c0336deca4e60b5ab1e4861873e1289de3f993b4f10d6b977f908b5e0d19a7fb69ad73169eccea91356adb9573b9bfb5dfccfc3c99e12ba76e6f0de217b652f5a1691a7c21d455f06fb7bd443925cbee4eb57077f4adb02213beab5cbfb5b5a7fec4eb6703915544b1be16fb417b51635f97b42d6716e8e37b6a71cc29d93864524872a943a9f65b8f80451c504782999e3fd3fd0f8c00dec21cf4e290eb1a4d50ac72374b16812213fb6437e8ff96267374839c4dc58cb098b16f1db90de9ec65a1aee2d75157144add79550c035d8cd47c5ef82602a35997aa99200f449a2224676447dc0a1575de884e5c1c07baf147092a8843920262c830763b74bea289a41eb38072017fba4432ee3842dd00b61127773a93ba3283b0f718cc6c0e4d0faf55c59ed8b9d1007fc8ed463f54f2386bd61093607718814eb1facebd242262a3911c9a0d8d6d7464c83a2a27a928a8e827b23fa1b41127fec99ae3bafd6eaa3b4f4ba19d10f2a353a8d4101eb1356aa1974d8a2d91dea4d599bfeedcd41dd44235a5cb0f4a4545c7635be3f8e4ad47860d474d6e0c3de9b66c76c21764de1d4a12e810ce644736d3756a57aa0d65c3992a75f86ea5ec0b7e5105f0a3e4e6187985b5cf10227461126b8c7538ef704d315ef7e1849ae5a95116a6754eedfa0e95b9173f99e4c21f659a70b1d38ef8ae9a6b051eb542a21342fdda1ff21d9b1dacfca19773600400c0b8c980ca80c", "bt": ""} diff --git a/tools/frida/hook_ssl_magic.js b/tools/frida/hook_ssl_magic.js new file mode 100644 index 0000000..3ad93ab --- /dev/null +++ b/tools/frida/hook_ssl_magic.js @@ -0,0 +1,39 @@ +'use strict'; +function emit(row) { try { send(row); } catch (e) {} } +function btOk() { + try { + return Thread.backtrace(this.context, Backtracer.ACCURATE).slice(0, 10).map(a => { + const m = Process.findModuleByAddress(a); + return m ? m.name + '!' + a.sub(m.base) : a.toString(); + }).join(' <- '); + } catch (e) { return ''; } +} +const PREF = [0x57, 0x18, 0x82, 0xcf]; +let fired = false; +for (const mod of Process.enumerateModules()) { + let addr = null; + try { addr = mod.getExportByName('SSL_write'); } catch (e) {} + if (addr === null) continue; + Interceptor.attach(addr, { + onEnter(args) { + if (fired) return; + const buf = args[1]; + const num = args[2].toInt32(); + if (num < 40) return; + try { + const b = buf.readByteArray(1 << 20 > num ? num : num); // 尽量读 + const u = new Uint8Array(b); + for (let i = 0; i + 4 < u.length; i++) { + if (u[i] === PREF[0] && u[i+1] === PREF[1] && u[i+2] === PREF[2] && u[i+3] === PREF[3]) { + fired = true; + const n = Math.min(num, 12000); + const hex = Array.from((new Uint8Array(buf.readByteArray(n)))).map(x => x.toString(16).padStart(2, '0')).join(''); + emit({ event: 'ssl-magic', module: mod.name, num, off: i, full: hex, bt: btOk() }); + return; + } + } + } catch (e) {} + }, + }); + emit({ event: 'ssl-hook', module: mod.name }); +} diff --git a/tools/frida/hook_treq_trace.js b/tools/frida/hook_treq_trace.js new file mode 100644 index 0000000..8f0038e --- /dev/null +++ b/tools/frida/hook_treq_trace.js @@ -0,0 +1,90 @@ +'use strict'; +function emit(row) { try { send(row); } catch (e) {} } +function btOk() { + try { + return Thread.backtrace(this.context, Backtracer.ACCURATE).slice(0, 8).map(a => { + const m = Process.findModuleByAddress(a); + return m ? m.name + '!' + a.sub(m.base) : a.toString(); + }).join(' <- '); + } catch (e) { return ''; } +} +// tReq = [571882cf664bb39401ee][cipher] — 过滤向量/字符串写入 +const PREF = [0x57, 0x18, 0x82, 0xcf]; +const seen = {}; +function probeBuf(p, len) { + try { + if (len < 4) return false; + const b = p.readByteArray(4); + const u = new Uint8Array(b); + return u[0] === PREF[0] && u[1] === PREF[1] && u[2] === PREF[2] && u[3] === PREF[3]; + } catch (e) { return false; } +} +const VECWRITE = '_ZN6udbjce15JceOutputStreamINS_12BufferWriterEE5writeINSt6__ndk19allocatorIcEEEEvRKNS4_6vectorIcT_EEh'; +const STRWRITE = '_ZN6udbjce15JceOutputStreamINS_12BufferWriterEE5writeERKNSt6__ndk112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEh'; +let installed = 0; +for (const mod of Process.enumerateModules()) { + for (const [name, kind] of [[VECWRITE, 'vec'], [STRWRITE, 'str']]) { + let addr = null; + try { addr = mod.getExportByName(name); } catch (e) {} + if (addr === null) continue; + Interceptor.attach(addr, { + onEnter(args) { + let data, len; + try { + if (kind === 'vec') { + const begin = args[1].readPointer(); + const end = args[1].add(8).readPointer(); + len = end.sub(begin).toInt32(); + data = begin; + } else { + const flag = args[1].readU8(); + if ((flag & 1) === 0) { len = flag >> 1; data = args[1].add(1); } + else { len = args[1].add(8).readU64().toNumber(); data = args[1].add(16).readPointer(); } + } + } catch (e) { return; } + if (!probeBuf(data, len)) return; + const key = mod.name + '|' + kind; + if (seen[key]) return; + seen[key] = true; + let hex = ''; + try { + const n = Math.min(len, 96); + hex = Array.from(new Uint8Array(data.readByteArray(n))).map(b => b.toString(16).padStart(2, '0')).join(''); + } catch (e) {} + emit({ event: 'treq-magic', module: mod.name, kind, len, head: hex, bt: btOk() }); + }, + }); + installed++; + } +} +emit({ event: 'treq-hooks', installed }); +// 动态重扫: 每 2s 对新加载模块补挂 (插件/lib 延迟加载场景) +const seenMods = {}; +setInterval(() => { + for (const m of Process.enumerateModules()) { + if (seenMods[m.name]) continue; + seenMods[m.name] = true; + for (const [name, kind] of [[VECWRITE, 'vec'], [STRWRITE, 'str']]) { + let addr = null; + try { addr = m.getExportByName(name); } catch (e) {} + if (addr === null) continue; + try { + Interceptor.attach(addr, { + onEnter(args) { + let data, len; + try { + if (kind === 'vec') { const b = args[1].readPointer(); const e = args[1].add(8).readPointer(); len = e.sub(b).toInt32(); data = b; } + else { const f = args[1].readU8(); if ((f & 1) === 0) { len = f >> 1; data = args[1].add(1); } else { len = args[1].add(8).readU64().toNumber(); data = args[1].add(16).readPointer(); } } + } catch (e2) { return; } + if (!probeBuf(data, len)) return; + const key = m.name + '|' + kind; + if (seen[key] === undefined) { seen[key] = true; } else return; + let hex = ''; + try { hex = Array.from(new Uint8Array(data.readByteArray(Math.min(len, 96)))).map(b => b.toString(16).padStart(2, '0')).join(''); } catch (e3) {} + emit({ event: 'treq-magic', module: m.name, kind, len, head: hex, bt: btOk() }); + }, + }); + } catch (e4) {} + } + } +}, 2000);