Arthals' ink

Back

MajsoulMax#

雀魂 Max 可用于本地解锁全角色、皮肤、装扮等。

原始 Python 仓库:

Avenshy / MajsoulMax

Waiting for api.github.com...

???
???
???
?????

基于 Rust 重构的仓库:

Xerxes-2 / MajsoulMax-rs

Waiting for api.github.com...

???
???
???
?????

在前者基础上,外加 TinyProxy 做鉴权并封装为了 Docker 镜像:

zhuozhiyongde / MajsoulMax-rs-docker

Waiting for api.github.com...

???
???
???
?????

解锁原理#

首先我们要明白,MITM(Man-in-the-Middle) 中间人攻击的本质是在雀魂游戏进程和服务器之间插入一个代理。当游戏客户端发送请求到服务器,或服务器返回响应给客户端时,这些网络流量都会经过我们启动的代理程序。

也即,原来是:

game -> server
plaintext

现在变成了:

game -> proxy -> server
plaintext

代理程序会识别出特定的游戏数据包(Protobuf 格式),并根据预设的规则在本地对其进行实时修改,将“未拥有”的角色或装扮数据修改为“已拥有”。修改后的数据包再被发送到游戏客户端,从而在视觉上欺骗客户端,让我们看到已经解锁了全角色和装扮。这个过程只发生在你的电脑或手机上,服务器端的数据完全没有改变。

由于他只是一个代理,所以部署在本地或者服务器 VPS 上都可以,而如果部署在 VPS 上,便可以实现全平台使用,且数据共享。

各个版本的差异:

  • Python:基于 mitmproxy 实现,兼容性最好,但需要手动安装管理依赖,可以比较方便的实现上下游代理链,兼容本地 AI 使用。
  • Rust / Docker:基于 hudsucker 实现,兼容性较差,优点是已经完全编译为二进制文件,快速启动无需安装依赖。

注意,Rust / Docker 所基于的 omjadas/hudsucker 项目有一个很令人困惑的地方,即其虽然身为会进行 MITM 的节点,但是对外提供的是 HTTP 的代理节点而非 HTTPS 的代理节点。这导致你必须在填写代理软件的时候,填写 HTTP 代理,并且同时信任其自签名的证书,而且在对流量进行代理链式配置的时候(如搭配本地 AI 软件),也会存在一些问题。

这点具体表现在:

  1. 游戏初始化的时候不能过双层代理链(解锁 + AI),只能插入一层代理

  2. 通过 Surge 测速的时候,日志会显示

    WARN hudsucker::proxy::internal: Unknown protocol, read '[48, 45, 41, 44]' from upgraded connection
    bash

    不过这并不影响使用。

我尝试了一些办法,但始终无法解决这个问题,只能做简易 Patch,详情见后。

启动代理#

请首先阅读各项目的 README 文档,了解启动方法。

Python#

git clone https://github.com/Avenshy/MajsoulMax.git
cd MajsoulMax
pip install -r requirements.txt
mitmdump -p 23410 -s addons.py
bash

Rust#

无需下载源码,直接在 Releases 根据你的平台下载二进制文件,解压出来后运行 majsoul_max_rs 即可。

Docker#

目前只支持 Linux 平台。

  1. 拉取并启动服务

    创建并进入目录:

    mkdir majsoul && cd majsoul
    bash

    然后创建 docker-compose.yml

    services:
        majsoul-proxy:
            image: arthals/majsoul-max-rs:latest
            restart: unless-stopped
            ports:
                # 将容器的 23411 端口映射到宿主机的 8888 端口
                - '8888:23411'
            volumes:
                - ./app:/app
            environment:
                - username=username
                - password=password
                # Github 代理下载
                - download_url=https://ghproxy.net/https://github.com/Xerxes-2/MajsoulMax-rs/releases/download/0.6.7/majsoul_max_rs-0.6.7-x86_64-unknown-linux-gnu.tar.gz
                # 原始下载
                # - download_url=https://github.com/Xerxes-2/MajsoulMax-rs/releases/download/0.6.7/majsoul_max_rs-0.6.7-x86_64-unknown-linux-gnu.tar.gz
                # 可选:代理下载
                # - http_proxy=${HTTP_PROXY:-http://172.17.0.1:7890}
                # - https_proxy=${HTTPS_PROXY:-http://172.17.0.1:7890}
    yaml

    启动容器:

    docker compose up -d
    bash

    默认会:

    • 映射宿主机 8888 端口到容器 23411 端口。
    • 使用账号 username/password 进行 Basic Auth 认证。
    • 通过 download_url 环境变量自动下载 GNU 版本的可执行文件。

    如需修改端口或账号密码,请直接编辑 docker-compose.yml 对应字段即可。

  2. 验证运行

    curl -k -x http://username:password@127.0.0.1:8888 https://baidu.com --head
    bash

    返回 HTTP/1.1 200 OK 即代表代理工作正常。

    然后你需要放行你服务器的 8888(或同自定义)端口,使之可以在外网访问。

