本文概览
本文系统记录近期针对微信小程序安全的研究与自动化审计思路,涵盖缓存定位、解包反编译、架构分析、本地工具研发(WxLocated)以及基于多 Agent 的自动化代码审计实践。
一、小程序解包与反编译
1.1 微信小程序缓存位置
微信在不同操作系统上的小程序缓存目录如下:
Windows
C:\Users\{用户名}\Documents\WeChat Files\Applet\
C:\Users\{用户名}\Documents\WeChat Files\{微信ID}\Applet\
文件结构:
Applet/
├── {appid}/
│ ├── __APP__.wxapkg # 主包
│ ├── __SUBPKG__*.wxapkg # 分包
│ └── ...
Linux
目前暂未覆盖。
macOS
macOS 客户端版本演进较快,新版已普遍采用 users/<账号哈希>/applet/packages 这种多账号隔离目录结构:
# 典型历史路径
~/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/Applet/
# 常见缓存路径
~/Library/Containers/com.tencent.xinWeChat/Data/Documents/Applet/
~/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/WeChat/Applet/
最新版微信的小程序缓存树形拓扑结构如下:
__APP__.wxapkgApp 启动逻辑、主页面、tabBar、分包清单
xxxx.wxapkg进入对应页面时下载
yyyy.wxapkg可不加载主包直接启动
zzzz.wxapkg插件或其他资源
同一个 AppID 下可以有多个版本;实际包名和目录内容以采集结果为准。
为了方便在 macOS 上快速查找与解析这些 wxapkg,我开发了原生 macOS 工具 WxLocated(具体功能将在后文详细介绍)。

1.2 解包与反编译方案
针对微信 4.0 版本的解包反编译,社区已有成熟方案,例如基于 Go 开发的开源工具:
使用效果如下(但 macOS 下直接查看往往难以区分具体 AppID 归属,配合 WxLocated 定位更高效):

二、wxapkg 分析思路与小程序架构
对 wxapkg 进行逆向分析本质上类似于前端安全分析,但额外多了一层**“微信运行时与客户端容器”**。通常先通过静态分析定位风险点,再结合动态测试展开深挖。
微信小程序逆向分析核心要素:
WXML + WXSS + JavaScript + 微信客户端运行时
核心思路与常规 Web 渗透一致:通过源码挖掘硬编码凭据、API 端点、鉴权缺陷,进而伪造凭证或实施后利用。
2.1 Web 前端与微信小程序技术对照
| Web 前端 | 微信小程序 | 说明 |
|---|---|---|
| HTML | WXML | 标签化结构定义语言 |
| CSS | WXSS | 样式语言,支持 rpx 尺寸转换 |
| JavaScript | JavaScript | 双线程架构,运行于 JsCore 中 |
| 浏览器 DevTools | 微信开发者工具 / 客户端调试 | 官方调试套件 |
| localStorage | wx.setStorage / wx.getStorage | 本地键值持久化 |
| fetch / axios | wx.request | 网络数据请求 |
| WebSocket | wx.connectSocket | 长连接通信 |
| 页面路由 | navigateTo / redirectTo | 页面堆栈管理 |
| iframe | <web-view> | 嵌入外部网页组件 |
| npm 打包产物 | app-service.js | 编译打包后的逻辑层产物 |
| Source Map | 小程序 Source Map | 源码映射映射文件 |
| Webpack Chunk | 主包 / 分包 | 模块化代码切分机制 |
2.2 打包与运行机制
开发者在开发环境编写工程代码:
app.js
app.json
app.wxss
pages/
index/
index.js
index.json
index.wxml
index.wxss
上传至微信开放平台后,代码被编译、压缩、打包生成二进制包:
__APP__.wxapkg
客户端在下载该包后,依次执行以下启动阶段:
- 解析文件:读取
.wxapkg文件头与索引结构; - 释放资源:提取包内虚拟文件并建立映射;
- 加载配置:解析
app.json全局与页面配置; - 初始化逻辑:在 JsCore 线程启动 JavaScript 逻辑层;
- 渲染页面:在 WebView 线程渲染 WXML 与 WXSS 界面。
2.3 wxapkg 文件物理结构
.wxapkg 是微信自定义的打包文件系统,无法直接使用 unzip 等通用解压工具打开。其结构由固定头部、文件索引表与正文数据区组成:
HEADERINDEXDATA BODYTRAILER读取索引中的路径、offset 与 size,再从数据区截取对应文件。
解包工具的核心逻辑是首先解析文件索引表,获取各个子文件的虚拟路径、起始偏移(offset)与字节长度(size),然后再从数据区精确截取对应文件内容。

