返回

PJSK 证书抓包教程

25 / 10 / 4 更:本文不再更新

本文不再更新。

这篇文章将被保留并归档,但不会再进行任何更新。如果你看到这篇文章时本文仍对你有所帮助,那么我此刻选择将本文保留而不是删除,大概就是有意义的吧?

25 / 8 / 31 更:请先阅读!

国服安卓并非无解~


本文的模拟器抓包部分流程是基于新版本 MuMu 模拟器撰写的,但国服安卓(包括官服与 b 服)会检测 Windows 上的新版本 MuMu 模拟器,若坚持使用本文方法与最新版 MuMu 模拟器则需要通过逆向手段绕过。这非常麻烦,但我们可以避免这一问题。
国服安卓抓包最简单的方式是考虑老版本 MuMu 模拟器或一些小众模拟器,因为国服安卓的检测手段不会针对这些模拟器。例如,可以参考 官服、B服安卓手机抓包教程,这篇文档提供了使用其他模拟器以简单但有效地绕过国服主流模拟器检测的解决方案。
本文的方案总体上是通用的,但可能会因为后续版本的模拟器检测、SSL Pinning 等问题需要进行一些额外的操作。对于国服安卓,我建议可以先阅读上文所给出的引用链接的文档。

安卓模拟器证书抓包

前言

考虑到台服、韩服不支持引继,加之不少实体安卓设备 root 困难(无论是否经过自定义证书,至少需要 root 才能解密 SSL 流量),因此台服、韩服的安卓设备用户抓包需要借助模拟器。在 root 的模拟器中可以使用证书解密流量,也可以考虑 eCapture(但依赖内核版本),本部分将一步一步介绍在模拟器上证书抓包的详细流程。

  • 国服安卓版本存在针对主流模拟器特征检测和代理检测,其中
    • 主流模拟器检测使得本方法的示例不直接适用于国服安卓版本,可以考虑逆向 hook 或更换其他模拟器,更换模拟器的方案即为文章 官服、B服安卓手机抓包教程 所介绍的方案;
    • 代理检测可以考虑支持 MITM 的代理客户端绕过;
  • 日服、国际服安卓用户可以考虑引继抓包,但也可以模拟器抓包;
  • 对于苹果用户,建议使用模块抓包,更加自动化。

注:截止至 2025 年 7 月,主流安卓模拟器内核版本均低于 5.5,eCapture 在这些设备上无法正常工作。经研究,可能是在低于 5.5 版本的内核上 bpf_probe_read_user 无法读取用户态数据导致的,因此本文主要介绍证书抓包的方法。持有实体安卓设备的用户可以考虑 eCapture。

准备工作

软件:

  1. 任意可 root 的安卓模拟器,以 MuMu模拟器 为例
  2. 任意抓包软件,以 Charles 为例
  3. Android SDK Platform-Tools
  4. OpenSSL for Windows(OpenSSL 可以仅下载但暂不安装,稍后按照教程安装)
  5. 如果是国服安卓版本,需要额外使用支持 MITM 解密 SSL/TLS 流量的代理客户端进行转发

硬件上只需要一台电脑。以下演示以 Windows 电脑的环境为例,Mac 电脑同理。

如果已不是第一次按本文方法流程抓包,则直接移步最后一步 开始抓包 即可!

Charles 设置

  1. 在 Proxy → Proxy settings 中勾选 Enable transplant HTTP proxying,端口 Port 保持默认的 8888 不变,点击 Done 保存改动;
  2. 在 Proxy → SSL Proxying Settings 中确认 Enable SSL proxying 为默认启用状态,随后在 Include 一栏(左栏)点击 +,Host 填入 *、Prot 填入 *,随后点击两次 Done 保存改动;
  3. 在 Help → SSL Proxying → Save Charles Root Certificate...,选择一个路径保存证书,例如 C:\Users\你的用户名\Desktop\abc.pem,但建议将证书保存至 Android SDK Platform-Tools 路径下。

