App 下架备份攻略|mitmproxy 与 Apple Configurator 技术保存与还原教学
iOS App 即将下架?透过 mitmproxy 嗅探 API 资料与 Apple Configurator 备份 .ipa 档,实现 App 永久留存与资料回放,保存产品生命周期最后回忆,避免资料遗失。
Click here to view the English version of this article.
點擊這裡查看本文章正體中文版本。
基于 SEO 考量,本文标题与描述经 AI 调整,原始版本请参考内文。
App 产品进入终点站,能做什么事缅怀?
使用 mitmproxy + apple configurator 让 App 永远停留在下架前的状态
前言
咒术回战
工作时间久、经手过的产品多,也开始遇到有曾经参与过的产品要进入终点站(下架);从零到有开发一个产品如同孕育一个新生命,团队一起努力了 3–4 个月将孩子生下来;虽然后期已交由其他保母(工程师)继续培养,最近听到它即将进入产品生命周期的终点还是有些许遗憾。
人生也是如此,我们永远都不知道明天是太阳先升起还是意外先来临;唯一能做的就是珍惜当下,把事情做好。
缅怀
凡走过必留下痕迹,我们希望能在产品进入终点站之前做些什么,让大家还有机会回忆也让它至少留下存在过的证明;以下方式都需要 App 还在线上,如果已经下架就真的只剩回忆了。
非技术方式 — 录影
除了直接用 iPhone 内建的萤幕录影功能 之外,我们也可以使用 QuickTime Player 将手机接上 Mac 使用电脑进行录影、汇出影片。
- 在 Mac 上打开 QuickTime Player App
- 左上角工具列选择「档案」->「新增影片录制」
- 跳出录影介面后点击 🔴 旁的「v」,萤幕与扬声器选择您接上的手机
- 此时录影介面就会出现手机画面
点击「🔴」开始录影,回到手机上操作要录影的内容。
录影中会显示当前影片大小,欲结束录影再按一次「🔴」即可停止。
可以透过 QuickTime Player 工具列简单的裁剪影片,最后按下「Command」+「s」汇出储存影片到指定位置,即完成录影留念。
影片留念的好处是未来回忆比图片更容易串连起来,录的越深就纪录的越仔细,若要将更别画面转成图片也可以直接截图,很方便。
技术方式
App 技术备份可分为两个方向;「骨」App 本身其实只是个骨架、「肉」由 API Response Data 组成才是 App 内容资料的核心。
骨会随著 App 从 App Store 商城下架而消失。
肉会随著 API 主机、伺服器关闭而消失。
因此我们也分成备份骨跟肉两个技术方式。
声明
本文仅为技术研究分享,不鼓励利用任何技术进行非法、侵权行为。
[骨] 备份 .ipa App 安装档
App 在商城下架后已下载 App 的手机只要不主动删除 App,就会一直存在在该手机上,换手机用转移的方式也会一并转移过去。
但如果我们不小心删除该 App 或是换手机没转移,那就真的永远跟他说再见了;此时如果有手动备份商城的 .ipa 档案就能再次续命。
很久以前 逆向工程的文章 有提到过,但这次只需单纯备份 .ipa 档案不需敲壳,全部都是使用 Apple 官方提供的工具完成。
1.安装 Apple Configurator 2
首先去 Mac App Store 下载安装「 Apple Configurator 2 」
2. 将 iPhone 接上 Mac 并点击信任电脑
接上成功后就会出现 iPhone 的主画面。
3. 确认你的手机已安装欲备份 .ipa 档案的 App
我们需要在 Apple Configurator 2 卡出取代画面,才能取得下载到暂存中的 .ipa 档案,因此我们要先确保手机上有安装目标 App。
4. 回到 Mac 上的 Apple Configurator 2
点两下上面显示的 iPhone 主画面进入资讯页。
切换到「App」-> 右上角「+ 加入」->「App」
完成 App Store 帐号登入后可以取得您曾经购买过的 App 列表。
搜寻找到欲备份的目标 App,选择后点「加入」。
此时会出现等待视窗,正在 XXX 上加入 App、正在下载「XXX」。
5. 提取 .ipa 档案
放著等他下载完成后,会跳出询问是否要取代现有已安装 App 视窗。
此时不要按任何动作。此时不要按任何动作。此时不要按任何动作。
我们打开一个 Finder:
左上角工具列选择「前往」-> 「前往档案夹」
贴上以下路径:
1
~/Library/Group Containers/K36BKF7T3D.group.com.apple.configurator/Library/Caches/Assets/TemporaryItems/MobileApps
就可以找到下载下来正准备要安装的目标 App .ipa 档案:
将其复制出来即可完成 App .ipa 档案备份。
完成档案复制后再回去 Apple Configurator 2 点击停止,终止操作。
[骨] 还原 .ipa App 安装档
一样是将欲还原 App 的手机接上 Mac 并打开 Apple Configurator 2,进入 App 加入介面。
还原的话要选择左下角「从我的 Mac 选择…」
选择备份的 App .ipa 档案,按「加入」。
等待传送、安装完成,回到手机上就能重新打开 App,复活成功!
[肉] 备份最后的 API Response Data
这边会运用到之前在 App End-to-End Testing Local Snapshot API Mock Server 文章(细节原理可参考) 中所使用到的方式跟当时弄的开源专案:
同之前用录制 API Request & Response 来跑 E2E Testing 的技术,我们也可以用它来纪录 App 下架、停机前最后的 API Request & Response Data。
1. 安装 mitmproxy
1
brew install mitmproxy
mitmproxy 是一套开源的中间人攻击,网路请求嗅探工具。
如果你不熟悉 Mitmproxy 中间人攻击的工作原理可先参考我之前的文章:「 APP有用HTTPS传输,但资料还是被偷了。 」或 Mimproxy 官方文件 。
如果是用在纯网路请求嗅探,用不习惯 mimproxy 介面也可以改用「 Proxyman 」可参考之前 另一篇文章 的用法。
2. 完成 mitmproxy 凭证设定
针对 HTTPS 加密连线我们需要使用根凭证抽换进行中间人攻击,因此第一次使用须先完成手机端根凭证下载与启用。
*如果您的 App & API Server 有实作 SSL Pinning 也需要将 Pinning 凭证加入到 mitmproxy。
首先确保 iPhone 手机与 Mac 电脑是连接在相同的网路环境
若无 WiFi 电脑连接实体网路,也可以 打开 Mac 的 WiFi 分享功能 让手机连到 Mac 的网路
在 Terminal 启动 mitmproxy
or mitmweb
(Web GUI 版)。
1
mitmproxy
看到这画面代表 mitmproxy 服务已启动,目前没有流量进来所以是空的,挂在这个画面不要关闭 Terminal。
- 到 Mac 网路设定查看 Mac 的 IP 位址
回到手机 WiFi 设定点击「i」进入详细设定,找到最下方「设定代理伺服器」:
伺服器输入 Mac 电脑的 IP 位址
连接埠输入 8080
储存
在手机上打开 Safari 输入: http://mitm.it/
如果出现:
1
If you can see this, traffic is not passing through mitmproxy.
代表手机的网路代理伺服器没有设定成功或是 Mac 上没启动 mitmproxy
。
正常情况会出现:
此时只有 HTTP 流量能被嗅探,HTTPS 流量会报错,我们继续往下设定。
代表连接成功,我们找到 iOS 区块点击「Get mimproxy-ca-cert.pem」
- 点击「允许」
下载完成后进入到手机的设定,会出现「已下载描述档」点击进入。
- 点击进入,右上角「安装」,输入手机密码完成安装。
回到设定 -> 「一般」->「关于本机」-> 最下方「凭证信任设定」-> 启用「mitmproxy」。
- 「继续」完成启用。
至此我们就完成中间人攻击所有的前置准备工作。
要记得当前你手机所有的流量都会经过代理从你的 Mac 电脑出去, 操作完毕记得回到手机上的网路设定把代理伺服器设定关掉 ,否则手机网路 WiFi 会全部连不上对外网路。
回到 Terminal mitmproxy,一边操做手机上的 App 就能看到所有被捕捉的 API 请求纪录。
每个请求都能进入查看详细 Request & Response 内容:
以上是 mitmproxy 基础设定与实际工作。
3. 嗅探、了解 API 架构
再来就要透过 mitmproxy 的 mitmdump
服务结合我之前开发的 mitmproxy-rodo addons 录制请求和回放请求。
我的实现原理 是将 Request 请求参数计算成 Hash 值,在回放时再次将请求拿去计算 Hash 如果在本地有找到相同 Hash 值的备份 Response 则返回,如果有多个相同 Hash 值的请求会按照顺序储存&回放。
我们可以先透过以上方法嗅探 App 的 API (或使用 Proxyman ),观察有哪些栏位跟哪些栏位可能会影响 Hash Mapping,可以将其记录下来,在后续设定排除, 例如有的 API 固定会带 ?ts
这参数不影响回传内容,但会影响 Hash 值计算导致无法找到本地的备份,我们就需要挑出来在后面的设定中排除掉 。
4.设定 mitmproxy-rodo :
使用我写好的录制、回放开源 Script。
细节参数设定请参考该开源专案的说明。
1
2
git clone git@github.com:ZhgChgLi/mitmproxy-rodo.git
cd mitmproxy-rodo
将上一步骤 3. 挑出来的参数填入到 config.json 设定档案中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"ignored": {
"*": {
"*": {
"*": {
"iterable": false,
"enables": [
"query",
"formData"
],
"rules": {
"query": {
"parameters": [
"ts",
"connect_id",
"device_id",
"device_name",
]
},
"formData": {
"parameters": [
"aidck",
"device_id",
"ver_name",
]
}
}
}
}
}
}
}
以上参数在计算 Hash 值时都会被排除,也能针对个别 Endpoint 路径设定特定排除规则。
5. 启用录制,在 Terminal 下改执行:
1
mitmdump -s rodo.py --set dumper_folder=zhgchgli --set config_file=config.json --set record=true "~d zhgchg.li"
结尾的
"~d zhgchg.li"
意思是只截取 * .zhgchg.li 的流量。dumper_folder
: 输出目的目录名称
6. 回到手机上操作目标 App 执行欲录制的流程路径
建议重启、重安装 App 用最干净的方式开始操作
建议可以搭配录影,以利记得复现步骤
边操作的同时,就能看到输出目录会有很多撷取下来的 API Response Data,会照著 Domain -> API 路径 -> HTTP 方法 -> Hash 值 -> Header-X / Content-X 存放(若相同 Hash 请求两次,会按照顺序储存下来)。
重新录制可以直接删出输出目录,让他重新撷取。
如果回传的资料包含个资,请记得调整撷取内容去识别化。
[肉] 回放撷取到的 API Response Data
录制完毕后请务必要尝试回放一次,测试资料是否正常,若 Hash Hit 很低(回放时几乎都没找到对应的 Response),可以重复嗅探步骤找到那个每次执行 App 都不确定影响 Hash 值的变数并将其排除。
执行回放:
1
mitmdump -s rodo.py --set dumper_folder=zhgchgli --set config_file=config.json
dumper_folder
: 输出目的目录名称预设本地没有 Hash Mapping 到的 Response Data 会直接回传 404 让 App 空白,这样才能知道撷取的资料有没有效。
录制撷取时有经过过的路径页面,回放时能重新显示:OK!
录制撷取时没经过过的路径页面,回放时显示网路错误:OK!
缅怀
至此,我们已经可以自行透过还原骨与最后的肉,来复现当年 App 走进终点站前的最后时光,以此缅怀那个大家一起同心协力生产出来的时光。
以此篇文章纪念第一份工作的团队与当年从网页后端开发边做边学转职 iOS App 开发,独立从无到有在 3–4 个月的短暂时间,与 Android、设计、PM 主管、后端同事一同顺利生产出的产品,虽然它即将进入生命周期的终点站,但我永远都会记得当年的酸甜苦辣与第一次看到他上线、有人使用的那个感动。
「谢谢」
欢迎协助贡献
如果你也有相同的遗憾,希望本篇文章也能帮助到你,因为 mitmproxy-rodo 当初只是 POC 概念验证下开发出的工具,欢迎协助贡献、提出遇到的 Bug 或开 PR 修改 Bug。
有任何问题及指教欢迎 与我联络 。
本文首次发表于 Medium (点击查看原始版本),由 ZMediumToMarkdown 提供自动转换与同步技术。