记一次 Android App 的逆向工程(一)
1 引子
国庆长假,跟媳妇去了个有山有水,稍微远离都市的地方,正好闭关分析了一下 115 手机端的通信协议,有了一点儿微小的收获。
整个分析过程,可以算是一个标准的逆向工程套路,故记录于此,对于逆向其他的 App 也可作为一个参考。
分析目标:115 手机版,Android 平台,版本 25.3.0。
工作平台:macOS Catalina 10.15.7。
2 分析工具
尽管开发 Android App 只需要一个 Android Studio
就够了,但是逆向工程 App ,却需要多个工具的辅助。
这里列出整个分析过程用到的工具,及对应的版本:
- 网络流量分析:
- Wireshark 3.2.7: https://www.wireshark.org/
- mitmproxy 5.2: http://mitmproxy.org/
- Android 开发:
- Android Studio 4.1: https://developer.android.com/studio
- apk 解包 / 打包:
- apktool 2.4.1: https://ibotpeaches.github.io/Apktool/
- jadx-gui 1.1.0: https://github.com/skylot/jadx
- so 反汇编 / 修改:
- Cutter 1.12.0: https://cutter.re/
- Binary Ninja Cloud: https://cloud.binary.ninja/
所有工具都是跨平台,而且免费的,在此向这些工具的开发者们,致以崇高的敬意。
3 截获通信
既然是要分析通信协议,首先就要截获通信的内容。
3.1 网络设置
常规的网络环境下,手机和电脑连接同一个路由器。在这种网络拓扑下,手机端的网络通信直接通过路由器转发到了互联网,无法在电脑端截获。
因此,要截获手机端的流量,首先要让电脑成为无线热点,让手机连接电脑提供的无线网络,而电脑自身通过有线网络连接原本的路由器:
这需要电脑同时具有有线网卡和无线网卡。如果电脑只有无线网卡,请准备一个 USB 有线网卡。
3.2 系统设置
在 macOS 上设置无线热点,可参考官方的手册: https://support.apple.com/zh-cn/guide/mac-help/mchlp1540/mac 。
设置完成后,在终端执行 ifconfig
命令,翻到输出的结尾,可以看到一个叫 bridge100
的网络设备,这个就是无线热点的网络设备,后面的抓包就针对这个设备进行。
1 | deadblue@Necronomicon ~ % ifconfig |
注意:
bridge100
这个名字可能随着系统更新,或者系统接入了其他设备而改变。
3.3 流量嗅探
首先登场的,是老牌嗅探和分析软件 ——Wireshark
。
将手机连上电脑开启的无线热点,为了减少其他流量的干扰,先把手机上所有程序退掉,静置几分钟。
然后从 Wireshark
中选择 bridge100
设备,启动嗅探,同时马上在手机上启动 115 客户端。
待客户端进入首屏界面后,停止嗅探,将嗅探的日志保存下来,以便后续分析。
3.4 流量分析
连上热点后,手机端的 IP 为 192.168.2.2
。
首先,使用过滤条件 ip.src == 192.168.2.2 && udp
,看一下手机端发出的 UDP 报文:
可以看到,所有 UDP 报文都是 DNS 查询,没有特殊的通信内容,可以忽略。
接下来,使用过滤条件 ip.src == 192.168.2.2 && tcp.ack == 0 && tcp.seq == 0
,看一下从手机端发起的 TCP 连接:
从这里可以看到,手机端发起了多个 TCP 连接,分别与不同服务器的 80
/443
/8011
/8088
端口进行了通信。
其中,80
和 443
端口分别是 HTTP 和 HTTPS 协议的默认端口。8011
端口的通信,查看后发现也是 HTTP 流量。而 8088
端口的通信,则是谜之数据。
先查看 80
与 8011
端口的通信。因为都是 HTTP 协议的通信,可以直接从 Host
请求头中获取对应的域名。
两个通信的域名分别为:cgi.connect.qq.com
和 astat.bugly.qq.com
,可以暂时忽略掉它们。
后面经过逆向 app,发现这两个通信是 115 客户端集成的,腾讯的某个 SDK 发起的。
针对 443
端口的 HTTPS 通信,可以通过 TLS 握手的 SNI
信息,查看对应的域名:
除截图的
uplb.115.com
外,还有其他几个 115 的域名,这里就不一一列出了。
而与 8088
端口的通信,通过同一份日志中的 DNS 查询记录,可以发现是服务器的域名是 ws.115.com
。
总结一下,通过 Wireshark
的嗅探和分析,可以得出如下结论:
- 115 手机客户端,主要通过 HTTPS 协议与服务器进行通信;
- 另有一个基于 TCP 自行封装的协议,与
ws.115.com
的8088
端口进行通信。
4 解密 HTTPS 通信
通过 Wireshark
,仅仅能够知道手机客户端使用了 HTTPS 协议进行了通信。
由于 HTTPS 协议的特性(或者说是 TLS 协议的特性),只有通信双方知道如何解密。
要想截获这部分内容,就需要一个神器 ——mitmproxy
—— 登场了:
4.1 设置代理
简单介绍一下 mitmproxy
:它作为一个代理服务器工作,并通过中间人攻击(Man-In-The-Middle)的机制,将所有经过它的 TLS 流量进行解密,前提是终端设备信任要它的 CA 证书。
关于 TLS 与中间人攻击,我会另起文章介绍,这里只需要知道它是解密 TLS 通信的神器即可。
mitmproxy
支持多种代理模式,在这篇文章的场景中,需要使用透明代理模式。
以透明代理模式启动 mitmproxy
,监听端口 9999
:
1 | mitmproxy --mode transparent --showhost --listen-port 9999 |
4.2 设置数据包转发
接下来,还要在电脑系统中设置数据包转发,将手机的 HTTP 和 HTTPS 流量转发到透明代理上。
第一步,启用系统的数据包转发功能:
1 | sudo sysctl -w net.inet.ip.forwarding=1 |
第二步,复制文件 /etc/pf.conf
到 /usr/local/etc/pf.conf
。用文本编辑器打开复制后的文件,找到 rdr-anchor
开头的一行,并在它后面追加一行内容:
1 | rdr pass on bridge100 inet proto tcp to any port {80, 443} -> 127.0.0.1 port 9999 |
第三步,启用数据包转发规则:
1 | sudo pfctl -f /usr/local/etc/pf.conf |
后续再需要通过
mitmproxy
的透明代理模式抓包时,只需要重复第三步即可。
4.3 安装 CA 证书
要解密 HTTPS 流量,还在需要手机端安装 mitmproxy
的 CA 证书。
在手机端浏览器访问 http://mitm.it
,会看到类似下图的界面:
点击其中的 Android
图标,下载 Android 系统中可以用的 CA 证书,然后按照系统的提示安装即可。
之后,mitmproxy
就可以正常截获并解密大部分 HTTPS 流量了。
这里说 “大部分”,是因为有的 app 并不信任自行安装的 CA 证书,或者干脆不信任所有的系统 CA 证书。
当然,这些也有相应的应对方案,由于本文没有遇到这些问题,因此略过。
4.4 见证奇迹的时刻?
与使用 Wireshark
嗅探流量的时候相同,先把手机端运行的程序全部退掉,静置几分钟。
在 mitmproxy
界面上按 z
键,清空所有捕获的流量,同时马上在手机端启动 115 客户端,捕获流量。从列表中可以清晰的看到 HTTPS 请求的路径和参数:
事不宜迟,马上点进一条记录的详细信息,看看服务端的响应:
Emmmm,可以看到,除了 HTTPS 外,还有另一层加密保护。
当然,这也在意料之中,在下一篇文章中,我将介绍如何来破解这层加密。
5 小结
尽管本篇文章详细讲述了分析应用通信协议的内容,但实际上,几乎 99% 的 C/S 结构应用都会使用 HTTPS 协议与服务端通信。这是因为 HTTP/HTTPS 的基础设施相对完善,一些常见的服务端需求,如负载均衡 / 区域加速 / 身份认证等,都有现成的协议和中间件支持。因此,出于成本和稳定性等因素的考虑,大多数厂商都会选择使用已有的地基,去构建自己的上层服务。
另外,可以看到 HTTPS 确实提供了比 HTTP 更高的安全性,但是仍然是不够的。如果对通信内容的安全性要求较高的话,在此之上再做一层加密是有必要的。