记一次 Android App 的逆向工程(一)

1 引子

国庆长假,跟媳妇去了个有山有水,稍微远离都市的地方,正好闭关分析了一下 115 手机端的通信协议,有了一点儿微小的收获。

整个分析过程,可以算是一个标准的逆向工程套路,故记录于此,对于逆向其他的 App 也可作为一个参考。

分析目标:115 手机版,Android 平台,版本 25.3.0。

工作平台:macOS Catalina 10.15.7。

2 分析工具

尽管开发 Android App 只需要一个 Android Studio 就够了,但是逆向工程 App ,却需要多个工具的辅助。

这里列出整个分析过程用到的工具,及对应的版本:

所有工具都是跨平台,而且免费的,在此向这些工具的开发者们,致以崇高的敬意。

3 截获通信

既然是要分析通信协议,首先就要截获通信的内容。

3.1 网络设置

常规的网络环境下,手机和电脑连接同一个路由器。在这种网络拓扑下,手机端的网络通信直接通过路由器转发到了互联网,无法在电脑端截获。

因此,要截获手机端的流量,首先要让电脑成为无线热点,让手机连接电脑提供的无线网络,而电脑自身通过有线网络连接原本的路由器:

这需要电脑同时具有有线网卡和无线网卡。如果电脑只有无线网卡,请准备一个 USB 有线网卡。

3.2 系统设置

在 macOS 上设置无线热点,可参考官方的手册: https://support.apple.com/zh-cn/guide/mac-help/mchlp1540/mac

设置完成后,在终端执行 ifconfig 命令,翻到输出的结尾,可以看到一个叫 bridge100 的网络设备,这个就是无线热点的网络设备,后面的抓包就针对这个设备进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
deadblue@Necronomicon ~ % ifconfig
####################
# Skip some output #
####################
bridge100: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=3<RXCSUM,TXCSUM>
ether XX:XX:XX:XX:XX:XX
inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
inet6 fe80::453:a68a:b070:e48f%bridge100 prefixlen 64 secured scopeid 0x10
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x0
member: ap1 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 5 priority 0 path cost 0
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
deadblue@Necronomicon ~ %

注意: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 端口进行了通信。

其中,80443 端口分别是 HTTP 和 HTTPS 协议的默认端口。8011 端口的通信,查看后发现也是 HTTP 流量。而 8088 端口的通信,则是谜之数据。


先查看 808011 端口的通信。因为都是 HTTP 协议的通信,可以直接从 Host 请求头中获取对应的域名。

两个通信的域名分别为:cgi.connect.qq.comastat.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.com8088 端口进行通信。

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
2
sudo pfctl -f /usr/local/etc/pf.conf
sudo pfctl -e

后续再需要通过 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 更高的安全性,但是仍然是不够的。如果对通信内容的安全性要求较高的话,在此之上再做一层加密是有必要的。

6 参考资料