信任证书#

  • 对于原始 Python 仓库,需要信任 ~/.mitmproxy/ 下的 mitmproxy-ca-cert.pem 证书。这个证书是本地自动生成的,非常安全。
  • 对于 Rust 版本或者 Docker 封装版本,需要信任 hudsucker.cer 证书。这个证书是在源码中写死的,如果你担心安全性,想要更换证书,你需要下载源码替换后重新编译。

以下以 hudsucker.cer 证书为例,讲解步骤:

macOS#

  1. 将证书拖入到 钥匙串访问-系统-证书

    macOS1

  2. 右键-显示简介-信任,调整为始终信任,然后关闭,输入密码确认。

    macOS2

iOS / iPadOS#

  1. 将下载好的 hudsucker.cer 隔空投送到 iPhone/iPad 上,进入 设置-已下载描述文件,点击安装

  2. 前往 通用-关于本机-证书信任设置,打开 Hudsucker Industries 的选项

    iOS

Windows / Android#

点击下载下来的 hudsucker.cer 证书文件,跟随指引安装证书即可。

代理配置#

原始项目需要使用 Proxifier 来进行流量代理,然而我们有更好的选择,那就是直接利用 Surge / Clash 来进行规则分流代理。

注意,如果是本地客户端,请开启 TUN / 增强模式以确保正确代理进程流量。

以下配置在 macOS Steam 客户端和 iOS / iPadOS 港服客户端测试通过,注意替换相关字段(IP、端口、协议、账号密码)为你的实际值。

Python#

提供的是本地 HTTPS 节点,无需账号密码。

Clash 配置示例:

proxies:
    - name: Majsoul
      port: 23410
      server: 127.0.0.1
      tls: true
      type: http
proxy-groups:
    - name: 🀄 雀魂麻将
      proxies:
          - Majsoul
          - DIRECT
      type: select
rules:
    - PROCESS-NAME,雀魂麻將,🀄 雀魂麻将
    - PROCESS-NAME,jantama_mahjongsoul.exe,🀄 雀魂麻将
    - PROCESS-NAME,Jantama_MahjongSoul.exe,🀄 雀魂麻将
yml

Surge 配置示例:

[Proxy]
Majsoul = https, 127.0.0.1, 23410

[Proxy Group]
🀄 雀魂麻将 = select, Majsoul, DIRECT

[Rule]
PROCESS-NAME,雀魂麻將,🀄 雀魂麻将
text

Rust#

提供的是本地 HTTP 节点,无需账号密码。

Clash 配置示例:

proxies:
    - name: Majsoul
      port: 23410
      server: 127.0.0.1
      tls: false
      type: http
proxy-groups:
    - name: 🀄 雀魂麻将
      proxies:
          - Majsoul
          - DIRECT
      type: select
rules:
    - PROCESS-NAME,雀魂麻將,🀄 雀魂麻将
    - PROCESS-NAME,jantama_mahjongsoul.exe,🀄 雀魂麻将
    - PROCESS-NAME,Jantama_MahjongSoul.exe,🀄 雀魂麻将
yml

Surge 配置示例:

[Proxy]
Majsoul = http, 127.0.0.1, 23410

[Proxy Group]
🀄 雀魂麻将 = select, Majsoul, DIRECT

[Rule]
PROCESS-NAME,雀魂麻將,🀄 雀魂麻将
text

Docker#