.wxapkg 映射模型
├── 文件名 1 → offset / size
├── 文件名 2 → offset / size
├── 文件名 3 → offset / size
└── Body Data ...
2.4 wxapkg 常见解包内容
解包之后通常包含以下四大类文件:
全局文件
app-config.json # 全局编译后配置
app-service.js # 核心逻辑层整合代码
app-wxss.js # 全局样式转换脚本
common.app.js # 提取出的公共模块
(注:不同微信版本、基础库版本及打包策略下文件名可能存在差异)
页面资源
在开发环境中各页面独立分布:
pages/index/index.js
pages/index/index.json
pages/index/index.wxml
pages/index/index.wxss
但在编译打包后,多个页面的 JavaScript 往往统一合并至 app-service.js,样式则合并至 app-wxss.js。
静态资源
images/logo.png
assets/icon.svg
static/banner.jpg
配置信息
app.json
app-config.json
project.config.json # 开发者工具本地配置(通常不打包进线上产物)
2.5 主包与分包机制
中大型小程序通常采用分包加载策略,降低首次下载体积:
小程序版本包分类
├── 主包:启动时必须加载的核心代码
├── 普通分包:访问特定页面时按需下载加载
├── 独立分包:可绕过主包直接启动加载
└── 资源扩展包:插件包、游戏资源或运行时模块
多版本目录层级示意:
packages / wx1234567890abcdef /APP ID__APP__.wxapkg 主包xxxxx.wxapkg 分包 Ayyyyy.wxapkg 分包 B__APP__.wxapkg 主包xxxxx.wxapkg 分包 A采集时先按版本归档,避免将旧分包误配到新主包。
主包(__APP__.wxapkg)
承载小程序的全局基础能力:
- 默认启动首页与 tabBar 页面;
app.js/ 全局启动监听逻辑;app.json全局路由与配置;- 公共组件、通用工具模块与全局依赖资源。
配置示例:
{
"pages": [
"pages/index/index",
"pages/profile/profile"
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
}
]
}
}
普通分包
采用按需加载策略:
分包加载流程:
主包初始化完成
↓
页面跳转至 packageOrder/pages/list/list
↓
检查订单分包是否已缓存
↓
未缓存则从微信 CDN 异步拉取分包
↓
分包下载完毕并完成加载挂载
↓
渲染目标页面
分包配置示例:
{
"pages": [
"pages/index/index"
],
"subPackages": [
{
"root": "packageOrder",
"name": "order",
"pages": [
"pages/list/list",
"pages/detail/detail"
]
},
{
"root": "packageShop",
"name": "shop",
"pages": [
"pages/list/list",
"pages/detail/detail"
]
}
]
}
这也解释了为什么初次访问小程序时,本地通常仅抓取到 __APP__.wxapkg;必须完整浏览各个业务模块,微信才会将全量分包拉取至本地。
2.6 小程序生命周期与审计关注点
小程序运行在客户端托管容器中,其生命周期与原生应用高度类似:
生命周期层级:
App 维度
├── onLaunch(options) # 初始化(关注入参解析、身份验证与全局状态)
├── onShow() # 切换至前台
├── onHide() # 切入后台
└── onError(msg) # 异常捕获
Page 维度
├── onLoad(options) # 页面加载(重点:URL/页面传参来源、权限校验)
├── onShow() # 页面展示(重点:数据刷新与重复鉴权逻辑)
├── onReady() # 初次渲染完成
├── onHide() # 页面隐藏
└── onUnload() # 页面卸载
Component 维度
├── created / attached # 组件创建与节点挂载
├── ready # 视图布局完成
└── moved / detached # 节点移动与移除
在安全审计中,应重点审查 onLaunch(options)、onLoad(options) 和 onShow():大部分未授权访问、参数注入、越权参数绑定均存在于这些入口函数中。
2.7 开发者工具
微信官方开发者工具集成了模拟器、编译器和调试台(类似 Xcode / Android Studio):
- 官网下载地址:微信开发者工具下载页面