模拟器设置

  1. 从右上角设置处进入 设置中心;

    设置中心
  2. 点击 其他 选项卡,找到 Root 权限,勾选 开启手机 Root 权限,并点击 保存设置;

  3. 设置中心 → 磁盘 → 磁盘共享 → 勾选 可写系统盘,模拟器将要求需要重启以应用更改,选择允许模拟器重启;

  4. 重启完毕后,在模拟器内进入 设置(包含在桌面的 系统应用 中)→ 关于手机 → 连续多次点击 版本号,直到提示已进入开发者模式;

  5. 在模拟器内进入 设置 → 系统 → 开发者选项 → 启用 USB 调试。

OpenSSL 安装

下载 OpenSSL for Windows 然后执行安装,基本上一直点击确定 / 继续即可,只有在下面这一步需要特别注意:

OpenSSL 安装

这里需要勾选 The OpenSSL binaries (/bin) directory。

最后软件希望我们为其捐赠的选项可以不勾选,将默认已勾选的 One-time $10 donation to Windows OpenSSL 的选项取消掉然后点击 finish 即可。

adb 操作(证书安装)

注:MuMu 模拟器默认启用了本地 adb 调试,因此无需设置。

  1. 在这一步需要使用到此前安装的 OpenSSL。

    • 对于 Windows11 用户,按住 WIn + S 搜索 “openssl” 将能够检索到此前安装的 Win64 OpenSSL Command Prompt,选中或回车;
    • 对于其他 Windows 系统版本或检索不到程序的用户,如果此前没有手动修改安装地址,则可在默认安装路径 C:\Program Files\OpenSSL-Win64 下找到 start.bat 批处理脚本文件,双击启动脚本。

    如果顺利,将启动一个终端。在终端中首先执行命令 cd SDK路径,其中 SDK路径 是 Android SDK Platform-Tools 所在的路径,这也是此前推荐的存放证书文件的路径——如果此前将证书存放到了其他位置,则应当 cd 到相应路径。

    接着,执行 openssl x509 -subject_hash_old -in 证书文件名 以获得证书的哈希值,其中 证书文件名 为你此前保存证书时输入的文件名。如果顺利,将得到下面的输出:

    获取证书哈希值

    其中第一行的 c866bff9 即为证书的哈希值(不同的版本、不同的设备上得到的证书哈希值可能不一样)。

    如果你此前将证书存放到了其他位置,在继续下一步前应首先执行命令 cd SDK路径。如果你此前按照推荐将证书文件放在了 SDK 路径下,则直接进行下一步。

  2. 接下来在终端中继续输入命令 adb connect 127.0.0.1:7555 以连接至 adb 服务端口,其中 7555 是 MuMu 模拟器的默认端口,对于别的常见模拟器:

    • 雷电模拟器:adb connect 127.0.0.1:5555
    • 夜神模拟器:adb connect 127.0.0.1:62001
    • 蓝叠模拟器:adb connect 127.0.0.1:5555

    如果顺利,应该能看到返回 connected to 127.0.0.1:7555 字样,然后输入命令 adb devices 再次确认,如果顺利,应该能看到返回结果:

    1List of devices attached
    2127.0.0.1:7555  device
    

    ⚠ 注意:如果此处列出了多个结果,例如

    1List of devices attached
    2127.0.0.1:7555  device
    3emulator-5554   device
    

    则下文中执行的 adb 命令需要通过 -s 短选项指定设备!

  3. 将证书文件重命名为 哈希值.0,例如演示中应当将证书重命名为 c866bff9.0,如果重命名是在资源管理器中操作的,则务必注意确保操作时未隐藏后缀名,如果不确定请百度 “Windows 资源管理器如何显示后缀”;

  4. 回到终端,在终端中输入命令 adb root 并回车执行。如果是第一次执行该命令,此时查看模拟器,模拟器内应当弹出询问是否同意操作的弹窗,选择允许,然后再次回到终端;

    ⚠ 注意:如果此前 adb devices 返回了多个结果则命令可能执行失败,此时应改为执行命令 adb -s 目标设备 root,对于 MuMu 模拟器而言通常是 adb -s 127.0.0.1:7555 root,对于其他模拟器则自行根据 adb devices 的结果在 -s 短选项后指定目标设备。

    当返回结果 restarting adbd as root 时表示操作成功。

  5. 执行命令 adb push 证书新文件名 /system/etc/security/cacerts;

    ⚠ 注意:如果此前 adb devices 返回了多个结果则命令可能执行失败,此时应改为执行命令 adb -s 目标设备 push 证书新文件名 /system/etc/security/cacerts,对于 MuMu 模拟器而言通常是 adb -s 127.0.0.1:7555 push 证书新文件名 /system/etc/security/cacerts,对于其他模拟器则自行根据 adb devices 的结果在 -s 短选项后指定目标设备。

  6. 执行命令 adb shell "chmod 664 /system/etc/security/cacerts/证书新文件名"。

    ⚠ 注意:如果此前 adb devices 返回了多个结果则命令可能执行失败,此时应改为执行命令 adb -s 目标设备 shell "chmod 664 /system/etc/security/cacerts/证书新文件名",对于 MuMu 模拟器而言通常是 adb -s 127.0.0.1:7555 shell "chmod 664 /system/etc/security/cacerts/证书新文件名",对于其他模拟器则自行根据 adb devices 的结果在 -s 短选项后指定目标设备。

