一次某 App 登录链路排查记录:反编译 + Proxyman + Android 模拟器
这篇是一次匿名化的排查记录,只保留方法和判断过程。真实包名、域名、接口路径和业务背景都做了脱敏,统一记成某 App、某网关、登录接口。
我这次的目标很简单:不是研究整个 APK,而是把某 App 的手机号登录链路摸清楚,最后拿到真实请求参数,方便和后台联调。
环境先定死,不然后面会一直怀疑链路⌗
我这次用的是:
- macOS
- Android Studio 自带模拟器,机型是 Pixel 8a
adb- Proxyman
- 一份 APK 安装包
先把 APK 装进模拟器,确认 App 至少能正常拉起:
adb -s emulator-5554 install -r base.apk
adb -s emulator-5554 shell monkey -p 某.app.package -c android.intent.category.LAUNCHER 1
这一步看着没技术含量,但很关键。后面如果抓不到流量,得先排除是不是 APK 根本没跑起来,或者其实还停留在 splash / 隐私页 / 历史登录态。
第一轮先做静态分析,但不要太相信静态结果⌗
我一开始先把 APK 反编译了一遍,主要看三类东西:
- 包名、版本号、启动页
- Retrofit / OkHttp 这类网络定义
- dex 里的接口路径和动作名字符串
静态分析的价值主要有两个:
- 先知道它大概打向哪些后端
- 先知道它是 REST 风格,还是网关风格
我这次遇到的就是典型网关风格。URL 本身信息很少,真正的业务动作不在路径里,而是在请求体里的两个字段里:
A=业务动作
P=业务参数
也就是说,哪怕你在抓包工具里看到几十条长得一模一样的 POST,它们也可能分别对应“发验证码”“登录”“拉用户信息”“拉首页数据”。
静态分析里我还看到过一套看起来像旧登录服务的定义,一开始差点以为那就是登录入口。后来事实证明,这种判断很容易错。包里存在,不等于现在运行真的走它。
第二轮开始抓运行时流量,先踩的坑不是证书,是代理根本没进⌗
我本机最开始开的是别的代理工具,模拟器里也把全局代理指过去了,但流量面板完全没有记录。
后来换成 Proxyman,问题开始清楚了。
Android 模拟器访问宿主机,不该填 127.0.0.1,而是:
10.0.2.2
所以模拟器里的代理要这么设:
adb -s emulator-5554 shell settings put global http_proxy 10.0.2.2:9090
adb -s emulator-5554 shell settings get global http_proxy
# 取消代理
adb -s 172.20.130.185:5555 shell settings put global http_proxy :0
我当时专门验证了三件事:
- 模拟器能
ping 10.0.2.2 - 宿主机上的 Proxyman 确实监听了
9090 - 模拟器能直接和
10.0.2.2:9090建立 TCP 连接
这一步非常重要。很多时候你以为是 App 绕过了代理,结果实际上是模拟器根本没打到宿主机代理端口。
浏览器能走代理,只说明链路通,不代表 App 一定会老实走⌗
我排查代理是否生效时,用了一个很土但很有效的方法:先不碰 App,直接让模拟器浏览器访问一个纯 HTTP 页面。
如果浏览器请求能在 Proxyman 里看到,说明至少这条链路是通的:
模拟器 -> 10.0.2.2:代理端口 -> Proxyman
这一步只解决了“代理通不通”,没有解决“某 App 会不会按系统代理走”的问题。
两者不是一回事。
有些 App 会老老实实走系统代理,有些不会。有些即使走了代理,到了 HTTPS 阶段还会因为证书校验、TLS 握手或更严格的校验策略直接失败。
日志里出现握手失败,不等于前面的判断全白做了⌗
我当时在 logcat 里能看到明显的 TLS 相关调用栈,比如:
startHandshakeconnectTlsgetOutputStream
这说明有部分网络请求确实已经走到了 HTTPS 连接阶段,只是后面没有顺利完成。
这类现象很容易把人带偏,误以为“代理完全没生效”。其实不一定。
更准确的理解应该是:
- 代理链路可能是通的
- 请求也可能已经发起了
- 但某些 HTTPS 流量在客户端校验阶段被拦下来了
所以这一步我没有再继续怀疑代理端口,而是转头去看另一件更关键的事:这次抓到的流量,到底是不是登录时刻的流量。
第一次导出的 CSV 看着很多,其实没法直接定位登录请求⌗
我后面导出过一份 CSV,请求数量并不少,但问题也很明显:
- 能看到某统计域名
- 能看到某网关入口被多次调用
- 能看到若干初始化接口
- 但看不到
POST body
这就导致一个典型误判:表面上像“没抓到登录接口”,其实更可能只是导出格式不对。
因为这个 App 的关键数据根本不在 URL 上,而是在 body 里。例如同样是某个统一网关入口:
- 一条可能是发验证码
- 一条可能是提交手机号和密码
- 一条可能是登录成功后拉用户信息
只看 CSV 里的路径和状态码,根本分不出来。
后来我回头看那份导出,还能发现一个反证:请求里已经带上了登录后才常见的一些上下文字段。这说明那次抓到的不是“第一次登录动作”,而是已经进首页之后的初始化流量。
清数据重新进一次,才有资格谈登录链路⌗
这次排查里最容易被忽略的一步,就是清空 App 数据。
如果模拟器里残留了历史状态,App 很可能:
- 直接跳过登录页
- 先落到主页
- 再补发一堆首页初始化请求
这样抓出来的数据再多,也不是你要的那条登录链路。
所以我后面每次重新验证前,都会先做:
adb -s emulator-5554 shell pm clear 某.app.package
adb -s emulator-5554 shell monkey -p 某.app.package -c android.intent.category.LAUNCHER 1
只有保证自己从冷启动、未登录状态进 App,后面看到的验证码请求、登录请求、登录后请求,时间顺序才可信。
真正有用的结论,不是“抓到了一个 URL”,而是确认了它的调用模型⌗
最后把静态分析和运行时抓包对起来,最有价值的不是某一条具体路径,而是下面这几个判断被坐实了:
- 这个 App 的主业务请求走统一网关,不是每个功能一个独立 URL。
- 真实业务动作藏在 body 里的
A和P,不是藏在 path 里。 - 静态分析里看到的某些旧接口定义,和当前实际登录链路不是一回事。
- 只导出 CSV 摘要不够,必须能看到 request body,才能判断哪一条是登录。
- 如果不先清数据,抓到的大概率是首页初始化流量,不是登录流量。
也正是因为这几个判断明确了,后面我才能在代理工具里缩小范围,最终拿到真实的登录请求参数。
这次排查里最值钱的其实是三个经验⌗
1. 静态分析负责缩小范围,动态抓包负责确认事实⌗
只看静态分析,很容易被包里的历史代码误导。只看动态抓包,如果没有上下文,又容易把网关型请求看成一堆无意义的重复调用。
两者一定要结合着看。
2. 模拟器代理最容易错在宿主机地址⌗
只要是 Android Emulator,访问宿主机代理,先想 10.0.2.2,别先想 127.0.0.1。
3. 导出格式决定你能不能定位登录动作⌗
如果导出的只是 URL、状态码、请求体大小,那基本只能做流量概览。真正要定位登录,至少要能看到:
- 请求时间顺序
- Request Body
- Response Body
否则你只能看到“网关被调用了”,看不到“登录到底怎么调的”。
收尾⌗
这次过程看起来像是在折腾反编译、代理、模拟器和日志,其实最后真正解决问题的,是把每一层的职责分清楚:
- 反编译用来判断请求模型
- 代理用来拿运行时真实参数
logcat用来判断代理阶段卡在哪- 清数据用来保证时序可信
把这些顺序理顺之后,登录链路其实没有想象中那么玄学。难的不是工具本身,而是别在错误的样本上做判断。

ps: 对于https 需要安装proxyman证书才能解密(如果是抓包设备应该把proxy证书安装在设备上),对于http明文可以看到