三、动态抓包与辅助工具
3.1 流量抓取方案
动态测试环节推荐采用 Proxifier + Yakit / Burp Suite 进行全量网络流量代理:
- 通过客户端规则强制将微信网络请求引流至本地代理;
- 拦截分析 HTTPS API 接口通信及敏感参数交互。
3.2 WxLocated:macOS 原生小程序分析工具
针对 macOS 生态缺乏好用的小程序逆向定位工具的问题,我使用 Swift + SwiftUI 开发了一款轻量级的小程序安全分析工具:
核心定位与能力清单
- 缓存目录探测:自动识别 macOS 上常见的 3.x、4.x 以及多账号架构缓存目录;
- 包指纹解析:原生解析标准 wxapkg 与 V1MMWX 微信本地加密缓存包,提取 AppID、名称、Logo、版本、主分包关系;
- 虚拟文件树重构:将主包与多级分包重构成完整统一的工程树;
- 源码反编译恢复:静态还原
app.json、页面配置文件、JavaScript 逻辑、WXS、WXML 标签树与 WXSS 样式; - Source Map 还原:自动提取内嵌 Source Map 并恢复原始未混淆源码;
- 代码语义美化:上下文感知美化 JS 语法,保持复合运算符、正则表达式和模板字符串语义;
- 攻击面提取:自动汇总提取全部请求接口、请求入参、外部域名、加解密密钥与敏感凭证;
- 安全无害化:所有解析完全在本机闭环进行,应用绝不执行包内代码,亦不发起任何外部网络通信。
软件界面展示
自动扫描 macOS 上的多代微信缓存目录(部分目录需授权访问):

查看小程序元数据与包结构信息:

批量导出反编译源码与资源文件:

macOS 原生 UI 开发设计记录:

源码构建方式
cd WxLocated
# 1. Debug 构建
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer \
xcodebuild build \
-project WxLocated.xcodeproj \
-scheme WxLocated \
-configuration Debug \
-destination 'platform=macOS' \
-derivedDataPath ./DerivedData \
CODE_SIGNING_ALLOWED=NO
# 运行 Debug 版本
open ./DerivedData/Build/Products/Debug/WxLocated.app
# 2. Release 构建
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer \
xcodebuild build \
-project WxLocated.xcodeproj \
-scheme WxLocated \
-configuration Release \
-destination 'platform=macOS' \
-derivedDataPath ./DerivedData \
CODE_SIGNING_ALLOWED=NO
四、Agent 自动化审计体系建设
针对小程序审计中业务逻辑繁多、变量混淆难读、权限模型复杂等痛点,我设计了一套面向多 Agent 的自动化代码审计套件:
4.1 编排架构
点击阶段,查看该阶段要回答的问题与应留下的材料。
对照主包、普通分包和独立分包,记录版本与来源;缺失材料先标记,不把未覆盖代码当作安全结论。
__APP__.wxapkg + package inventory每一步都可以停在“材料不足”;流程图不是自动确认漏洞的承诺。
material-check材料与完整性感知
attack-surface攻击面与接口清单
secret-scan硬编码凭证扫描
authz-analyzer越权与权限矩阵
payment-audit支付安全检查
dataflow-tracer污点与数据流追踪
privacy-compliance用户隐私合规
dynamic-tester动态验证与 PoC
code-restorerLLM 语义逆向还原
report-builder审计报告生成
模块各自留下中间材料,最终由报告阶段关联证据与结论。
4.2 核心设计理念
4.2.1 完整性感知
传统静态扫描工具往往“给什么扫什么”,容易因材料缺失导致误报或严重漏报。真正合格的智能审计 Agent 必须具备完整性认知:
完整性闭环流程:
输入 wxapkg / 微信缓存 / 反编译目录
↓
material-check 检查材料完备度
↓
智能决策:材料是否足以开展全量分析?
↓
构建攻击面总览与接口拓扑
↓
自动生成针对性测试假设与验证任务
↓
排除误报并关联上下文
↓
输出带证据链条的报告与复现脚本
在正式开启扫描前,Agent 必须首先核验以下先验条件:
- 是否存在主包?
- 全局配置声明了几个分包,实际收集到几个?
- 是否包含未加载的独立分包?
- 是否误混入旧版本分包?
- 插件包是否存在缺失?
- 反编译出来的代码语义是否完整?
4.2.2 渐进式逆向还原
通过开源逆向工具还原出的前端代码往往包含大量的变量名混淆(如 _0x1a2b)、语法压缩与死代码:

LLM 最突出的能力之一是上下文理解与语义推断。审计套件内置了渐进式逆向还原机制:
代码还原编排:
用户输入反编译目录(混淆/质量参差不齐)
↓
material-check 自动化评估代码可读性与质量
↓
┌───────┴───────┐
质量合格 存在明显缺陷
│ │
直接审计 交互询问 / 自动评估策略
↓
是否启动 Agent 逆向重构?
↓
┌───────┴───────┐
是 否
│ │
Agent 语义还原 标注局限性并直接审计
通过子 Agent 协作,可逐步实现:
- 语义变量名推导:将无序变量(
_0x1a2b)结合调用链还原为具备业务含义的名称(userToken、orderId); - AST 格式化与美化:重构控制流、规范缩进;
- 业务注释与函数摘要:结合业务逻辑推导函数功能并补充核心注释;
- 工作流多文件并行:利用 Workflow 多 Agent 并发对关键页面进行语义重构。
4.2.3 证据优先(Evidence-First)
为避免多轮对话和复杂调用链中 Agent 产生事实幻觉或结论前后矛盾,审计全流程必须维护强类型状态拓扑:
{
"facts": [],
"hypotheses": [],
"confirmed_findings": [],
"rejected_findings": [],
"blocked_tasks": [],
"missing_artifacts": [],
"coverage": {},
"next_actions": []
}
针对每一个潜在漏洞,严格记录其演进链路:
{
"hypothesis": "订单详情接口可能存在水平越权 (IDOR)",
"evidence": [
"orderId 直接来源于 onLoad.options.id",
"网络请求携带当前登录用户的 JWT Bearer Token",
"前端未进行订单 owner 校验,后端接口亦无隔离校验"
],
"missing_evidence": [
"测试账号 B 凭证",
"属于账号 B 的真实 orderId"
],
"status": "NEEDS_SECOND_ACCOUNT"
}
同时,通过维护全局 artifact-manifest.json 跟踪所有材料来源,确保每一条审计 Finding 均可溯源至原始包与行号:
{
"artifact_id": "pkg-001",
"type": "wxapkg",
"role": "main_package",
"appid": "wx1234567890",
"version": "42",
"source": "wechat_macos_cache",
"original_path": "/path/to/__APP__.wxapkg",
"sha256": "3a8c1f...",
"size": 1837462,
"collected_at": "2026-08-01T14:00:00+08:00",
"toolchain": {
"extractor": "WxLocated",
"extractor_version": "1.2.0"
},
"status": "EXTRACTED",
"warnings": []
}
Finding 反向关联证据链:
{
"finding_id": "VULN-2026-001",
"evidence_refs": [
"pkg-001:pages/order/detail.js:120-146",
"request-017",
"response-019"
]
}
4.2.4 身份验证矩阵(Identity Matrix)
在 API 与逻辑层审计中,越权与未授权访问是高发漏洞。Agent 不能仅支持“单 Token 单角色”检测,而必须具备身份拓扑认知:
角色维度:
├── 匿名访问 (No Auth)
├── 普通用户 A
├── 普通用户 B
├── 付费 VIP 会员
├── 商家 / 商户端
├── 内部员工
├── 系统管理员
└── 租户边界 (Tenant A vs Tenant B)
自动衍生笛卡尔交叉验证矩阵:
交叉测试用例:
├── 用户 A Token + 用户 A 资源 → [正常访问基线]
├── 用户 A Token + 用户 B 资源 → [测试水平越权]
├── 用户 B Token + 用户 A 资源 → [双向水平校验]
├── 无 Token + 敏感业务接口 → [测试未授权访问]
├── 过期 Token + 受保护资源 → [测试凭证失效机制]
├── 普通用户凭证 + 后台管理接口 → [测试垂直越权]
└── 租户 A 凭证 + 租户 B 资源 → [测试多租户数据穿透]
同时对异常结果做明确分类,避免将公开静态资源或无需认证的正常接口误报为越权缺陷:
- 认证缺失(Authentication Missing)
- 水平越权(IDOR / Horizontal Privilege Escalation)
- 垂直越权(Privilege Escalation)
- 跨租户数据越权(Cross-Tenant Breach)
- 资源不存在(404 Not Found)
- 业务公开访问(Public Accessible)
五、真实审计案例复盘
挑选两个近期通过该方案完成的实战审计案例进行复盘。
5.1 案例一:某考研择校辅导机构小程序
目标特征
- 业务场景:高校择校测评、VIP 付费咨询、考研资料库;
- 架构体系:主包 + 3 个业务分包。
审计过程
- 包重构:使用 WxLocated 进行快速定位、解包与目录拓扑生成;
- 智能分析:在 Claude Code 环境下加载
miniapp-audit编排套件(使用 Claude 3.7 Sonnet / High Thinking); - 并发还原:调度 SubAgent 并发对核心路由和支付/鉴权模块进行代码清洗与语义恢复;