开始抓包Ⅰ(台服 Suite 演示)

首先获取电脑的本地 IP。在 Charles 上依次按 Help → Local IP addresses,查看电脑的本地 IP。

  • 例如,我的电脑使用 Realtek 网卡并通过有线以太网接入网络,因此 Realtek PCIe GbE Family Controller 对应的 IP 便是本机当前的 IP,如下图所示:

    以太网网卡本地 IP
  • 或者,若电脑使用无线网卡接入网络,例如我的电脑使用的是 Intel AX200 无线网卡,则 Intel(R) Wi-Fi 6 AX200 160MHz 对应的 IP 便是本机当前的 IP,如下图所示:

    无线网卡本地 IP

回到模拟器的安卓系统内,依次按 设置 → 网络和互联网 → 互联网 → 齿轮图标,然后点击右上角的笔图标、再单击 高级选项 右侧的展开按钮以配置代理。

选择手动代理,在 代理主机名 填入 电脑本地 IP 地址,在 代理端口 填入 8888(若此前在 Charles 中更改了默认代理端口,则填入相应的端口而不是 8888),然后保存。

回到 Charles,如果是初次代理,则 Charles 会询问是否允许连接,选择允许(如果是初次代理但未询问是否允许连接,则在模拟器内进行一次任意网络活动即可触发,例如在浏览器中随便访问一个网站)。现在我们可以解密 SSL 流量了,确保 Charles 处于 recording 与 SSL proxying 状态,即右上角的录制图标和解锁图标应当处于选中、启用的状态:

确保 Charles 正在工作

现在再回到模拟器内,启动游戏并登录即可抓包。

  • 玩家数据抓包 发生在每次从标题界面进入游戏的时候
  • 烤森数据抓包 如果使用普通版抓包,则每次退出到标题界面重新进入烤森才会抓取 如果使用(强制刷新)版抓包,则每次进入烤森都会强制让游戏刷新数据,每次都能够抓取

如果是国服以外的游戏(日服、台服、国际服及韩服),一般此时直接登录游戏即可抓包。

⚠ 注意:国服嵌入了字节跳动 SDK,除检测虚拟机外还会检测代理。如果在开启代理后登录被提示 网络连接异常,请稍后再试,很可能是代理被检测。与此同时,经过我的测试发现国服似乎并不存在 SSL Pinning 而仅仅进行了代理检测,因此可以使用支持 MITM 的代理客户端将解密后的流量转发至 Charles 以解决本问题。

以台服为例,登录游戏后回到 Charles,可以看到如下内容:

抓取 Suite

对于台服而言,其中域名 mk-zian-obt-cdn.bytedgame.com 下的 Suite 就是我们的游戏账户资产数据(不包含 MySekai),如果是其他服务器则自行寻找相应的 Suite 即可。

截止至 2025/9/27,所有游戏服务器 Suite 与 MySekai 目标 URL 可参考后文 模块配置(全服务器 URL 模式)

