在逆向圈有一个非常常见的攻击方式,门槛极低,却能破坏绝大多数移动应用的业务逻辑:
直接替换 IPA 里的资源文件,然后重新签名安装。
攻击者通常只要解压 IPA,就能看到:
- 明文 JSON(配置、接口地址、UI 结构)
- 明文 JS(逻辑、校验、加密流程)
- 明文 HTML(WebView 页面)
- Flutter assets
- React Native 的 bundle
- 图片资源(图标、流程指引、场景脚本)
然后他们可以轻松做到:
- 删除风控逻辑
- 修改跳转配置
- 注入恶意 JS
- 替换 H5 页面
- 修改用户可见提示
- 伪造 UI
- 定制自己的 IPA 版本
重签名后就能安装,整个流程不需要任何逆向能力。
在攻击者面前,你的 App 的"资源文件"从来不属于你。
本文将围绕 "如何防止资源被替换" 展开,用工程视角构建一个可落地、可自动化、可持续维护的 iOS 资源安全体系。
一、为什么 iOS 资源文件这么容易被替换?
核心原因只有一个:
Apple 的签名机制只保证 Mach-O 不被篡改,并不保证资源文件完整性。
IPA 解压后,资源层是完全裸露的:
Payload/
AppName.app/
Assets.car
assets/xxx.json
js/xxx.js
h5/page.html
Flutter.framework/
*.png
*.plist
攻击者可以随意修改,再重新签名,也能运行。
特别是混合项目(Flutter / RN / H5),暴露面更大。
二、资源替换攻击会造成什么实际风险?
以下是常见实战案例:
✔ 修改支付逻辑、校验逻辑
JS/H5 页面常包含支付回调、签名校验、跳转地址。
✔ 绕过风控
json 文件里经常包含"开关"与"配置"。
✔ 替换 UI 诱导用户
图片文字修改,诱导用户点击错误按钮。
✔ 注入恶意代码
通过 WebView 注入 JS,可窃取 token、设备信息。
✔ 篡改 Flutter/RN 配置
assets 修改后可直接改变业务行为。
资源替换是实际攻击链路中最常见、门槛最低的方式。
三、资源防护不是单点,而是多工具组合策略
要防止资源被替换,需要覆盖三个关键环节:
- 结构扰动(让攻击者难以识别资源)
- 完整性检测(检测文件是否被替换)
- 资源混淆与路径保护(提高修改成本)
下面进入具体工具和方法。
四、工具矩阵:资源保护要用哪些工具协同完成?
① 静态分析工具(识别资源暴露)
| 工具 | 功能 |
|---|---|
| MobSF | 扫描资源目录、js/h5/json 暴露情况 |
| otool / nm | 确认是否有资源路径硬编码 |
| Hopper | 检查资源加载逻辑 |
这是处理前的"基线扫描"。
② IPA 层资源保护(核心层)
资源保护最有效的做法不是加密,而是:
- 改名
- 改路径
- 修改 MD5
- JS/H5 混淆
- 文件扰动
- 目录打散
- Swift/ObjC 层调用同步更新符号
- 保留正确运行所需结构
这些能力 Ipa Guard CLI 可以直接完成,而且支持自动化,无需源码。
主要能力包括:
- 修改图片/资源文件名
- 修改文件 MD5(提高替换难度)
- 对 JS 文件做混淆
- 扰动 Flutter/RN/H5 的 assets
- 生成符号与资源映射表
- 支持无源码保护 IPA(适合外包与混合项目)
示例流程如下。
Step 1:提取可混淆符号与资源引用
bash
ipaguard_cli parse app.ipa -o sym.json
该文件中会包含:
- 可混淆类名
- 资源引用路径
- 文件依赖关系
开发者可根据 fileReferences 决定哪些资源不能被动。
Step 2:执行资源扰动与符号混淆
bash
ipaguard_cli protect app.ipa \
-c sym.json \
--image \
--js \
-o protected.ipa \
--email dev@team.com
完成:
- 图片重新命名
- JSON/JS/HTML 改名与移动
- 文件 MD5 变化
- Swift/ObjC 层资源调用同步处理
- JS 混淆(可选)
攻击者此时再尝试替换文件,就会出现:
- App 无法找到新的文件名
- 文件被替换导致加载错误
- 业务逻辑崩溃或校验失败
- 无法恢复原路径结构
资源替换难度成倍增加。
③ 完整性检测层(运行时判断)
常用策略:
- 对关键配置做 hash 校验
- 对资源目录扫描 hash
- 对初始化阶段做完整性判定
- 注入 native 校验代码
可用 Swift/ObjC 手写或引入轻量工具。
Ipa Guard 修改资源 MD5 的能力也可作为完整性防御之一。
④ 重签名验证层(必须确保加固后还能正常运行)
用 kxsign:
bash
kxsign sign protected.ipa -c cert.p12 -p pwd -m dev.mobileprovision -z signed.ipa -i
验证:
- H5 页面是否仍正常加载
- JSBridge 是否正常
- Flutter 资源是否正常
- 资源路径是否无误
资源混淆最容易导致运行错误,因此这一步极其重要。
⑤ 逆向对抗层(验证资源是否真的难以替换)
工具:
| 工具 | 测试目标 |
|---|---|
| Hopper | 是否还可读出资源调用结构 |
| 手动替换测试 | 是否能修改 json、js、图片 |
| Frida | 测试 Hook 是否还能定位资源加载点 |
这是确认实际加固效果的最好方式。
⑥ 映射表治理层
资源被改名后:
- 文件路径
- 资源名
- 对应关系
都需要记录。
Ipa Guard CLI 会输出映射表,可存入:
- Git 加密仓库
- KMS
- S3(加密)
用于崩溃恢复。
五、可工程化的"资源防替换流程"示例(可直接加入 CI/CD)
① MobSF 分析 → 输出资源暴露报告
确认所有可读资源。
② Ipa Guard CLI 提取资源引用
bash
ipaguard_cli parse app.ipa -o sym.json
③ 自动处理资源混淆策略
白名单保留:
- 热更新相关路径
- SDK 必需资源
- Storyboard、xib
- JSBridge 与 WebView 关联路径
④ 执行资源混淆与扰动
bash
ipaguard_cli protect app.ipa -c sym.json --image --js -o protected.ipa
⑤ 重签并验证资源加载
重点验证:
- Flutter assets
- RN bundle
- H5 页面
- 配置 json
- 图片/动画资源
⑥ 替换攻击验证
尝试替换 json/js,看 App 是否能继续运行。
⑦ 映射表上传与归档
用于未来崩溃定位。
六、经过加固后,攻击者将无法轻易替换资源文件
攻击者将面临:
资源文件名全是随机值
路径已被打散,不知文件在哪里被引用
替换文件会导致 App 崩溃或功能失效
JS/H5 已混淆,难以修改
图片/音频文件的 MD5 已被扰动
Flutter/RN 的资源引用关系不再清晰
替换攻击的成本被成倍提高。
资源防替换是一套系统工程,而不是一个"加密动作"
要建立可靠的资源保护体系,需要多工具组合:
分析层
MobSF、class-dump
资源混淆层(核心)
Ipa Guard CLI
- 混淆符号
- 改名资源
- 扰动路径
- 修改 MD5
- JS 混淆
验证层
kxsign(签名与运行验证)、Hopper / Frida(逆向验证)