提供的是远程 HTTP 节点,需要账号密码、IP 端口等配置,此时服务器作为中间代理,而客户端设备只需要信任证书后配置节点和分流规则即可。

Docker 的配置和 Rust 非常类似,只是多了一个鉴权部分。

Clash:

proxies:
    - name: Majsoul
      port: your_service_port
      server: your_server_ip
      tls: false
      type: http
      username: username
      password: password
yaml

Surge:

[Proxy]
Majsoul = http, your_server_ip, 8888, username, password
text

如果你是桌面端,请参考之前的 Rust 版本配置,只需替换 proxies 字段即可,无需对规则做操作;

如果你是移动端设备,即 iOS(无法使用 PROCESS-NAME 规则,会被忽略)或者是安卓但不确定 PROCESS-NAME 是否正确,那你需要将规则改为域名关键字或者 IP 分流,如下:

Clash:

rules:
    - DOMAIN-KEYWORD,majsoul,🀄 雀魂麻将
    - DOMAIN-KEYWORD,maj-soul,🀄 雀魂麻将
    - DOMAIN-KEYWORD,catmjstudio,🀄 雀魂麻将
    - DOMAIN-KEYWORD,catmajsoul,🀄 雀魂麻将
    - IP-CIDR,146.66.155.0/24,🀄 雀魂麻将
    - IP-CIDR,185.25.182.18/32,🀄 雀魂麻将
    - IP-CIDR,203.107.63.200/32,🀄 雀魂麻将
yml

Surge:

[Rule]
DOMAIN-KEYWORD,majsoul,🀄 雀魂麻将
DOMAIN-KEYWORD,maj-soul,🀄 雀魂麻将
DOMAIN-KEYWORD,catmjstudio,🀄 雀魂麻将
DOMAIN-KEYWORD,catmajsoul,🀄 雀魂麻将
IP-CIDR,146.66.155.0/24,🀄 雀魂麻将
IP-CIDR,185.25.182.18/32,🀄 雀魂麻将
IP-CIDR,203.107.63.200/32,🀄 雀魂麻将
text

Akagi#

Akagi 可以提供 AI 雀魂分析,帮你分析下一步应当打什么牌,并且具有一个十分现代化的 TUI(Terminal UI),对于 Windows 客户端,还可以下载编译好的版本完成自动代打,不过我没尝试过。

shinkuan / Akagi

Waiting for api.github.com...

???
???
???
?????

akagi

AI 原理#

和解锁类似,AI 的工作流程也是通过 MITM 来截获对局信息,从而还原出牌局状况,然后送入 AI 来进行分析。所以你需要类似的完成信任证书、配置软件分流的操作。

Akagi 使用的证书和 MajsoulMax 的 Python 版本一致,位于 ~/.mitmproxy

对于 Windows 用户,可以直接下载编译好的 exe 可执行文件;对于 macOS 用户,则必须手动执行 py 脚本。

启动 AI#

git clone https://github.com/shinkuan/Akagi.git
cd Akagi
pip install -r requirements.txt
# 然后按照原仓库的 README 走
# 先按照 For Developer 走,配置好 libriichi 的依赖
# 然后同前文(macOS)或者 README(Windows) 一样,安装证书。
python run_akagi.py
bash

原始仓库提供了一个基础的 Mortal 版本,不过你可以在 这个 issue 下载到更新的权重。

MajsoulCopilot#

类似 Akagi 的项目,也是可以本地提供 AI 辅助,不同的是其同时支持 Windows / macOS 的自动打牌功能,而 Akagi 虽然也支持,但只支持 Windows 平台。

latorc / MahjongCopilot

Waiting for api.github.com...

???
???
???
?????

我的 Fork 版本(修了一些 macOS 上的证书信任检测问题,支持兼容雀魂 Max 解锁,但 PR 尚未合并,推荐使用):

zhuozhiyongde / MahjongCopilot

Waiting for api.github.com...

???
???
???
?????

自动打牌原理#

自动打牌基本就是通过在浏览器里定位控件元素,并模拟鼠标操作,来完成自动打牌、自动开启对局等功能。

然而,其不仅存在一些限制(浏览器分辨率、尺寸等),而且浏览器的渲染界面(至少在 macOS 上)精度不如客户端,体验也有所残缺,且自动打牌很容易被封号,所以不建议使用。

