ksjsb/docs/capture_login_chain.md
2026-07-30 20:25:56 +08:00

9.8 KiB
Raw Blame History

capture/ 登录链路 + APP 初始化 实测分析

来源:capture/ Reqable body-only 抓包导出1738 文件) 时间2026-07-23 06:32 起session B全新装机 + 登录) 目标设备:did=ANDROID_f05497e9cef09a7f(与 .env 账号设备 e8dfd2f16b618053 不同 = 全新装)

0. 抓包格式与固有限制

  • 文件命名:{ts_ms}-{flowId}-{part}-{type}.reqableflowId/ts 决定时序。
  • 类型:req_raw-body(请求体,常为加密 {"data":"..."} 或明文 formres-raw-body原始响应chunked/gzip 二进制)、res-extract-body已解码响应 JSON主要可读源)、req-extract-body(解码请求体)。
  • 无 URL/header/method 文件。端点只能从 body 内容 + 响应推断。
  • 混入少量酷狗(com.kugou.androidflow 466/467噪声主体是快手 nebula。
  • 请求体多为 kwsg 加密;关键字 grepmobile/smsCode命中的多是日志上报flow 577 几百段=批量 log非登录。

1. APP 初始化序列session B06:32 起,已登录前 uid=0

flow 时间 端点(推断) 关键字段
13 06:32 冷启动首批请求
171 06:48 配置拉取 public_param{uid:0,did,kpn:NEBULA,kpf,app_version} + request_info[{config_name:config}]
189 ~06:xx DFP 设备注册 productName=NEBULA&ts=...&deviceInfo=<urlenc>= gdfp_report/unified_fetch,已还原于 core/dfp_forms.py
272/274 ~08:44 域名-IP 路由表 domains[]{domain,iplist{ipv4,ipv6}}(含 api.e.kuaishou.comid.kuaishou.com 等,非登录

DFP bootstrap设备 did+egid 在线注册)在登录前完成,与 tools/new_device.py 已还原链路一致。✓

2. 登录链路(核心发现)

登录方式 = 运营商一键登录provider-token非手机号短信

flow 22108:18登录提交请求体明文 + 已还原签名):

provider=11
&provider_token=CgZORUJVTEESGEFORFJPSURfZjA1NDk3ZTljZWYwOWE3ZhjdzY/JgMgdIKy0l/v4Mw==
&session_id=eab9a270-1d55-45a2-97dd-f4f32f9c3eb8
&cs=false&os=android&client_key=2ac2a76d
&sig=6d37a2436f910601ef23cd2b6fd212f2
&__NS_sig3=544530168b10f35b1f1c1f1ecddd17765822656c010d0315
&__NS_xfalcon=HUDR_sFnX+...==$TE_253aa3c5c5193634544b6e193634544b...

provider_token base64 解码为 protobuf

field1(string) = "NEBULA"                      # kpn
field2(string) = "ANDROID_f05497e9cef09a7f"    # did
field3(varint) = 0xddcd8fc980c81d              # 时间戳类
field4(varint) = 0xacb497fbf833                # nonce/凭证

{kpn, did, ts, nonce}——由运营商一键登录 SDK(如移动认证/极光一键登录)签发,绑定设备 did。

  • provider=11 = 认证 provider 编码(一键登录)。
  • 请求签名 sig/__NS_sig3/__NS_xfalcon 全部用已还原算法可复算。✓

登录响应

  • flow 221 响应{"result":1,"bind_interval_ms":604800000} → 登录成功,设备绑定有效期 7 天604800000 ms
  • flow 22208:19疑似 getLoginUser/refreshToken 后续)响应
    {"dataRsp":"<576B base64>","result":1,"error_msg":""}
    
    result=1 = 成功。会话票据(api_st/h5_st/user_id/client_salt)封装在 dataRsp 加密块内。

3. 会话票据加密层(关键)

  • dataRsp576Bhead8 = 7a1c41a6 6f7ee464
  • 不属于已还原的 kwsg 10400 ZT envelopehead85a54eecd...,见 core/enc_data.py:ZT_OUTER_CONFIGS)。
  • 判定:登录会话走 libpfl_crypto 层(Pfl.decryptBinaryNativeFINDINGS 历史"解密方向"用的是 native 桥,纯 Python 解密未还原)。
  • 对比reward/ad 的 encData = kwsg 10400已还原纯 Python 加密);登录 dataRsp = libpfl未还原纯 Python
  • 另:api_st/h5_st 也可能下发在响应 headerbody-only 抓包看不到)——子代理此前同样怀疑此点。

4. 与既有结论的交叉验证

  • out/FINDINGS.md:2476-2504 已实测:直接换 H5 did/egid → signIn/reporttreasureBox/report 返回 result=50 签名验证失败。H5 真正缺口是 kwssectoken/kwscode/kwfv1/kww 票据组Yoda/KsGuard/WebView 安全层)。
  • 本次 capture 未见 kwssectoken/kwscode/kwfv1/kww 在 body 中签发 → 这组票据是 WebView/JS 运行时产物或 headerHTTP body 抓包不包含其生成。kww 在真实 App 中确为请求 headermain.py:H5_HEADERS.kww),本抓包无 header → 不可见。

5. "新设备纯 Python 登录"的阻塞点(结论)

阻塞点 性质 现状
① 运营商 provider_token 外部黑盒(运营商一键登录 SDK需 SIM+设备) 无法纯 Python 生成;本抓包只看到它被消费
dataRsp 会话解密 libpfl_crypto envelopehead8 7a1c41a6 未纯 Python 还原(历史仅 native 桥)
kwssectoken/kwscode/kwfv1/kww Yoda/KsGuard/WebView 运行时票据 不在 HTTP body 抓包H5 写请求换设备必 result=50
KS 侧请求签名 sig/__NS_sig3/__NS_xfalcon 已还原 ✓ 可复算登录请求
DFP 设备注册 已还原 ✓ 新设备可在线注册