我们对 Suite 右键保存便大功告成:

保存 Suite

如果使用 HarukiBot / Lunabot,在网站 上传Suite数据 | Haruki 工具箱 上传我们抓取的 Suite 便可以使用组卡功能了!

开始抓包Ⅱ(国服 MySekai 演示)

MySekai 的数据按相同流程操作即可获取,区别仅仅是目标 URL,这里以住区国服 MySekai 数据做演示。

对于国服,为了方便地绕开代理检测,我们使用某款支持 MITM 的本地代理客户端(例如 HttpCanary)将解密后的流量转发至 Charles,然后继续上文描述的抓包流程进行操作即可,最后当我们在游戏内进入到 MySekai 后就会收到响应报文。

对于国服而言,域名 mkcn-prod-public-60001-1.dailygn.com 下的 mysekai 即为 MySekai 数据。

截止至 2025/9/27,所有游戏服务器 Suite 与 MySekai 目标 URL 可参考后文 模块配置(全服务器 URL 模式)

国服烤森抓包

实体安卓设备证书抓包

前言

由于谷歌安全策略的限制,非 root 安卓用户已不能自行安装根证书,因此必须有已 root 的安卓设备才能通过证书抓包。

这里以通过 Magisk 获得 root 权限的小米 8 为例。至于如何获取 root 权限,本文不再赘述,这是因为不同品牌的设备、不同的 root 方式差别很大,这可能需要读者自行解决。例如,华为手机和澎湃系统的小米手机由于厂商的限制,普通用户基本上无法获取 root 权限;即使是演示所使用的这部小米 8,也因为骁龙 845 的 Fastboot 驱动问题在折腾了数个小时后才成功 root。

鉴于目标读者已经在实体安卓设备上取得 root 权限,因此本部分仅概述关键流程,不再像上文 安卓模拟器证书抓包 那样逐步演示。

⚠ 注意:国服嵌入了字节跳动 SDK,除检测虚拟机外还会检测代理。如果在开启代理后登录被提示 网络连接异常,请稍后再试,很可能是代理被检测。与此同时,经过我的测试发现国服似乎并不存在 SSL Pinning 而仅仅进行了代理检测,因此可以使用支持 MITM 的代理客户端将解密后的流量转发至 Charles 以解决本问题。

准备工作

硬件:

  1. 一台电脑,以 Windows 电脑为例
  2. 一部已 root 的实体安卓设备,以通过 Magisk 获取 root 权限的小米 8 为例(Android 10)
  3. 一根用于连接电脑与安卓设备的数据线

软件(不包括 hook 绕过 SSL Pinning 所需的软件,这部分内容请见 ):

  1. 任意抓包软件,以 Charles 为例
  2. Android SDK Platform-Tools
  3. OpenSSL for Windows(OpenSSL 请按上文教程安装)

Charles 的设置、证书文件的更名、OpenSSL 的安装与上文相同。请分别参考上文中的 Charles 设置、adb 操作(证书安装) 以及 OpenSSL 安装,同时确保实体安卓设备已激活开发者选项且启用 USB 调试功能。