- 端点整理:Agent 自动梳理出高度结构化的
endpoints.txt与parameters.txt,相比传统正则匹配,能更好捕获动态拼接的参数名与接口地址:


- 报告产出:自动化输出完整规范的 Markdown 审计报告:

核心审计成果
【主要风险点摘要】
1. 硬编码凭据
- 前端代码中散落云服务存储桶 SecretKey、短信签名第三方密钥。
2. 水平越权漏洞 (IDOR-001)
- 严重级别: 🔴 CRITICAL
- 置信度: HIGH
- 漏洞端点: GET /certifications/:uid
- 问题描述: 任意认证用户通过修改 uid 入参,可直接查询其他考生的真实姓名、就读高校、报考专业等完整认证数据,后端缺少用户归属权判定。
3. 越权篡改漏洞 (IDOR-002)
- 严重级别: 🔴 CRITICAL
- 置信度: HIGH
- 漏洞端点: PUT /certifications/:id
- 问题描述: 用户 A 提交的认证记录可被用户 B 调用接口恶意覆盖修改,造成数据篡改及假冒认证。
4. 付费权益绕过
- 客户端根据本地缓存判定是否为 VIP 并控制跳转,修改客户端返回包即可未付费直接阅读 VIP 专属内容。
5.2 案例二:某高校课程签到系统
目标特征
- 业务场景:高校课堂定位签到、请假审批、学生平时成绩管理;
- 审计策略:聚焦于核心签到逻辑与请假审批流程,有针对性地挑选对应代码段进行还原分析。
审计成果
- 发现教师端与学生端共用同一套接口基座,缺乏细粒度的角色鉴权拦截;
- 存在鉴权 SecretKey 客户端暴露问题,可直接利用该密钥签发任意学号的伪造 Token,实现全自动化替签到与伪造请假条。

审计结果怎么验收
上面两组案例里,解包和接口提取只是起点。真正需要保留下来的是接口、参数、身份和返回数据之间的对应关系。公开资源、资源不存在、水平越权和跨租户访问要分别记录,避免把一个异常响应直接当成漏洞结论。
报告中的发现应回到对应业务流程核对:服务端是否验证数据归属,角色权限是否在接口层执行,客户端出现的凭据是否仍有效。静态代码还原提供线索,身份矩阵和请求响应证据才用于判断结论。本文案例描述不代表其他版本也存在相同问题。
抓包阶段可以配合Burp Suite 代理、扫描与 Collaborator 笔记,分析客户端和服务端之间的权限边界时可参考威胁建模与信任边界。