含义

  • "新设备 + 复用已有账号 token 跑任务"A 路线API 侧可行(已验证 200H5 侧被 ③ 卡死result=50除非补 kws* 票据(需 WebView JS 逆向,不在 HTTP 抓包内)。
  • "新设备 + 全新登录拿设备绑定 token"B 路线):被 ①② 卡死。① 要么复刻运营商一键登录 SDK极难、需 SIM要么改走手机号+短信登录(本抓包未捕获该路径,需另抓);② 需还原 libpfl_crypto 纯 Python 解密。

6. 关键 flow 索引

flow 文件前缀 用途
13 1784817239557610-13-* 冷启动
171 1784817240305029-171-1-* 配置拉取
189 1784817240121*-189-1-* DFP 设备注册deviceInfo
213 1784817244968189-213-1-* 登录前加密请求3798B待解
221 1784817247*-221-1-* 登录提交provider_token明文+签名)
222 1784817247*-222-1-* 登录后续响应dataRsp 会话,加密)
272/274 1784817247*-27[24]-1-* 域名-IP 路由表

7. 下一步可选

  1. 解密 flow 222 dataRsp:还原 libpfl_crypto 纯 Python 解密(参照 EmbeddedAesKeyHex + Pfl.decryptBinaryNative 的 native 逻辑),取出 api_st/h5_st/user_id/client_salt 明文,确认是否设备绑定。
  2. 抓手机号+短信登录路径:作为 ① 的替代(更可纯 Python 复刻),需真机抓一次短信登录 HAR。
  3. WebView JS 逆向 kws 票据*:解 ③,才能真正让新设备跑 H5 写请求。

8. pfl_crypto 静态逆向进展dataRsp 解密2026-07-23

已拿到(新硬证据)

  • 内嵌 AES key 已静态还原(此前 FINDINGS 认为需 runtime frida
    • EmbeddedAesKeyHex @ libpfl_crypto.so:0x6249clazy singletonguard @ 0x111f78storage @ 0x111fa0)。
    • 构造器 0x62550:分配 64 字节,key[i] = blobA[i] ^ blobB[i % 32]i=0..63)。
      • blobA @ 0x182c864BblobB @ 0x1830832B循环
    • 还原结果:027e5393fd36a4ba1b6cf52094edb4aeffcc55d175492d87ed7df271eb691ef064 hex = AES-256 key
    • 诱饵 WrongEmbeddedAesKeyHex @ 0x625e4blobs 0x18328/0x18368= 真 key 首字节 XOR 0x10 -> 127e...
  • AesDecrypt @ 0x62fbc1728Bhex-decode key 串(校验 len 0x40=AES-256 / 0x20=AES-128随后对密文做自定义字节重排memcpy @ 偏移 0xcend-0x10),再调内部 cipher。
  • 排除 kwsg-10400dataRsp head8=7a1c41a6...,用 4 个已知 kwsg xor_key 解包后 inner magic 均 ≠ dec0adde;且 7a1c41a6 非 kwsg head85a54ee..-> dataRsp 不是 kwsg 10400 envelope,是 pfl 自有格式。
  • 设备绑定已硬证据(无需解密 dataRsp
    • 登录请求 flow 221 provider_token = protobuf {kpn=NEBULA, did=ANDROID_f05497e9cef09a7f, ts, nonce} -> 登录凭证构造上就绑设备 did
    • probe3.log 常规任务请求携带 klinkToken(同结构 protobuf含 .env 设备 did-> 设备绑定 token 随请求流转。
    • out/FINDINGS.md 实测:换 H5 did -> result=50 签名验证失败

仍阻塞(需动态捕获)

  • cipher 是 standard AES硬件实现libpfl_crypto.so 用 ARM 硬件 aese/aesd/aesmc/aesimc(全 .so 共 1769 条),故无软件 S-box/rcon/T-table。
  • 用还原 keyreal/decoy对 dataRsp 试遍 ECB/CBC/CTR/CFB/OFBAES-128/256 IV@首16/末16/0/12/16/32ct 全/[16:]/[16:-16]/[32:] 等)均乱码 -> dataRsp 不是简单 AesDecrypt(还原key, dataRsp)
    • 要么 dataRsp 用的 key 非 EmbeddedAesKeyHex会话派生 / RSA 包裹 / 另一静态 key
    • 要么缺 Pfl.decryptBinaryNative第二个参数 envelopebody-only 抓包看不到, IV/envelope 可能来自该 arg 或响应 header
    • 要么 dataRsp 走的不是 pfl网络层另解
  • AesDecrypt@0x62fbc 字节重排:把密文拆 [0:12] / [12:N-16] / [N-16:N] 三段 std::string再调硬件 AES0x9492c等 + 循环)。
  • 要拿 dataRsp 明文,需动态捕获真正用的 (key, envelope, IV, plaintext)。 已写探针 out/probe_pfl_login.js:登录时 hook Pfl.decryptBinaryNative
    • pfl::crypto::AesDecrypt + EmbeddedAesKeyHex,命中 api_st/h5_st/user_id 即打印明文。

结论

  • 设备绑定问题已有硬答案 = 是(请求侧 provider_token 内嵌 did + H5 换设备 result=50
  • dataRsp 明文api_st/h5_st/user_id 具体值)需动态跑 out/probe_pfl_login.js 抓取key 已静态还原但 dataRsp 非该 key 直解,缺 envelope/session key。属 "确认响应侧 token 是否也带 did 校验"的锦上添花项,不改变绑定结论。