在实体设备上安装证书

  1. 完成准备工作并将安卓设备与电脑连接后,使用 Android SDK Platform-Tools 在终端中执行 adb devices,如果顺利应当得到以下结果:

    12b74da54        device
    

    ⚠ 注意:若提示设备 unauthorized,例如 adb devices 返回结果

    12b74da54        unauthorized
    

    这可能是设备首次与电脑连接而未授权导致的,此时安卓设备上应弹出是否允许当前计算机对设备 USB 调试的弹窗,选择允许 / 确定后再次执行 adb devices,应该就可以得到正确的结果。

  2. 为 Shell 获取权限。执行 adb shell 进入 Android 设备的 Linux Shell 环境,然后执行 su 获取超级用户权限。对于 Magisk,此时安卓设备上可能会弹出是否允许 Shell 获取 root 权限,应迅速点击 “允许”,否则倒计时结束后将默认拒绝提权,提示 Permission denied。

    如果未及时同意授予权限,对于 Magisk,可在 Magisk → 超级用户 中手动允许 Shell 超级用户权限,再回到终端中执行 su。

  3. 挂载系统分区为可写。对于 Android 10+ 常见的 system-as-root 方案,system 分区被挂载在根目录 / 下,因此只需要挂载根目录可写,即执行 mount -o rw, remount /;对于 Android 10 以下的版本,可能应改为执行 mount -o rw, remount /system 以挂载 system 分区为可写。

  4. 推送证书。对于已更名为 哈希值.0 的证书文件,依次执行

    • 退出 Linux Shell 环境,执行 exit
    • 复制证书至某个不需要权限的目录,例如 /data/local/tmp,执行 adb push 已更名的证书文件 无需权限的证书存放目录
    • 回到超级用户的 Linux Shell 环境,执行 adb shell,再执行 su
    • 将证书推送至目标位置,执行 cp 存放证书的目录/证书文件名 /system/etc/security/cacerts/
    • chmod 644 /system/etc/security/cacerts/已更名的证书文件
    • chown root:root /system/etc/security/cacerts/已更名的证书文件
    • 重启以应用更改,执行 reboot

开始抓包

剩余步骤与安卓模拟器情况下的操作相同,配置代理再开始抓包即可,因此不再赘述。

⚠ 注意:国服嵌入了字节跳动 SDK,除检测虚拟机外还会检测代理。如果在开启代理后登录被提示 网络连接异常,请稍后再试,很可能是代理被检测。与此同时,经过我的测试发现国服似乎并不存在 SSL Pinning 而仅仅进行了代理检测,因此可以使用支持 MITM 的代理客户端将解密后的流量转发至 Charles 以解决本问题。

苹果设备证书抓包

  1. 古法抓包:苹果设备的证书抓包与上文安卓设备证书抓包没有任何本质区别,只不过在流程上较之安卓设备简化许多,因为比起谷歌,苹果允许用户直接自行安装并信任证书。

    所以这里就不过多介绍了,因为操作与上文是相同的。在按提示安装好并信任证书后,剩下的步骤与安卓设备证书抓包流程是一模一样的——配置代理,然后使用代理软件解密 SSL 流量。

  2. 模块转发自动上传:可以参考 Haruki工具箱 - iOS模块上传数据教程。没有复杂的操作,不需要任何专业的前置知识,因此本文不过多介绍;引用的链接能够很好地帮助用户使用苹果设备抓包。

如果选择通过模块直接自动将数据包上传至第三方服务器,那么用户不会获得数据包,至少 Shadowrocket 的脚本功能不支持将数据包下载至本地。按下文的方式,可以获取数据包——这对帮助其他人抓包,或者开发自己的烤森自动解析程序而言,都是有帮助的。

模块转发抓包

这一方法适用于任何服务器,即使是国服。缺点亦显而易见,你需要一台苹果设备。

我们的目的是抓取来自服务器的原始账户资产数据,例如 Suite 与 MySekai 数据。

本部分主要介绍模块抓包,因为这一方法更不易被检测,全服务器适用,包括限制最多的国服。

准备工作

硬件:

  1. 一部能够使用某个支持 MITM 代理客户端的设备,许多时候这会是一部苹果设备
  2. 一部能运行 Python 的设备,最好是搭载任何一个操作系统的电脑(实际上,即使是安卓手机也可以通过 Termux 运行 Python,所以移动设备也可以做到,但可能操作不便)

软件:

  1. 某个支持 MITM 代理客户端软件(本部分以 Shadowrocket 模块做演示,其他软件灵活调整即可)
  2. Python3

按 世界计划抓包教程 · 模块抓包 | ルナ茶 完成 Shadowrocket 模块抓包的前置准备工作。

模块配置

魔改模块配置基于 Lunabot烤抓包模块 | ルナ茶 的劳动成果,十分感谢!

只需要把 Lunabot烤抓包模块 | ルナ茶 提供的模块配置的 script-path 字段修改为指向稍后将运行 Python 设备的 URL 即可,譬如我的设备在内网中的 IP 是 192.168.1.12,那么就可以将 script-path 修改为 http://192.168.1.12:8000/upload.js。

