9.7 KiB
快手极速版 短信登录链路(纯 Python 可复刻路径)
来源:
login_gateway_plugin-master.apk(jadx)+ 主 app jadx(zvl.aRetrofit 接口) 日期: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 + 设备)门槛低得多。
登录 API(Retrofit 接口 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/mobileVerifyCode(r0)、n/user/login/token(s0)、n/user/login/mobile(148)、n/user/login/mobileQuick(197,一键)、n/user/login/quickLogin(140)、n/user/login/preCheck(205)、/rest/n/loginRegister/unified/verify(258)。
响应: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 | 加密 dataRsp(libpfl,未纯 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,后续任务链即可用新设备+新会话跑
待确认 / 风险
- host:
/rest/n/user/login/...走 aegon 网关,确切 host 需实测确认 (候选:api2.kuaishou.com/apissl.ksapisrv.com/api.ksapisrv.com)。 静态未见明文 base URL(zvl.a经pnm.b.b(1559932927)DI 创建,base URL 在网络模块)。 - 签名:高概率走已还原的
sig/__NS_sig3/__NS_xfalcon(运营商登录 flow 221 实测带这些, 同一网络层),验码 FieldMap 中已补publicKey/raw/secret账号保护字段。 - 请求是否带 encData:
@FormUrlEncoded+ flow 221 明文先例 -> 判定明文 form,无 encData。 待实测确认。 - 风控:新设备 + 短信登录可能触发设备校验/短信频控/异地登录提示,需小流量验证。
- 收码:必须能接收短信(自有手机或接码平台),这是 SMS 登录固有限制。
关键文件索引
- Retrofit 接口:
out/jadx/sources/zvl/a.java(M发码,r0mobileVerifyCode) LoginUserResponse:含kuaishou.api_st/h5_st/api_client_salt/userInfoRequestVerifyCodeResponse:{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 body,URL query 只放设备参数。parse_login_user_response(data)解析明文LoginUserResponse。- sig3 使用进程级
Kwsg10418State:seed 按 nativesrand(time) -> rand()+1现场生成,验证码重放、发码和登录共享同一递增 counter。
tools/sms_login_cli.py:CLI 闭环(全新设备画像 -> 在线 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
requestMobileCode 或 mobileVerifyCode 同时返回 result=705 和 HTTPS
error_url 时,CLI 自动尝试验证码求解,并在拿到 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,也不会进入验证重试。
实测需确认:
- host:默认
apissl.ksapisrv.com;若result!=1/网络错误,再换api2.kuaishou.com/api.ksapisrv.com/api.e.kuaishou.com。 - session_seed/counter:seed 是每进程动态值,不是固定常量;CLI 已纯 Python
复现 native PRNG,并从启动后基线
counter=0x5f开始让所有请求连续递增。 CLI 不提供固定 seed/counter 的复现入口。 - 响应明文:
mobileVerifyCode响应应直接含kuaishou.api_st/h5_st/api_client_salt。 - userInfo.user_id 字段名:解析已兼容
user_id/userId/eid/uid。 - 验证码位数 / type 归属:复核
PhoneVerifyParams与zvl.a.B(map)后确认, APP 6 位码对应“手机验证页”路径:requestMobileCode(type=6)->n/user/verify/mobile,返回ActionResponse,不是直接登录拿会话。 用户实测type=1文案为“仅用于注册”,不用于登录;CLI 直接登录固定使用type=27。
登录成功后 CLI 会自动输出可直接写入 .env 的
ksck="账号#完整 Cookie#client_salt",无需额外参数。