启动 Copilot#

参见原文 README 即可。

与 Akagi 不同的是,对于 MahjongCopilot,只需要将模型文件拖入即可,无需再额外修改代码。

值得注意的一点是,MahjongCopilot 与前文的项目有所不同的一点是,其做了一层隔离,所需要信任的证书位于 ./mitm_config 下而非默认的 ~/.mitmproxy,这一点在联合使用的时候可能需要注意,但代码应当会自动完成信任过程。

联合使用#

Akagi + MajsoulMax#

由于二者都需要进行 MITM,所以你需要配置代理链让流量串行经过两个节点,并且需要同时信任二者的证书。

这里有基于 MajsoulMax-rs 和基于 MajsoulMax 的两种配置,配置相近,不同点在于:

  1. MajsoulMax-rs(Rust)启动的是 HTTP 代理(基于 hudsucker),且链式代理时,初始化的时候会遇到问题
  2. MajsoulMax(Python)启动的是 HTTPS 代理(基于 mitmproxy),可以完美进行链式代理。

虽然听起来后者更好,但还是建议按照前者走,原因无他,方便快捷(无需切换 Python 环境等)。

Rust 版本代理链条如下:

game -> majsoul_max_rs(23410, http) -> akagi(7880, https) -> server
plaintext

Python 版本代理链条如下:

game -> MajsoulMax(23410, https) -> akagi(7880, https) -> server
plaintext

建议的配置如下:

Clash:

proxies:
    - name: Majsoul
      port: your_service_port
      server: your_server_ip
      tls: false
      type: http
      username: username
      password: password
    - name: MajsoulLocal
      port: 23410
      server: 127.0.0.1
      tls: false
      type: http
    - name: Akagi
      port: 7880
      server: 127.0.0.1
      tls: true
      type: http
proxy-groups:
    - name: 🀄 雀魂麻将
      proxies:
          - Majsoul
          - MajsoulLocal
          - DIRECT
          - 🔰 节点选择
      type: select
rules:
    - PROCESS-NAME,雀魂麻將,🀄 雀魂麻将
    - PROCESS-NAME,majsoul_max_rs,Akagi
yaml

Surge:

[Proxy]
Majsoul = http, your_server_ip, your_service_port, username, password
MajsoulLocal = http, 127.0.0.1, 23410
Akagi = http, 127.0.0.1, 7880

[Proxy Group]
🀄 雀魂麻将 = select, Majsoul, MajsoulLocal, DIRECT, 🔰 节点选择

[Rule]
PROCESS-NAME,雀魂麻將,🀄 雀魂麻将
PROCESS-NAME,majsoul_max_rs,Akagi
text

这么配置的好处在于,你可以在不想用 AI 的时候分流到服务器上的 Majsoul 节点进行简单的解锁,而在需要 AI 的时候,先通过服务器节点或者直连进行初始化,然后再换到本地的 MajsoulLocal 节点即可。

如果你实在嫌麻烦,你还可以让 LLM 给你写一个基于 Clash / Surge HTTP API 的自动化脚本,来完成这个过程。

MahjongCopilot + MajsoulMax#

参见 我的 Fork 的 README 即可。

settings.json 中设置 "majsoulmax_proxy": "http://127.0.0.1:23410"

随后,请以如下方式启动 MajsoulMax:

mitmdump -p 23410 --mode upstream:http://127.0.0.1:10999 -s addons.py --ssl-insecure
bash

请注意,如果你修改了 MajsoulMax 或者 MahjongCopilot 的代理端口,请相应修改对应端口,并且确保 MajsoulMax 和 MahjongCopilot 的自签名证书均正确安装(这两者是不同的,前者默认使用 ~/.mitmproxy/ 下的证书,而后者使用 ./mitm_config/ 下的证书)。

最终代理链为:

game -> MajsoulMax(23410, https) -> MahjongCopilot(10999, https) -> server
plaintext

分流类似前文,在此不再赘述。

雀魂 MajsoulMax / Akagi / MajsoulCopilot 使用教程
https://arthals.ink/blog/majsoul
Author Arthals
Published at July 17, 2025
Comment seems to stuck. Try to refresh?✨