Skip to content

WRITING / 文章

微信小程序自动化审计:从解包到Agent智能分析

深入探讨微信小程序安全审计的完整流程,包括wxapkg解包、反编译分析、WxLocated工具实践,以及基于Agent的自动化审计思路与实现。

本文目录 22 个章节

本文概览

本文系统记录近期针对微信小程序安全的研究与自动化审计思路,涵盖缓存定位、解包反编译、架构分析、本地工具研发(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/

最新版微信的小程序缓存树形拓扑结构如下:

CACHE TOPOLOGY从账号目录走到版本包
radiumusers<账号哈希>appletpackages<AppID><版本>
主包
__APP__.wxapkg

App 启动逻辑、主页面、tabBar、分包清单

普通分包
xxxx.wxapkg

进入对应页面时下载

独立分包
yyyy.wxapkg

可不加载主包直接启动

扩展包
zzzz.wxapkg

插件或其他资源

同一个 AppID 下可以有多个版本;实际包名和目录内容以采集结果为准。

为了方便在 macOS 上快速查找与解析这些 wxapkg,我开发了原生 macOS 工具 WxLocated(具体功能将在后文详细介绍)。

WxLocated 界面

1.2 解包与反编译方案

针对微信 4.0 版本的解包反编译,社区已有成熟方案,例如基于 Go 开发的开源工具:

使用效果如下(但 macOS 下直接查看往往难以区分具体 AppID 归属,配合 WxLocated 定位更高效):

wxapkg 解包效果


二、wxapkg 分析思路与小程序架构

对 wxapkg 进行逆向分析本质上类似于前端安全分析,但额外多了一层**“微信运行时与客户端容器”**。通常先通过静态分析定位风险点,再结合动态测试展开深挖。

微信小程序逆向分析核心要素:
WXML + WXSS + JavaScript + 微信客户端运行时

核心思路与常规 Web 渗透一致:通过源码挖掘硬编码凭据、API 端点、鉴权缺陷,进而伪造凭证或实施后利用。

2.1 Web 前端与微信小程序技术对照

Web 前端微信小程序说明
HTMLWXML标签化结构定义语言
CSSWXSS样式语言,支持 rpx 尺寸转换
JavaScriptJavaScript双线程架构,运行于 JsCore 中
浏览器 DevTools微信开发者工具 / 客户端调试官方调试套件
localStoragewx.setStorage / wx.getStorage本地键值持久化
fetch / axioswx.request网络数据请求
WebSocketwx.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

客户端在下载该包后,依次执行以下启动阶段:

  1. 解析文件:读取 .wxapkg 文件头与索引结构;
  2. 释放资源:提取包内虚拟文件并建立映射;
  3. 加载配置:解析 app.json 全局与页面配置;
  4. 初始化逻辑:在 JsCore 线程启动 JavaScript 逻辑层;
  5. 渲染页面:在 WebView 线程渲染 WXML 与 WXSS 界面。

2.3 wxapkg 文件物理结构

.wxapkg 是微信自定义的打包文件系统,无法直接使用 unzip 等通用解压工具打开。其结构由固定头部、文件索引表与正文数据区组成:

BINARY PACKAGE.wxapkg 的四层结构
01
包头标识 / 段长 / 索引长
HEADER
02
文件索引表路径 / 偏移 / 大小
INDEX
03
文件内容区按索引定位文件数据
DATA BODY
04
包尾校验标记结束与校验信息
TRAILER

读取索引中的路径、offset 与 size,再从数据区截取对应文件。

解包工具的核心逻辑是首先解析文件索引表,获取各个子文件的虚拟路径、起始偏移(offset)与字节长度(size),然后再从数据区精确截取对应文件内容。

wxapkg 结构分析

.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 主包与分包机制

中大型小程序通常采用分包加载策略,降低首次下载体积:

小程序版本包分类
├── 主包:启动时必须加载的核心代码
├── 普通分包:访问特定页面时按需下载加载
├── 独立分包:可绕过主包直接启动加载
└── 资源扩展包:插件包、游戏资源或运行时模块

多版本目录层级示意:

VERSION LAYOUT同一 AppID,不同版本分别存放
packages / wx1234567890abcdef /APP ID
12 /版本 12
__APP__.wxapkg 主包xxxxx.wxapkg 分包 Ayyyyy.wxapkg 分包 B
13 /版本 13
__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 开发了一款轻量级的小程序安全分析工具:

核心定位与能力清单

  1. 缓存目录探测:自动识别 macOS 上常见的 3.x、4.x 以及多账号架构缓存目录;
  2. 包指纹解析:原生解析标准 wxapkg 与 V1MMWX 微信本地加密缓存包,提取 AppID、名称、Logo、版本、主分包关系;
  3. 虚拟文件树重构:将主包与多级分包重构成完整统一的工程树;
  4. 源码反编译恢复:静态还原 app.json、页面配置文件、JavaScript 逻辑、WXS、WXML 标签树与 WXSS 样式;
  5. Source Map 还原:自动提取内嵌 Source Map 并恢复原始未混淆源码;
  6. 代码语义美化:上下文感知美化 JS 语法,保持复合运算符、正则表达式和模板字符串语义;
  7. 攻击面提取:自动汇总提取全部请求接口、请求入参、外部域名、加解密密钥与敏感凭证;
  8. 安全无害化:所有解析完全在本机闭环进行,应用绝不执行包内代码,亦不发起任何外部网络通信。

软件界面展示

自动扫描 macOS 上的多代微信缓存目录(部分目录需授权访问):

缓存扫描

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

元信息查看

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

源码重构导出

macOS 原生 UI 开发设计记录:

Xcode 开发环境

源码构建方式

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 编排架构

INTERACTIVE / AUDIT PIPELINE
把审计过程拆成五个可检查的阶段

点击阶段,查看该阶段要回答的问题与应留下的材料。

01 / COLLECT
先确认包是否齐全

对照主包、普通分包和独立分包,记录版本与来源;缺失材料先标记,不把未覆盖代码当作安全结论。

OUTPUT / EVIDENCE__APP__.wxapkg + package inventory

每一步都可以停在“材料不足”;流程图不是自动确认漏洞的承诺。

AGENT ORCHESTRATIONminiapp-audit · 主编排引擎
01
material-check

材料与完整性感知

02
attack-surface

攻击面与接口清单

03
secret-scan

硬编码凭证扫描

04
authz-analyzer

越权与权限矩阵

05
payment-audit

支付安全检查

06
dataflow-tracer

污点与数据流追踪

07
privacy-compliance

用户隐私合规

08
dynamic-tester

动态验证与 PoC

09
code-restorer

LLM 语义逆向还原

10
report-builder

审计报告生成

模块各自留下中间材料,最终由报告阶段关联证据与结论。

4.2 核心设计理念

4.2.1 完整性感知

传统静态扫描工具往往“给什么扫什么”,容易因材料缺失导致误报或严重漏报。真正合格的智能审计 Agent 必须具备完整性认知:

完整性闭环流程:
输入 wxapkg / 微信缓存 / 反编译目录
           ↓
material-check 检查材料完备度
           ↓
智能决策:材料是否足以开展全量分析?
           ↓
构建攻击面总览与接口拓扑
           ↓
自动生成针对性测试假设与验证任务
           ↓
排除误报并关联上下文
           ↓
输出带证据链条的报告与复现脚本

在正式开启扫描前,Agent 必须首先核验以下先验条件:

  • 是否存在主包?
  • 全局配置声明了几个分包,实际收集到几个?
  • 是否包含未加载的独立分包?
  • 是否误混入旧版本分包?
  • 插件包是否存在缺失?
  • 反编译出来的代码语义是否完整?

4.2.2 渐进式逆向还原

通过开源逆向工具还原出的前端代码往往包含大量的变量名混淆(如 _0x1a2b)、语法压缩与死代码:

逆向混淆代码示例

LLM 最突出的能力之一是上下文理解与语义推断。审计套件内置了渐进式逆向还原机制:

代码还原编排:
用户输入反编译目录(混淆/质量参差不齐)
               ↓
material-check 自动化评估代码可读性与质量
               ↓
       ┌───────┴───────┐
    质量合格        存在明显缺陷
       │               │
    直接审计        交互询问 / 自动评估策略
                       ↓
               是否启动 Agent 逆向重构?
                       ↓
               ┌───────┴───────┐
              是               否
               │               │
         Agent 语义还原    标注局限性并直接审计

通过子 Agent 协作,可逐步实现:

  1. 语义变量名推导:将无序变量(_0x1a2b)结合调用链还原为具备业务含义的名称(userToken、orderId);
  2. AST 格式化与美化:重构控制流、规范缩进;
  3. 业务注释与函数摘要:结合业务逻辑推导函数功能并补充核心注释;
  4. 工作流多文件并行:利用 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 个业务分包。

审计过程

  1. 包重构:使用 WxLocated 进行快速定位、解包与目录拓扑生成;
  2. 智能分析:在 Claude Code 环境下加载 miniapp-audit 编排套件(使用 Claude 3.7 Sonnet / High Thinking);
  3. 并发还原:调度 SubAgent 并发对核心路由和支付/鉴权模块进行代码清洗与语义恢复;

任务分发与分析过程

子任务执行状态

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

生成的材料清单

接口与参数解析详情

  1. 报告产出:自动化输出完整规范的 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 笔记,分析客户端和服务端之间的权限边界时可参考威胁建模与信任边界。

编辑这篇文章

继续阅读

同主题文章
上一篇
Threat Model
下一篇
CNVD-2026-20654: LG NAS 远程命令注入漏洞分析

本文目录

SEARCH / QUICK FIND

站内搜索

试试搜索