986 字
5 分钟
如何获取 4399 SAuth(Android 渠道)
2026-03-10
无标签
NOTE

本文由现有代码,在 AI 辅助下完成。若在实现时遇到问题,欢迎询问。

所需内容#

变量说明
verify_session验证码 ID,随机生成的 48 位十六进制字符串
DEVICE_IDENTIFIER设备标识符,格式:yyyyMMddHHmmss + 38 位随机十六进制
DEVICE_IDENTIFIER_SM副设备标识符,生成规则同上
username4399 账号用户名
password4399 账号密码
udid随机生成的 16 位十六进制字符串(用于最终 sauth_json)

步骤详解#

1. 获取文字验证码#

GET https://ptlogin.4399.com/ptlogin/captcha.do?captchaId={{verify_session}}

返回一张验证码图片,读出验证码记为 verify_code

2. 获取 OAuth 登录 URL#

POST https://m.4399api.com/openapiv2/oauth.html
User-Agent: Dalvik/2.1.0 (Linux; U; Android 16; Build/UKQ1.231108.001) 4399android 4399OperateSDK
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
usernames=&top_bar=1&state=&device={{device_json}}

device_json 为以下结构序列化后的字符串:

字段
DEVICE_IDENTIFIER见上文
DEVICE_IDENTIFIER_SM见上文
DEVICE_MODELAndroid
DEVICE_MODEL_VERSION16
SYSTEM_VERSION16
PLATFORM_TYPEAndroid
SDK_VERSION3.12.2.503
GAME_KEY115716
GAME_VERSION3.7.15.287957
BIDcom.netease.mc.m4399
RUNTIMEAndroid
NETWORK_TYPEWIFI
TEAM2
其余字段空字符串

从响应 JSON 中取 result.login_url,解析其 Query 参数,记录 client_idrefstate

3. 提交账号密码登录#

POST https://ptlogin.4399.com/oauth2/loginAndAuthorize.do?channel=&sdk=op&sdk_version=3.12.2.503
User-Agent: Mozilla/5.0 (Linux; Android 16; ...) 4399android 4399OperateSDK
Origin: https://ptlogin.4399.com
Referer: https://ptlogin.4399.com/oauth2/authorize.do?channel=&sdk=op&sdk_version=3.12.2.503
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
username={{username}}
&password={{password}}
&captcha_id={{verify_session}}
&captcha={{verify_code}}
&response_type=TOKEN
&client_id={{client_id}}
&ref={{ref}}
&state={{state}}
&scope=basic
&bizId=2100001792
&auth_action=ORILOGIN
&redirect_uri=https://m.4399api.com/openapi/oauth-callback.html?gamekey=44770&game_key=115716
&reg_mode=reg_phone
&isInputRealname=false
&isValidRealname=false
&sec=0
&show_topbar=false
&css=
&show_close_button=
&show_4399=
&username_history=
&uid=
&expand_ext_login_list=
&autoCreateAccount=
&show_ext_login=
&show_back_button=
&auto_scroll=
&access_token=
&show_forget_password=
&aid=
&cid=
WARNING

不跟随重定向,期望收到 3xx 响应。若非 3xx,则登录失败,可从响应 HTML 中提取错误信息(如实名认证失效、验证码错误等)。

取响应头 Location,记为 callback_url,然后 GET 该地址获取登录结果 JSON。

4. 处理登录结果#

响应 JSON 中的 code 字段:

code含义
100登录成功,取 result.uidresult.state
103需要二次人机验证,取 result.url 作为验证码接口地址,进入步骤 5
其他登录失败

5. 处理二次验证码(code=103 时)#

5.1 获取验证码数据#

GET {{result.url}}

根据 URL 路径判断验证码类型,取对应字段:

URL 含类型响应字段
jigsaw拼图滑块result.imgresult.img2result.captchaId
click文字点击result.imgresult.textresult.captchaId

5.2 拼图滑块(jigsaw)#

图片说明

  • result.img:背景图(含缺口),base64 编码的 PNG,从图片左上角开始剪切 544×270 作为背景图
  • result.img2:滑块图片,base64 编码的 PNG,需叠加在背景图左侧起始位置

用户操作

将两张图片叠加展示,滑块初始位于最左侧(x=0)。用户横向拖动滑块至缺口位置后释放,记录拖动距离(像素)。

若展示容器宽度与原始图片宽度不一致(存在缩放),需按比例换算为实际坐标:

actualDistance = round(displayDistance / containerWidth * 544)

answer 构造

将实际距离组装为 JSON:

{"x": {{actualDistance}}}

然后用 AES-CBC 加密该 JSON 字符串:

参数
KeyMD5(“df0a5f98c337de97”)(16 字节)
IVUTF-8 bytes of “79c83220d9974edf”(16 字节)
ModeCBC
PaddingPKCS7
输出Base64 字符串

最终 answer = 上述 Base64 密文,URL 编码后作为 v 参数提交:

GET https://m.4399api.com/captcha/jigsaw-check.html?refer=sdk&v={{answer}}&captchaId={{captchaId}}

5.3 文字点击(click)#

图片说明

  • result.img:待点击的图片,base64 编码的 PNG,原始尺寸 544×306
  • result.text:需要点击的文字,逗号分隔,如 "字A,字B,字C",点击次数由逗号分隔数量决定

用户操作

展示图片,用户按 result.text 的顺序依次点击图中对应文字,共需点击 N 次(N = result.text 中逗号分隔项的数量)。

每次点击记录坐标,若展示尺寸与原始尺寸不一致,需换算:

actualX = round(displayX / displayWidth * 544)
actualY = round(displayY / displayHeight * 306)

answer 构造

将所有点击坐标按顺序组装为 JSON 字符串(不加密):

{"w": 544, "h": 306, "c": [{"x": {{x1}}, "y": {{y1}}}, {"x": {{x2}}, "y": {{y2}}}, ...]}

URL 编码后作为 v 参数提交:

GET https://m.4399api.com/captcha/click-check.html?refer=sdk&v={{answer}}&captchaId={{captchaId}}

5.4 处理校验结果#

响应 code处理
!= 100重新 GET result.url 刷新验证码数据,要求用户重试
100result.token,进入下一步完成登录

取得 result.token 后,构造验证码凭据 JSON 字符串:

{"v_token": "{{token}}", "captcha_id": "{{captchaId}}", "type": "0"}

将该字符串 URL 编码,作为 captcha 参数追加到 callback_url,再次 GET 完成登录,回到步骤 4 处理结果。

6. 构造 SAuth#

{
"sauth_json": "{{sauth_json_dump}}"
}

sauth_json_dump 为以下 JSON 序列化后的字符串:

{
"aim_info": "{\"aim\":\"127.0.0.1\",\"country\":\"CN\",\"tz\":\"+0800\",\"tzid\":\"\"}",
"realname": "{\"realname_type\":2}",
"app_channel": "4399com",
"platform": "ad",
"client_login_sn": "{{DEVICE_IDENTIFIER}}",
"gameid": "x19",
"login_channel": "4399com",
"sdk_version": "3.12.2",
"sdkuid": "{{uid}}",
"sessionid": "{{state}}",
"udid": "{{udid}}",
"deviceid": "{{DEVICE_IDENTIFIER}}"
}
如何获取 4399 SAuth(Android 渠道)
https://qwq.cam/posts/pe-sauth-guideance/
作者
汐洛
发布于
2026-03-10
许可协议
CC BY-NC-SA 4.0