例如,要抓取国服 Suite 数据,对于 Lunabot烤抓包模块 | ルナ茶 提供的原始 Shadowrocket 模块配置,

 1#!url=https://bot.teaphenby.com/public/modules/cn_suite.sgmodule
 2#!name=LunaBot世界计划抓包模块-国服(Suite)
 3#!desc=抓取世界计划国服游戏的Suite数据并上传到bot服务器
 4#!homepage=https://bot.teaphenby.com/public/tutorial/tutorial.html
 5#!author=NeuraXmy
 6#!redirect=1
 7#!mitm=2
 8#!total=3
 9
10[URL Rewrite]
11^https:\/\/submit\.backtrace\.io\/  reject
12
13[Script]
14SCRIPT_cn_suite_1 = type=http-response, requires-body=1, binary-body-mode=1, max-size=100000000, timeout=60, pattern=^https:\/\/mkcn-prod-public-60001-1\.dailygn\.com\/api\/suite\/user\/(\d+)$, script-path=https://bot.teaphenby.com/public/scripts/upload.js
15
16[Mitm]
17hostname=%APPEND% mkcn-prod-public-60001-1.dailygn.com, submit.backtrace.io

我们将其中的 [Script] script-path 字段修改为指向本地服务器的 URL,确保 [Script] pattern 字段与 [Mitm] hostname 字段分别为目标 URL 与目标域名:

 1#!name=国服游戏数据本地转发
 2#!desc=抓取游戏数据并转发到本地计算机
 3#!author=魔改自NeuraXmy
 4#!mitm=2
 5#!total=3
 6
 7[URL Rewrite]
 8^https:\/\/submit\.backtrace\.io\/  reject
 9
10[Script]
11SCRIPT_upload = type=http-response, requires-body=1, binary-body-mode=1, max-size=100000000, timeout=60, pattern=^https:\/\/mkcn-prod-public-60001-1\.dailygn\.com\/api\/suite\/user\/(\d+)$, script-path=http://192.168.1.12:8000/upload.js
12
13[Mitm]
14hostname=%APPEND% mkcn-prod-public-60001-1.dailygn.com, submit.backtrace.io

这里给出一些常见的 pattern,截止至 2025/9/27,记录如下:

Suite URL patternMySekai URL pattern
国服1. ^https:\/\/mkcn-prod-public-60001-1\.dailygn\.com\/api\/suite\/user\/(\d+)$
2. ^https:\/\/mkcn-prod-public-60001-2\.dailygn\.com\/api\/suite\/user\/(\d+)$
1. ^https:\/\/mkcn-prod-public-60001-1\.dailygn\.com\/api\/user\/(\d+)\/mysekai\?isForceAllReloadOnlyMysekai\=(True|False)$
2. ^https:\/\/mkcn-prod-public-60001-2\.dailygn\.com\/api\/user\/(\d+)\/mysekai\?isForceAllReloadOnlyMysekai\=(True|False)$
日服^https:\/\/production-game-api\.sekai\.colorfulpalette\.org\/api\/suite\/user\/(\d+)$^https:\/\/production-game-api\.sekai\.colorfulpalette\.org\/api\/user\/(\d+)\/mysekai\?isForceAllReloadOnlyMysekai\=(True|False)$
台服^https:\/\/mk-zian-obt-cdn\.bytedgame\.com\/api\/suite\/user\/(\d+)$^https:\/\/mk-zian-obt-cdn\.bytedgame\.com\/api\/user\/(\d+)\/mysekai\?isForceAllReloadOnlyMysekai\=(True|False)$
韩服^https:\/\/mkkorea-obt-prod01-cdn\.bytedgame\.com\/api\/suite\/user\/(\d+)$^https:\/\/mkkorea-obt-prod01-cdn\.bytedgame\.com\/api\/user\/(\d+)\/mysekai\?isForceAllReloadOnlyMysekai\=(True|False)$
国际服^https:\/\/n-production-game-api\.sekai-en\.com\/api\/suite\/user\/(\d+)$^https:\/\/n-production-game-api\.sekai-en\.com\/api\/user\/(\d+)\/mysekai\?isForceAllReloadOnlyMysekai\=(True|False)$

