원클릭으로
mobai-reverse
MobAI Pro 会员系统逆向工程全流程。适用于 Go 64-bit PE 分析、license/quota 系统 patch、NSIS→7z SFX 重打包、以及 Go 二进制 embed.FS 前端提取。需要 IDA Pro MCP 连接。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
MobAI Pro 会员系统逆向工程全流程。适用于 Go 64-bit PE 分析、license/quota 系统 patch、NSIS→7z SFX 重打包、以及 Go 二进制 embed.FS 前端提取。需要 IDA Pro MCP 连接。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Create and iteratively refine parametric 3D CAD models through progressive refinement with inspectable feedback. Use when the task involves OpenSCAD, build123d, STL/STEP/3MF output, fixture/enclosure/adapter design, or debugging shape accuracy from renders or screenshots. Covers both generation and editing as a unified workflow.
Claudeception is a continuous learning system that extracts reusable knowledge from work sessions. Triggers: (1) /claudeception command to review session learnings, (2) "save this as a skill" or "extract a skill from this", (3) "what did we learn?", (4) After any task involving non-obvious debugging, workarounds, or trial-and-error discovery. Creates new Claude Code skills when valuable, reusable knowledge is identified.
AI-assisted distributed systems verification with TLA+ formal specification. Use when verifying distributed system correctness, discovering race conditions, writing TLA+ specifications from codebases, performing model checking on consensus/replication protocols, or setting up Lamport Agent workflows. Triggers on: "verify distributed system", "formal verification", "TLA+ spec", "model checking", "find race condition", "prove correctness", "CRAQ", "Paxos verification", "Raft verification", "chain replication verification", "distributed consensus verification".
Expert tutor and reference for 具身智能 / embodied intelligence and robot learning, grounded in 《具身智能导论》— the 17-chapter Chinese textbook translated from UC Berkeley CS294-291 "Robots That Learn". Use this skill whenever the user asks about embodied AI / robot learning topics the book covers: 中枢模式发生器(CPG)、 生物运动力学与步态、李群 SO(3)/SE(3) 机器人运动学与动力学、扩散模型/扩散策略 (DDPM, score matching, flow matching, diffusion policy)、灵巧手与欠驱动协同、 触觉感知(GelSight)、运动控制(LQR/MPC/阻抗控制)、卡尔曼滤波与预测控制、视频世界模型、 强化学习(MDP/SAC/PPO/actor-critic)、行为克隆与动作分块、视觉模仿学习(UMI/跨具身)、 足式运动(RMA)、导航(GOAT/可穿越性)、Sim-to-Real 灵巧操作、VLA 与 π0.5 长程规划。 Trigger it for conceptual questions, math derivations, paper explanations, PyTorch implementation help, study/teaching, or "解释一下/推导/这门课/具身智能" requests in this domain — even when the user doesn't name the book. Prefer this skill over answering from memory, because it gives grounded, citable, notation- consistent answers and links to the exact chapter.
Automates publishing novel chapters to 番茄小说 (fanqienovel.com) via Playwright browser automation. Use when the user wants to publish, batch-upload, or retry uploading novel chapters from a local directory to 番茄小说. Handles login state, ProseMirror editor injection, popup dismissal (错别字检测/仅基础检测/AI声明/确认发布), and auto-archives successfully published files. Triggers on requests like "发布章节到番茄", "上传小说", "batch publish chapters", or retrying failed chapters.
Use when reviewing HarmonyOS (ArkTS/ArkUI) code, when file extensions are .ets/.ts in HarmonyOS context, or when checking ArkUI component implementations, async/await patterns, or @State/@Prop/@Provide usage
| name | mobai-reverse |
| description | MobAI Pro 会员系统逆向工程全流程。适用于 Go 64-bit PE 分析、license/quota 系统 patch、NSIS→7z SFX 重打包、以及 Go 二进制 embed.FS 前端提取。需要 IDA Pro MCP 连接。 |
目标:MobAI Pro (Android 设备自动化工具) — 绕过 Pro 会员验证,解锁无限设备、无限 token、离线模式。
二进制: MobAI_payload.exe (145 MB, Go 1.22+ 64-bit, NSIS v3.11 Unicode 安装器内嵌)
补丁数: 7 (v2.0) | 方法: 根源数据覆写 + 服务器同步阻断
# 检查 EXE 签名
file MobAI.exe
# "Nullsoft Installer self-extracting archive (NSIS)"
# 提取 NSIS 载荷
7z x MobAI.exe -onsis-extract
# 产出:
# MobAI_payload.exe ← 真正的 Go 二进制 (145 MB)
# $PLUGINSDIR/System.dll, nsDialogs.dll
# $PLUGINSDIR/webview2bootstrapper/MicrosoftEdgeWebview2Setup.exe
file MobAI_payload.exe
# "PE32+ executable (console) x86-64 Go BuildID=..."
# 用 IDA 加载 → 17 个段,带 Go PCLNTAB 符号表
# .symtab 段: 函数名、包路径完整保留 (15 MB 符号表)
Go 的 embed.FS 数据存储在 .rdata/.data 段中。使用 IDA MCP 搜索特征路径:
# IDA Python: 搜索 "frontend/dist/"
results = ida_search.find_text("frontend/dist/", ...)
# 定位到 embedded.resources.Init() 中 embed.FS 引用
# 前端文件路径模式: frontend/dist/assets/index.xxxxxxxx.js
# 从 .rdata/.data 段提取: index.html, index.js (499KB), index.css (63KB)
提取的文件:
| 文件 | 大小 | 技术栈 |
|---|---|---|
index.html | 371 B | WebView2 入口 |
index.js | 499,662 B | React 18 + TypeScript + Webpack 5 + Zustand |
index.css | 63,833 B | Tailwind CSS + Nunito font |
scripts.js | 100,000 B | 辅助逻辑 |
auth-success.html | 485 B | Supabase OAuth 回调 |
Go 编译器在 .symtab 段生成完整符号表。IDA 自动解析为函数名 package.(*Type).Method。
关键命名空间:
mobai_internal_license.(*Manager).* ← 许可证核心
mobai_internal_quota.(*Manager).* ← 配额/限额
mobai_internal_supabase.(*Client).* ← 后端认证
mobai_internal_device/android/* ← ADB 集成
mobai_internal_embedded.* ← 内嵌资源
main.(*App).* ← 应用入口 + Go↔JS 桥接
# IDA MCP: 列出 license 包函数
ida_func_query(filter="mobai_internal_license.*")
核心函数表:
| 函数 | 地址 (VA) | 说明 |
|---|---|---|
NewManager | 0x140F311C0 | 初始化 license Manager |
GetTier | 0x140F31500 | 读取 tier 字符串 |
IsPro | 0x140F31620 | 判断是否 Pro |
HasUnlimitedTokens | 0x140F31680 | 无限 token? |
HasUnlimitedDevices | 0x140F316C0 | 无限设备? |
HasOfflineMode | 0x140F31720 | 离线模式? |
CanMakeRequest | 0x140F31780 | 允许发请求? |
CanConnectDevice | 0x140F31A00 | 允许连设备? |
GetStatus | 0x140F35020 | 向前端报告状态 |
SyncLicense | 0x140F32000 | 从服务器同步 |
RefreshTier | 0x140F33080 | 刷新 tier |
StartTierSync | 0x140F33EC0 | 启动定时同步 |
从 NewManager 和 GetTier/GetLimit 反推出内存布局:
// license.Manager (大小 0x60+)
// VA 参考: NewManager = 0x140F311C0
struct LicenseManager {
void* supabaseClient; // +0x00: Supabase 客户端
void* quotaManager; // +0x08: quota.Manager 指针
string tier; // +0x10: tier 字符串 (ptr)
int64 tierLen; // +0x18: tier 长度
void* rwMutex; // +0x20: 读写锁
// +0x28: EventEmitter
// +0x38: context/其他
};
// quota.Manager (大小 0x88+)
// VA 参考: NewManager = 0x140F2DEE0
struct QuotaManager {
void* supabaseClient; // +0x00
void* eventEmitter; // +0x08
void* storage; // +0x10
// ...
string tier; // +0x38: tier 字符串 (ptr)
int64 tierCode; // +0x40: tier 代码 (4)
int64 tokensRemaining; // +0x48: 剩余 token 数 (初始 100)
int64 limit; // +0x50: 每日限额 (100 = free, -1 = pro)
// +0x58: 离线票
void* offlineTicket; // +0x68: 离线 ticket
};
App 启动
└─ license.NewManager()
├─ tier = "free", len = 4 [地址: 0x140F3137D, 0x140F3138C]
└─ quota.NewManager()
├─ tier = "free", code = 4 [地址: 0x140F2DFEC, 0x140F2DFFB]
├─ tokensRemaining = 100 [地址: 0x140F2DFFF]
└─ limit = 100 [地址: 0x140F2E007] ← ROOT CAUSE
用户登录 → handleInitResult()
├─ 成功路径: 不调用 setTier (tier 保持 "free")
├─ 失败路径: setTier("free", 4) [地址: 0x140F328A0, 0x140F329C0]
└─ setTier() → quota.SetTier()
└─ 只更新 +0x38, +0x40, 不更新 +0x50! ← 设计缺陷
服务器同步 → StartTierSync() 定时调用 RefreshTier()
└─ RefreshTier() → SyncLicense() → 从 Supabase 获取真实 tier
└─ 如果是 free 用户 → setTier("free", 4) → 覆盖!
// IsPro @ 0x140F31620 — 反编译
bool IsPro(Manager* m) {
Tier t = GetTier(m); // 从 +0x10 读 tier 字符串
return t.len == 3
&& *(uint16*)t.ptr == 0x7270 // "pr" (LE)
&& *(uint8*)(t.ptr+2) == 0x6F; // "o"
}
// HasUnlimitedTokens @ 0x140F31680 — 反编译
bool HasUnlimitedTokens(Manager* m) {
return GetLimit(m->quotaManager) < 0; // limit == -1 → true
}
// CanMakeRequest @ 0x140F31780 — 反编译
bool CanMakeRequest(Manager* m) {
if (GetLimit(m->quotaManager) >= 0) // limit >= 0 → 受限
return CanUseToken(...); // 检查并消耗 token
return true; // limit < 0 → 无限制
}
// CanUseToken @ 0x140F2E3E0 — 反编译 (直接读字段!)
bool CanUseToken(QuotaManager* q) {
if (q->limit >= 0) // +0x50 字段
return q->tokensRemaining > 0; // +0x48 字段, 每次 -1
return true; // limit < 0 → 无限
}
策略: 逐个修补布尔检查函数 (IsPro, HasUnlimitedTokens, HasOfflineMode...)
失败根因:
CanUseToken 读 +0x50 字段 (100),不调用 GetLimit()策略: 直接修改数据源 + 阻止服务器覆盖
| # | 补丁 | 虚拟地址 | 原始字节 | 补丁字节 | 作用 |
|---|---|---|---|---|---|
| 1 | GetLimit 返回路径 1 | 0x140F2FC85 | 48 8B 44 24 10 | 6A FF 58 90 90 | push -1; pop rax (5B) |
| 2 | GetLimit 返回路径 2 | 0x140F2FC95 | 48 8B 44 24 10 | 6A FF 58 90 90 | panic 恢复路径 |
| 3 | license.NewManager len | 0x140F3137D | 48 C7 40 18 04... | 48 C7 40 18 03... | tier 长度 4→3 |
| 4 | "free" 字符串覆写 | 0x1418D15B8 | 66 72 65 65 | 70 72 6F 00 | "free"→"pro\0" |
| 5 | quota.NewManager limit | 0x140F2E007 | 48 C7 40 50 64... | 48 C7 40 50 FF... | limit 100→-1 |
| 6 | RefreshTier 禁用 | 0x140F33080 | 49 3B 66 10... | 31 C0 31 DB C3... | 立即返回 |
| 7 | StartTierSync 禁用 | 0x140F33EC0 | 4C 8D 64 24 F8... | C3 90 90 90... | 立即返回 |
原始指令 5 字节 mov rax, [rsp+0x10]。需要替换为 rax = -1。
mov rax, -1 = 48 C7 C0 FF FF FF FF (7B) → 超长!
解决方案: push -1; pop rax = 6A FF 58 (3B) + NOP × 2 = 5B ✓
6A FF push -1 ; -1 压栈 (sign-extended imm8)
58 pop rax ; rax = 0xFFFFFFFFFFFFFFFF
90 90 nop; nop ; 填充
31 C0 xor eax, eax ; rax = 0 (nil error → "成功"但无操作)
31 DB xor ebx, ebx ; rbx = 0 (nil 返回值)
C3 ret ; 立即返回 — 不调用服务器!
90×4 nop ; 填充
关键: Go 函数返回 (result, error) 在 rax, rbx 中。xor eax,eax; xor ebx,ebx; ret 等价于 return nil, nil ——调用方认为刷新成功但无数据返回,不会覆盖本地 tier。
NSIS 安装器无法直接修改后重新打包(需要 NSIS 编译器),使用 7z SFX 替代:
# 1. 用打补丁的 MobAI_payload.exe 替换原始文件
cp MobAI_payload.exe nsis-extract/MobAI.exe
# 2. 创建 7z 归档
7z a -t7z mobai-patched.7z ./pkg/* -mx=5
# 3. 拼接 SFX 安装器
cat 7z.sfx config.txt mobai-patched.7z > MobAI-Pro-Patched-v2.exe
;!@Install@!UTF-8!
Title="MobAI Installer (Pro Patched)"
BeginPrompt="This will install MobAI with Pro membership unlocked..."
Progress="yes"
RunProgram="MobAI.exe"
AutoInstall="yes"
Directory="MobAI"
;!@InstallEnd@!
补丁脚本需要正确处理 VA→文件偏移。PE 布局 (17 个段):
.text: RVA 0x1000 → file 0x600 (120 MB)
.rdata: RVA 0x1271000 → file 0x1270600 (100 MB)
.data: RVA 0x76A7000 → file 0x76A6000 (8 MB)
动态解析 远比硬编码偏移可靠——patcher.py v2.0 实现了完整的 PE 解析器。
WebView2 通过 window.chrome.webview.hostObjects.mobai 暴露 Go 方法:
// JS → Go (同步/异步调用)
await mobai.getLicense(); // → main.(*App).GetLicenseStatus → license.GetStatus
await mobai.connectDevice(sn); // → main.(*App).ConnectDevice
await mobai.runTask(taskJSON); // → 自动化执行
await mobai.upgradePro(); // → CreateCheckout
// Go → JS (事件推送)
window.chrome.webview.addEventListener('message', (e) => {
const { type, payload } = JSON.parse(e.data);
// license:updated, bridge:started, agent:progress
});
main.GetLicenseStatus (+0x1411C60E0)
└─ license.GetStatus (+0x140F35020)
├─ GetTier() → {ptr, len} → result._r0, result._r1
├─ IsAuthenticated() → result._r2
├─ GetUserEmail() → {ptr, len} → result._r3, result._r4
├─ if GetLimit() >= 0: tokens → result._r5, result._r6
└─ GetOfflineTicketExpiry() → result._r7
前端直接使用 tier 字符串显示 "Free"/"Pro" 标签。因此必须修改字符串本身而非仅 IsPro 返回值。
| 工具 | 用途 |
|---|---|
| IDA Pro 8.x + MCP 插件 | 反编译、反汇编、数据流追踪 |
| 7-Zip 23+ | NSIS 解包、7z SFX 打包 |
| Ghidra (备选) | Go PCLNTAB 符号恢复 |
| Python 3.11 | 补丁脚本、PE 解析 |
| Git + Git LFS | 二进制文件版本管理 |
CanUseToken 直接读 +0x50 而非调用 GetLimit()"pro" (3B) vs "free" (4B),需要同时修改长度字段RefreshTier/StartTierSync 必须禁用,否则服务器会覆盖本地修改push imm8; pop reg = 3B) 在空间受限时非常有用