我把一个Android应用转换成了网页
摘要
作者反向工程了Travelbound Android应用,发现它只是一个带有追踪和广告的网页,并使用HTTP Toolkit和已root的安卓模拟器将其转换为一个合适的基于网页的行程表。
<p><a href="https://lobste.rs/s/vhbvwc/i_converted_android_app_webpage">评论</a></p>
查看缓存全文
缓存时间: 2026/07/11 07:22
# 你的“应用”本来可以是个网页(所以我来帮你改了……)
来源:https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/
### 为什么这非得是个“应用”?
今年夏天,孩子们就读的表演艺术学校要去迪士尼乐园参加一场歌舞演出。大家都很兴奋,但*我*的兴奋劲儿——至少——在被告知需要安装“Travelbound”应用(https://play.google.com/store/apps/details?id=com.vamoos.apps.travelbound)才能查看行程、交通安排和住宿详情时,稍微打了点折扣。
去他的。这明明就该是个网页。为什么非要让我装一个(又一个)破应用,就为了告诉我一些完全可以放在一份(更小、更快、更通用的)文档里的东西?
> Android 应用截图,显示摘要行程:列出了“渡轮过境”、“酒店入住”、“司机住宿”、“迪士尼夏延酒店”和“欢迎晚宴”的时间,每项都配了一张漂亮但千篇一律的照片。(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#lightbox-p-attachment_29642)
我一点也没夸张。这个应用本质上就是文字、图片和指向PDF文件的链接,全部通过网络传输。
这个“应用”似乎只有两件网页做不到的事,而且这两件都算得上是“负功能”:
1. 它会向开发者报告与你的 Google 账号关联的追踪数据。
2. 它会向你展示由同一机构组织的其他旅行的广告(他们管这叫“灵感”)。
去。他。的。全。都。去。他。的。做网页会比这个好多了。不像这个应用,网页可以:
1. (https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#footnote-29641-1)
- 复制粘贴
- 打印
- 保存
- 添加书签
- 搜索
- 在几乎任何设备上使用
- (可能)更好的无障碍支持
我烦得够呛……所以我打算“修正”这个应用。看我的。
### 拦截应用流量
距离上次通过网络流量逆向分析安卓应用(https://danq.me/2018/07/05/comic-chameleon/)已经有一阵子了,所以我得重新熟悉一下最佳方法。最后我是这样做的:
1. 在 Android Studio 的虚拟设备管理器里创建了一个新的虚拟设备。
2. 测试了 `adb shell` 可以工作,然后用 rootAVD(https://gitlab.com/newbit/rootAVD)获取 root 权限:`./rootAVD.sh system-images/android-33/google_apis_playstore/x86_64/ramdisk.img`。
2. (https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#footnote-29641-2)
3. 冷启动后,运行 Magisk(https://github.com/topjohnwu/Magisk),调整设置让它自动授予 `su` 权限给任何请求的应用。
3. (https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#footnote-29641-3)
> HTTP Toolkit 应用在 MacOS 和模拟的 Android 手机上运行截图,启用了用户信任和系统信任。(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#lightbox-p-attachment_29644)
你的流量都归我了。到了这一步,就跟跑 Wireshark 或 TCPdump 差不多。
1. 运行 HTTP Toolkit(https://httptoolkit.com/)并让它拦截 AVD 的流量。它会安装一个(伪造的)VPN 提供商,把手机的流量通过代理路由出去。
4. (https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#footnote-29641-4)
2. 从 Play 商店安装 Travelbound 应用。
3. 配置 HTTP Toolkit,使其仅代理 Travelbound 应用(这样信号更多,噪音更少)。
只花了几分钟试验,我就发现这个应用的工作原理是把用户名和密码拼接起来
5. (https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#footnote-29641-5),然后用以下格式的 URL:
> `https://travelbound.api.vamoos.com/api/itineraries/{username}-{password}`
这会返回一大坨 JSON,稍加解释就能发现它代表了应用所“展示”的*所有内容*。例如,包含:
- 一个数组,里面是行程的每一段;
- 一个数组,里面是准备展示给你的所有“灵感”广告;
- 一个交叉引用的数组,包含其他部分引用的所有文件(图片等)。
> Firefox 显示 JSON 文档,聚焦于“你的渡轮过境”部分,附带一些 HTML。(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#lightbox-p-attachment_29645)
他们显然*还是*生成了 HTML 代码……所以我要再问一遍:*为什么这不能是个网页?*
稍加试验发现,S3 图片 URL 的过期时间比较短,所以即使内容没变,也需要定期重新获取 JSON。
6. (https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#footnote-29641-6)
### 把它变成更好的东西
现在我有了所有需要的东西,去做出一个……*更好的*东西。我写了一个 Ruby 脚本,通过 Cron 定时任务运行,拉取最新的 JSON 并用它生成一个 HTML 页面。我选择完全跳过“灵感”(数据模式中的“overlayRows”),只列出:
1. 行程中的项目;
2. 所有*未*被灵感或行程引用的文件(这是一种偷懒的方法来汇总 PDF 下载链接)。
然后我把这个页面托管起来,加上了密码保护:就是最初给旅行团的那个密码。我把使用的原始 JSON 放在 `<code>` 元素里,这样如果后来出现了模式中我没看到但可能出现的部分,也可以检查。
> 一个简单样式网页的截图,显示关于渡轮的相同信息,以及一张甲板照片。(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#lightbox-p-attachment_29647)
我的网页没有那个“借用”信息的应用那么“漂亮”。但它体积小得多,而且免费获得了 Web 的所有标准功能。
有些人喜欢“应用”,这……好吧,我猜也是。但有些应用*本来*可以是个网页。特别是像这个应用一样,交付的内容已经是 HTML 写成的,并且通过 HTTP 传输……那它们*本来就应该*是个网页,对吧?我不明白我们怎么会走到“应用文化”这个地步!软件公司明明可以*让工作更轻松*(*也更便宜*:部署到大型应用商店可不是免费的!),却非要为了*用更少的功能*把 HTML 内容*传送给更少的人*
7. (https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#footnote-29641-7),而不是直接发布到网络上。
有些任务用“应用”确实是正确选择。Travelbound 不在其列。但至少*我*(以及我们旅行团里我分享出去的其他人)现在*可以选择*如何访问这些内容了。要么是一个 43MB 的应用(下载完额外内容后会膨胀到 124MB),附带追踪和广告;要么是一个 0.05MB 的网页(可选额外 35MB 的图片),提供更多功能,在更多设备上可用。我知道我会用哪一个!
> Android 应用截图,显示摘要行程:列出了“渡轮过境”、“酒店入住”、“司机住宿”、“迪士尼夏延酒店”和“欢迎晚宴”的时间,每项都配了一张漂亮但千篇一律的照片。(https://bcdn.danq.me/_q23u/2026/07/travelbound-app-summary.png)×(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#attachment_29642)
> HTTP Toolkit 应用在 MacOS 和模拟的 Android 手机上运行截图,启用了用户信任和系统信任。(https://bcdn.danq.me/_q23u/2026/07/http-toolkit-intercepting.png)×(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#attachment_29644)
> Firefox 显示 JSON 文档,聚焦于“你的渡轮过境”部分,附带一些 HTML。(https://bcdn.danq.me/_q23u/2026/07/travelbound-api-json.png)×(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#attachment_29645)
> 一个简单样式网页的截图,显示关于渡轮的相同信息,以及一张甲板照片。(https://bcdn.danq.me/_q23u/2026/07/untravelbound-webpage.png)×(https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/#attachment_29647)
相似文章
@HowToAI_: 有人开源了一个工具,可将任何网站转换为安卓应用,且完全在本地运行。只需粘贴网址,点击构建…
一个开源工具允许用户将任何网站转换为安卓应用,完全在手机上本地运行,输出APK以供安装和分享。
[DEV] Android优先的OpenClaw实现:登录浏览器访问、后台任务和个人应用
Mechanly是一个新的Android优先工具,允许用户利用手机浏览器会话、通知和调度能力创建个人应用和后台任务,灵感来自OpenClaw。
Show HN:通过逆向工程将Web应用转化为代理工具
一个基于浏览器的代理,能够逆向工程Web应用API,自动生成代理工具,实现无需修改代码的深度集成。
从Firefox提升权限至Android Root
本文宣布了Android 17上首个从浏览器到内核的全链路远程代码执行漏洞,源代码即将发布。
使用Claude Code对Android恶意软件进行逆向工程
本文详细介绍了作者如何使用Claude Code对预装在廉价Android投影仪上的恶意软件进行逆向工程,识别并禁用了可疑的软件包。