模块的使用方法请移步 世界计划抓包教程 · 模块抓包 | ルナ茶。

Python 同步脚本

编写代码,为模块生成远程 JavaScript 脚本,同时监听来自模块转发的数据。

在使用脚本之前,记得修改 LOCAL_IP!

 1import http.server
 2import socketserver
 3import os
 4import time
 5import re
 6from urllib.parse import urlparse
 7from datetime import datetime
 8
 9PORT = 8000
10LOCAL_IP = '192.168.1.12'
11
12def extract_api_type(url):
13    if re.search(r'/mysekai(\?|$)', url):
14        return 'mysekai'
15    if re.search(r'/suite/', url):
16        return 'suite'
17    return 'unknown'
18
19def generate_filename(api_type, original_url):
20    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
21    user_id = re.search(r'/user/(\d+)', original_url)
22    user_str = f"_user{user_id.group(1)}" if user_id else ""
23    return f"{api_type}{user_str}_{timestamp}_{os.getpid()}.bin"
24
25class RequestHandler(http.server.SimpleHTTPRequestHandler):
26    def do_GET(self):
27        if self.path == '/upload.js':
28            js_content = """
29            const upload = () => {
30                $httpClient.post({
31                    url: "http://%s:%d/upload",
32                    headers: { 
33                        "X-Original-Url": $request.url,
34                        "X-Request-Path": $request.path
35                    },
36                    body: $response.body
37                }, (error) => $done({}));
38            };
39            upload();
40            """ % (LOCAL_IP, PORT)
41
42            js_content = js_content.strip()
43            self.send_response(200)
44            self.send_header('Content-Type', 'application/javascript; charset=utf-8')
45            self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
46            self.send_header('Pragma', 'no-cache')
47            self.send_header('Expires', '0')
48            self.send_header('Content-Length', str(len(js_content.encode('utf-8'))))
49            self.end_headers()
50            self.wfile.write(js_content.encode('utf-8'))
51            return
52
53        self.send_response(404)
54        self.end_headers()
55
56    def do_POST(self):
57        original_url = self.headers.get('X-Original-Url', '')
58        api_type = extract_api_type(original_url)
59        filename = generate_filename(api_type, original_url)
60        content_length = int(self.headers['Content-Length'])
61        received_data = self.rfile.read(content_length)
62
63        with open(filename, 'wb') as f:
64            f.write(received_data)
65
66        print(f"Saved [{api_type.upper()}]: {filename}")
67        print(f"Source URL: {original_url[:100]}{'...' if len(original_url) > 100 else ''}")
68        print(f"File Size: {len(received_data)/1024:.2f} KB\n")
69
70        self.send_response(200)
71        self.send_header('Content-Type', 'text/plain; charset=utf-8')
72        self.end_headers()
73
74if __name__ == "__main__":
75    print(f"Universal Data Receiver running at http://0.0.0.0:{PORT}")
76    print("File naming format: [api_type]_[user]_[timestamp]_[pid].bin\n")
77    try:
78        with socketserver.TCPServer(("", PORT), RequestHandler) as httpd:
79            httpd.serve_forever()
80    except KeyboardInterrupt:
81        print("\nServer stopped by user")

开始抓包

启动 Python 脚本,启用模块并登录游戏,抓取的数据将保存在 Python 脚本当前的工作路径。

API 解密

首先安装由 mos9527 编写的工具库 sssekai(pip install -U sssekai)。

然后以 Suite 为例,执行命令 sssekai apidecrypt mysuite.bin suite.json 即可解密并得到明文数据。

逆向工程请见 Project SEKAI 逆向 - 笔记归档 | mos9527。

后记

参考文档 1:MuMu模拟器如何将系统磁盘更改为可读写? | MuMu模拟器

参考文档 2:如何安装证书&抓包? | MuMu模拟器

参考文档 3:世界计划抓包教程 | ルナ茶

参考文档 4:Project SEKAI 逆向 - 笔记归档 | mos9527

作者:等待雨晴,始作于 2025-7-23,最后更新于 2025-10-4