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

9.7 KiB
Raw Blame History

快手极速版 短信登录链路(纯 Python 可复刻路径)

来源:login_gateway_plugin-master.apkjadx+ 主 app jadxzvl.a Retrofit 接口) 日期2026-07-24 关联:docs/capture_login_chain.md(运营商一键登录 = 加密 dataRsp难复刻

核心结论

短信登录是纯 Python 可复刻的登录路径:请求为明文 form响应为明文 JSON直接返回 api_st/h5_st/api_client_salt/userInfo无需 pfl/kwsg 解密(与运营商一键登录的 加密 dataRsp 不同)。

唯一非 Python 环节:接收短信验证码(需一台能收码的手机/接码服务)--但比运营商 一键登录(需 carrier SDK + SIM + 设备)门槛低得多。

登录 APIRetrofit 接口 zvl.a,全部 POST form

1. 发送短信验证码

POST  n/user/requestMobileCode        # 方法 M@FormUrlEncoded
form:
  mobileCountryCode   "+86"
  mobile              "<手机号>"
  type                27              # 已存在手机号短信登录
  useVoice            false
  needCheck           true
  prefetchPhoneNumber ""
  requestSource       "<来源>"
query:
  + sig / __NS_sig3 / __NS_xfalcon / client_key / os / did / egid / oDid / rdid / ...
-> RequestVerifyCodeResponse { result, isCheck, phone[] }

2. 验证码登录(拿会话)

POST  /rest/n/user/login/mobileVerifyCode  # 方法 r0@FormUrlEncoded@y0n.d Map
query:
  did / egid / oDid / rdid / client_key / os / ...
form (动态 map / FieldMap):
  code / mobile / mobileCountryCode / type=27 / isDegraded=false
  deviceName / deviceMode / publicKey / raw / secret
  + sig / __NS_sig3 / __NS_xfalcon
-> LoginUserResponse  (明文 JSON见下

签名细节2026-07-24 Frida + jadx 确认):

  • sig = CPU.getClock(sorted(query + body 非签名字段))
  • __NS_sig3 = KSecurity.atlasSign(encodedPath + sig)
  • __NS_xfalcon = KXGS((sig + __NS_sig3).getBytes(), 2096)
  • encodedPath 只用于 sig3 与跳过列表判断;xfalcon 原始 byte[] 不包含 path

相关变体(同接口):

  • n/user/login/mobileVerifyCoder0n/user/login/tokens0n/user/login/mobile148n/user/login/mobileQuick197一键n/user/login/quickLogin140n/user/login/preCheck205/rest/n/loginRegister/unified/verify258

响应LoginUserResponse明文含完整会话

直接 JSON 字段(@c 注解 = JSON key

字段 JSON key 用途
mApiServiceToken kuaishou.api_st API 会话 token
mH5ServiceToken kuaishou.h5_st H5 会话 token
mNewTokenClientSalt kuaishou.api_client_salt client_salt__NStokensig 用)
mobile / mobileCountryCode mobile / mobileCountryCode 登录手机号
mPassToken passToken pass token
quickloginToken quickloginToken 一键登录 token
userInfo / multiUserInfo userInfo / multiUserInfo 用户信息(含 user_id
codeKey / codeUri codeKey / codeUri 二维码登录用
bindPhoneRequired / canLogin / canQuickLogin / isNewRegisterUser / loginType 同名 登录态标志

响应包装:Observable<ylm.d<LoginUserResponse>> -> 标准 KS 信封 {result:1, error_msg:"", data:{ kuaishou.api_st, kuaishou.h5_st, kuaishou.api_client_salt, ... }} 明文,非 dataRsp 加密

与运营商一键登录对比

维度 短信登录 mobileVerifyCode 运营商一键 quickLogin
请求 明文 form + sig/sig3/xfalcon 明文 form provider=N&provider_token=<carrier proto>
凭证来源 手机号 + 收到的短信码 carrier SDK token需 SIM+设备+SDK
响应 明文 LoginUserResponse 加密 dataRsplibpfl未纯 Python 还原)
纯 Python 可行 (仅缺收码) carrier token + dataRsp 解密两道黑盒)

复刻流程(纯 Python

新设备画像DFP bootstrap 在线注册 did/egid/oDid/rdid已还原
  ↓
POST /rest/n/user/requestMobileCode  (mobile=手机号, did=新设备, sig/sig3/xfalcon)
  ↓  服务端发短信
[人工/接码] 收到验证码
  ↓
POST /rest/n/user/login/mobileVerifyCode
  (query=设备, body=code/type=27/publicKey/raw/secret/sig/sig3/xfalcon)
  ↓  明文响应
LoginUserResponse -> 取 kuaishou.api_st / kuaishou.h5_st / api_client_salt / userInfo
  ↓
写入 .env / cookie_dict后续任务链即可用新设备+新会话跑

待确认 / 风险

  1. host/rest/n/user/login/... 走 aegon 网关,确切 host 需实测确认 (候选:api2.kuaishou.com / apissl.ksapisrv.com / api.ksapisrv.com)。 静态未见明文 base URLzvl.apnm.b.b(1559932927) DI 创建base URL 在网络模块)。
  2. 签名:高概率走已还原的 sig/__NS_sig3/__NS_xfalcon(运营商登录 flow 221 实测带这些, 同一网络层),验码 FieldMap 中已补 publicKey/raw/secret 账号保护字段。
  3. 请求是否带 encData@FormUrlEncoded + flow 221 明文先例 -> 判定明文 form无 encData。 待实测确认。
  4. 风控:新设备 + 短信登录可能触发设备校验/短信频控/异地登录提示,需小流量验证。
  5. 收码:必须能接收短信(自有手机或接码平台),这是 SMS 登录固有限制。

关键文件索引

  • Retrofit 接口:out/jadx/sources/zvl/a.javaM 发码,r0 mobileVerifyCode
  • LoginUserResponse:含 kuaishou.api_st/h5_st/api_client_salt/userInfo
  • RequestVerifyCodeResponse{result, isCheck, phone[]}
  • login_gateway_plugin-master.apk:仅 carrier 一键登录(联通/电信/移动 SDK + AuthModel 无短信路径 -> 短信登录在主 app。
  • 主 app 调用点:com.yxcorp.login.bind.*ChangePhoneFragment 等)

实现已完成2026-07-24

  • core/sms_login.py
    • login_api_params(profile) 设备+app 参数(静态协议字段 + device_profile_cookie_fields 覆盖)。
    • signed_login_url(path, params, body_pairs, state, base_url, t1, t2) 签名 URL sig / __NS_sig3 / __NS_xfalcon__NStokensig,登录态未建立)。
    • request_mobile_code(...) -> RequestVerifyCodeResponse(发码)。
    • login_by_code(...) -> LoginSession{api_st, h5_st, client_salt, user_id, mobile, pass_token} login/* 为 Retrofit @FieldMap,签名字段放在 form bodyURL query 只放设备参数。
    • parse_login_user_response(data) 解析明文 LoginUserResponse
    • sig3 使用进程级 Kwsg10418Stateseed 按 native srand(time) -> rand()+1 现场生成,验证码重放、发码和登录共享同一递增 counter。
  • tools/sms_login_cli.pyCLI 闭环(全新设备画像 -> 在线 DFP 注册 -> 发码 -> 输入码 -> 会话)。每次执行都不读取或保存历史设备、抓包字段及区域票据。
  • CLI 只提供 --mobile--code--base-url--transport;短信类型、 超时、sig3、region 和验证码重试策略均由内部固定。

待实测确认(用 CLI 跑一次真机即可)

# 真实流程(在线注册全新设备 -> 发码 -> 输入码 -> 会话)
uv run python -m tools.sms_login_cli --mobile <手机号>

# 如果发码请求超时但手机已收到短信,可跳过发码继续验码:
uv run python -m tools.sms_login_cli --mobile <手机号> --code <收到的验证码>

# 可选覆盖登录 host
uv run python -m tools.sms_login_cli --mobile <手机号> --base-url https://api.ksapisrv.com

# 可选切换 HTTP 传输:
uv run python -m tools.sms_login_cli --mobile <手机号> --transport okhttp4-android10

requestMobileCodemobileVerifyCode 同时返回 result=705 和 HTTPS error_urlCLI 自动尝试验证码求解,并在拿到 captchaToken 后重放原请求。 每个阶段内部最多重试 2 次。HTTP 求解未拿到 captchaToken 时直接停止,不启动 Playwright、Edge/Chrome 或系统浏览器。

当前 14.5.50.11631 匿名登录 query 已按 APP 样本对齐 kcv=1630,并补齐 language/ud/bottom_navigation/is_background/icaver/darkMode/ftt。这些字段参与签名和 服务端设备上下文判断,不能继续使用旧版本默认值。

登录阶段的 raw/publicKey/secret、设备画像、手机号密文和 passport_account_image 在当前 CLI 流程内固定,验证后重试时保持原请求正文一致。

当请求表现为 status=0 body={}CLI 会额外打印底层 error 字段。该状态属于 传输失败,不会误判为 705也不会进入验证重试。

实测需确认:

  1. host:默认 apissl.ksapisrv.com;若 result!=1/网络错误,再换 api2.kuaishou.com / api.ksapisrv.com / api.e.kuaishou.com
  2. session_seed/counterseed 是每进程动态值不是固定常量CLI 已纯 Python 复现 native PRNG并从启动后基线 counter=0x5f 开始让所有请求连续递增。 CLI 不提供固定 seed/counter 的复现入口。
  3. 响应明文mobileVerifyCode 响应应直接含 kuaishou.api_st/h5_st/api_client_salt
  4. userInfo.user_id 字段名:解析已兼容 user_id/userId/eid/uid
  5. 验证码位数 / type 归属:复核 PhoneVerifyParamszvl.a.B(map) 后确认, APP 6 位码对应“手机验证页”路径:requestMobileCode(type=6) -> n/user/verify/mobile,返回 ActionResponse,不是直接登录拿会话。 用户实测 type=1 文案为“仅用于注册”不用于登录CLI 直接登录固定使用 type=27

登录成功后 CLI 会自动输出可直接写入 .envksck="账号#完整 Cookie#client_salt",无需额外参数。