研究的第二部分已经发布:《MAX 的隐藏功能 #2:这款即时通讯软件内置了用于通话的关键词识别系统》。
在第三部分,我计划解答评论和论坛中最常被问到的问题。如果您有任何疑问,请告诉我;我会拿着代码一步步为您解答。
-
MAX 是否在后台监听麦克风?
-
MAX 是否像 Telegram 一样具有端到端加密 (E2E)?
-
未经授权是否可以获取聊天记录中的照片?
-
MAX 在安全性方面与 Telegram 有何不同?
这些问题以及其他问题的答案将在第三部分中给出。
该研究的第三部分已经发表:
TL;DR(太长不看版)
- VK 的 MAX(前身为 TamTam)会在您每次通过 6 个服务(Yandex、Amazon、 Mail.ru等)打开 VK 时秘密检测您的外部 IP 和 VPN。
- 这些服务的 URL 以数字数组的形式隐藏在代码中,因此无法通过搜索和快速分析网络流量找到它们。
- 该应用程序检查俄罗斯服务的可用性,包括gosuslugi.ru(Gosuslugi 已集成到 MAX 中,但它检查的是可用性 ,而不是功能)。
- 检测 VPN 并将信息发送到服务器。调用代码包含一个“无需 VPN 效果更佳”的小部件(该小部件存在于代码中,未经动态验证)。
- 代码中包含域名main.telegram.org和mmg.whatsapp.net - 虽然当前版本中未使用它们,但它们出现在活动检查旁边这一事实值得注意。
- 所有数据均与您的 MAX 账户( OK.ru ID)关联:IP 地址 + 运营商 + VPN 状态 + 时间
如果您感兴趣,下面有详细的分析。如果您想查看代码本身,请向下滚动到“第二部分”。
这是该系列文章的第一篇。
我正在对 MAX 即时通讯软件进行全面的安全审计。本文主要介绍其 IP 地址收集系统和 VPN 检测功能。如果大家对这个话题感兴趣,后续还会推出更多文章。
- 静默呼叫 :服务器如何在不响铃或显示用户界面的情况下发起呼叫
- 通过麦克风输入关键词 :MAX 内置了 ASR(语音识别)、语音识别和关键词检测功能,其模型由服务器提供。
- 端到端加密?不,你肯定没听说过 :消息、联系人和令牌都是以明文形式存储的。
背景
我从事移动应用安全审计工作。最近我接手了 MAX 的调查,这是一款来自 VK 的即时通讯应用,它被大力宣传为“Telegram 的替代品”。我从 Google Play 和 RuStore 下载了 APK 文件,使用 JADX 对其进行了反编译,然后开始深入研究代码。
在分析网络流量时,我注意到一个奇怪的现象:每次启动应用时,它都会访问checkip.amazonaws.com。这是亚马逊的一项服务,用于获取你的外部 IP 地址。为什么这款即时通讯应用需要通过亚马逊获取我的 IP 地址呢?
我顺着线索找到了一个完整的子系统,而不是一个漏洞。它经过精心设计、调试,具备防检测保护和保证数据传输到服务器的功能。这不是简单的分析,而是网络监控基础设施。
第一部分:我的发现
不包含代码,以下是概要:该应用程序的功能、其运行原因以及存在的风险。
- 六种查找您IP地址的服务
每次打开 MAX 时,该应用都会秘密检测您的外部 IP 地址。它使用六项服务来实现这一点:
- ipv4-internet.yandex.net — Yandex
- ipv6-internet.yandex.net — Yandex
- ifconfig.me 是独立的
- api.ipify.org — 独立
- checkip.amazonaws.com - 亚马逊
- ip.mail.ru - Mail.ru(VK 集团)
六个服务——只为完成一项任务。为什么要这么多?为了可靠性:如果一个服务没有响应,另一个服务会接替。每次的顺序都是随机打乱的——这使得基于网络模式检测请求变得更加困难。
但最有趣的是:这些服务的地址隐藏 在代码中。它们不是像“ https://ip.mail.ru/ ”这样的常规字符串,而是数字数组:
{104, 116, 116, 112, 115, 58, 47, 47, 105, 112, 46, 109, 97, 105, 108, 46, 114, 117, 47}
每个数字都是一个字母的 ASCII 码。104 代表“h”,116 代表“t”,以此类推。这样就得到 了https://ip.mail.ru/这样的网址。标准的 ASCII 码搜索(例如 grep、strings)永远找不到这些网址。这不是漏洞或优化问题,而是有意隐藏 。
还有一点:该应用程序使用底层原始套接字(java.net.Socket)发送请求,而不是标准的 OkHttp 库(后者很容易被拦截)。这绕过了网络拦截器、代理和流量监控。
简单来说: 一个典型的应用程序如果出于合法目的(例如,为了提供地理位置信息)需要你的 IP 地址,它会通过标准库发出一个请求。而 MAX 则通过隐藏的 URL,经由原始套接字发出六个备份请求。这可是恶意软件级别的技术。
2. 五项辅助功能检查:该应用程序会确定您是否身处俄罗斯
在收集 IP 地址的同时,该应用会检查五个主机的可用性,以确定您的手机是否可以连接到它们:
- api.oneme.ru (VK集团)——其自身的API
- gstatic.com (谷歌)——互联网访问检查器
- mtalk.google.com (谷歌)—推送通知
- calls.okcdn.ru (VK 集团)— 通话 CDN
- gosuslugi.ru (俄罗斯联邦政府)— 俄罗斯政府服务
Gosuslugi 出现在这份列表中并非偶然——MAX 集成了通过统一身份识别和认证系统 (ESIA) 进行身份验证的功能(更多内容将在后续文章中介绍)。然而,此次检查并非针对身份验证,而是针对基本的网络访问性 :您的设备是否可以访问gosuslugi.ru?检查结果(简单的“是”或“否”)将与 VPN 标志和 IP 地址一起发送到服务器。
为什么?综合所有答案,VK才能了解全貌:
- 公共服务可用 + 无需 VPN + 俄罗斯运营商 = 俄罗斯普通用户
- 政府服务不可用 + 使用 VPN + 俄罗斯运营商 =用户绕过封锁
- 公共服务不可用 ,但其他国外服务可用 + 无 VPN + 未知运营商 =用户绕过封锁 + 用户绕过 VPN 验证
3. VPN检测:MAX能够识别并报告
MAX 通过标准的 Android API 检测 VPN。它适用于任何 VPN——NordVPN、WireGuard、OpenVPN Enterprise 以及内置 VPN。
接下来会发生什么: 每次您打开应用时,您的 VPN 状态、IP 地址和其他数据都会被发送到 VK 服务器。这一点已通过代码分析和流量监控得到证实。VK 可以准确地知道您是否正在使用 VPN、何时使用以及使用的 IP 地址。
此外,代码中还发现了一个名为“无需 VPN 通话更佳”的小部件——该面板应在启用 VPN 的通话期间显示。该应用程序的资源包含俄语和英语字符串。我尚未在真机上动态复现此问题,但代码和资源确实存在。
4. 每次开业时填写完整的档案
每次打开 MAX(或应用程序在后台启动)时,它都会收集以下数据并将其发送到 VK 服务器:
- 您的 MAX 账户 ID (OK.ru ID) - 来自您的账户
- 会话 ID - 来自应用程序
- 授权密钥 - 来自 HTTP 请求
- 外部 IP 地址 - 通过 6 种 IP 服务之一
- 移动运营商 - 来自 SIM 卡(例如“MTS”)
- 连接类型 :WiFi / 4G / 5G
- VPN 是否已启用? — 通过系统 API
- 5 项服务的可用性 - 通过网络检查
- 时间 - 系统时钟
这是发送到服务器的数据包的样子(根据代码重建):
用户: #123456789(账户 MAX)
时间: 2026年4月12日 14:30:00
IP地址: 185.xxx.xxx.xxx
VPN: 是
运营商: MTS
连接方式: WiFi
服务: gosuslugi.ru — 是,Google — 是,API MAX — 是,CDN 调用 — 是,推送 — 是
这不是匿名分析。每条帖子都与您的帐户唯一关联 。由于 VK 集团拥有OK.ru、VK.com和Mail.ru,您的 MAX 帐户与您的 VKontakte 个人资料、电子邮件和其他生态系统服务相关联。
规模
MAX拥有1.07亿注册用户 和7700万日活跃用户 (VK数据,2026年3月)。从2025年9月起,该应用将预装 在俄罗斯和白俄罗斯销售的所有安卓设备上。
想象一下:每天有7700万人打开MAX浏览器。每次打开时,他们都会收到一个包含其IP地址、VPN状态和运营商信息的数据包。这相当于每天数千万个数据点 :谁在使用VPN,谁没有使用,使用哪个IP地址,通过哪个运营商,以及被屏蔽的服务是否可用。所有信息都是实时生成的。
这不仅仅是“单一应用分析”,而是一个全国性的网络环境监控基础设施。随着俄罗斯联邦通信、信息技术和大众传媒监管局(Roskomnadzor)实施新的网络封锁,HOST_REACHABILITY 数据变得更有价值——它能显示 封锁是否有效 以及哪些攻击者绕过了封锁。
5. 代码中的 Telegram 和 WhatsApp 域名
存储活跃服务地址的同一个文件也包含竞争对手的域名:main.telegram.org和mmg.whatsapp.net。
当前版本中未使用它们。
我并不是说 Telegram 的可用性检查器“可以立即启用”。但竞争对手的域名与正在运行的数据收集系统存储在同一个文件中,这一事实值得注意。
此外,MAX 会检查您的设备上是否安装了 Telegram,方法是搜索三个应用版本:主应用、测试版应用和网页版。官方说法是,这是为了检测“分享”按钮(Telegram 排在第一位)。
详细信息请见下方技术部分。
6. 服务器控制一切
整个追踪系统通过 VK 的推送管理系统 (PMS)由一个服务器标志 控制。这类似于远程配置,但功能更强大:PMS 值通过持久的 TCP 连接传输并立即生效。
实际意义如下:
- VK 可以通过单个交换机为所有用户 启用IP 地址收集功能。
- 可以针对特定用户 启用(定向跟踪)
- 可针对特定群体 启用(A/B 测试、特定操作员、特定地区)
- 可以在检查之前禁用 (例如,在 Google Play 审核之前)
- 这一切都无需更新应用程序。
该功能甚至还有一个专用的线程池 ,名为“主机可达性”。这不是附加的分析功能——它是一个独立的子系统,被设计成一个单独的组件。
还有一点:数据永不丢失 。如果发送失败,请求会重试三次。如果三次尝试后仍然失败,数据会保存到本地存储,稍后再发送。当应用最小化时,所有累积的事件都会被强制清除。VK 设计此功能是为了确保100% 收集到的数据 都能被检索到。
7. 法律现实
我不会猜测VK是否与情报机构共享这些数据。相反,以下是事实。
VK/MAX 是根据联邦第 149 号法律注册的“信息传播组织者”。根据《亚罗瓦亚法》(联邦第 374 号法律),VK/MAX 必须存储通信元数据一年,并应要求提供。必须存储的元数据包括 IP 地址、用户 ID、时间戳和 VPN 状态。联邦第 276 号法律(2024 年修订版)加大了对使用 VPN 绕过封锁的处罚力度,而 HOST_REACHABILITY 可以提供 VPN 使用者、使用时间和使用地点的精确证据。
但是,根据联邦法律第152号,IP地址被视为个人数据。收集此类信息无需征得 用户的同意。
重要提示: 我并非指责 VK 滥用这些数据。我只是指出,其代码会收集这些数据,法律要求必须存储和共享这些数据,而用户却无法选择退出。最终结论由您自行判断。
第二部分:证据(供想要核实的人参考)
以下是反编译后的 APK 的具体代码。所有文件和字符串引用均来自 JADX 反汇编器,APK 版本为 26.12.1。
2.1 URL 的隐藏方式:通过 int 进行混淆
文件: defpackage/ f28.java:43
以下是地址https://ip.mail.ru/在 MAX 代码中的显示方式:
// f28.java:53 x = new int {104, 116, 116, 112, 115, 58, 47, 47, 105, 112, 46, 109, 97, 105, 108, 46, 114, 117, 47};
手动解码:
104 → h 116 → t 116 → t 112 → p 115 → s 58 → : 47 → / 47 → / 105 → i 112 → p 46 → . 109 → m 97 → a 105 → i 108 → l 46 → . 114 → r 117 → u 47 → /
f28.java中的所有 16 个 URL都采用这种编码方式。解码由rd4.java延迟执行(IP 服务使用第 17-22 个用例,检查使用第 12-16 个用例)。
这并非代码压缩或优化。ProGuard 会混淆类名和方法名,但不会将字符串字面量转换为整数数组。这是开发者手动完成的工作 ,旨在使 URL 对静态分析工具(例如 grep、strings、jadx string search)不可见。
2.2 IP 地址收集:w18.java
文件: defpackage/w18.java:139-140
// 将所有 6 个 IP 服务收集到一个列表中
列表 o1 = rz3.o1(sz3.U(
f28.o.getValue(), // Yandex IPv4
f28.q.getValue(), // Yandex IPv6
f28.s.getValue(), // ifconfig.me
f28.u.getValue(), // api.ipify.org
f28.w.getValue(), // checkip.amazonaws.com
f28.y.getValue())); // ip.mail.ru
// 洗牌 - 每次都随机排序
Collections.shuffle(o1);
接下来,执行顺序搜索:第一个返回 IP 地址不等于 127.0.0.1 的服务获胜。其余服务不予查询。
关键点: 请求是通过 java.net.Socket + ByteArrayOutputStream(原始 TCP)发送的,而不是 OkHttp。OkHttp 是 Android 的标准 HTTP 库,很容易被代理(例如 Burp Suite、Charles、mitmproxy)拦截。原始套接字可以绕过所有这些限制。在设备上配置了代理的研究人员将无法 在标准工具中看到这些请求。
2.3 组装数据包:c28.java
文件: defpackage/c28.java:100-116
ro9 ro9Var = new ro9 ();
// 主机可用性检查结果:{hostname: true/false}
ro9Var.put(“hosts”, vibVar);
// 移动运营商:“25001:MTS”
ro9Var.put(“运算符”, str);
// 连接类型:WiFi (0) 或移动网络 (1)
ro9Var.put(“connection_type”, new Integer ( nc4Var.g() ? nc4Var.b().a : 1));
// 外部 IP 地址
如果 (str2 != null) {
ro9Var.put(“ip”, str2); }
// VPN标志
if (((nc4) b19Var.getValue()).e()) {
ro9Var.put(“vpn”, new Integer (1)); }
// 发送:类型 HOST_REACHABILITY,事件 GET_HOST_REACHABILITY
lg9.h(lg9Var, “HOST_REACHABILITY”, “GET_HOST_REACHABILITY”, ro9Var.b(), 8);
发送到服务器的重构 JSON:
{
“type”: “主机可达性”,
“事件”: “GET_HOST_REACHABILITY”,
“userId”: 123456789,
“sessionId”: 987654321,
“时间”:1712847600000,
“params”: {
“hosts”: {
" api.oneme.ru ": true,
" gstatic.com ":true,
" calls.okcdn.ru ": true,
" gosuslugi.ru ":true,
" mtalk.google.com ":真
},
“操作员”: “25001:MTS”,
“connection_type”: 0,
“ip”: " 185.xxx.xxx.xxx ",
“vpn”:1
}
}
目标地址: api.ok.ru/api/log/externalLog(POST,gzip,通过 session_key 进行身份验证)。
2.4 保证送达
文件: defpackage/lg9.java:49-103
发送 → 出错? → 重试 1 → 出错? → 重试 2 → 出错? → 重试 3 → 出错? → 保存到本地存储 (vgh) → 连接后稍后发送
最多重试 3 次(第 66 行:intValue() > 3)。3 次失败后,数据将保存到本地 vgh 存储(第 68-77 行)以便稍后发送。当应用程序最小化时,将强制刷新(r87.java:68)。
结果:无论网络 连接如何, 您的数据都会发送到 VK 服务器。没有网络?它会等待。服务器崩溃?它会重试。您关闭了应用?下次启动应用时,数据将会发送。系统设计确保不会丢失任何事件 。
2.5 “使用 VPN 更佳”小部件和 VPN 事件分析
文件: one/me/calls/ui/ui/call/panels/ VpnPanelWidget.java,defpackage/ dy1.java:46
// dy1.java:46 — 通话期间检测到 VPN
VpnPanelWidget widget = new VpnPanelWidget ();
// 已使用“call_vpn_panel_widget_tag”标签添加到用户界面
VPN 通知状态
文件: defpackage/ l4j.java
l4j.a // 已启用 — VPN 已启用
l4j.b // 已禁用 — VPN 已禁用
l4j.c // USER_IGNORED — 用户关闭了警告
l4j.d // 未知 — 无法确定
显示横幅时的分析事件:类型为 VPN 的 BAD_CONNECTION_ALERT(m82.java:43。
2.6 非活跃 Telegram 和 WhatsApp 可用性检查
文件: defpackage/ rd4.java:87
case 15: return hb0.a(f28.l); // main.telegram.org
案例 16:返回 hb0.a(f28.m); // mmg.whatsapp.net
文件: defpackage/ c28.java:150 —活动 检查列表:
列表 U = sz3.U(
" api.oneme.ru ",
(String) f28.b.getValue(), // gstatic.com
(String) f28.f.getValue(), // calls.okcdn.ru
(字符串)f28.h.getValue(),// gosuslugi.ru
(String) f28.d.getValue()); // mtalk.google.com
f28.l(Telegram)和 f28.m(WhatsApp)存在于rd4.java解码器中,但不在c28.java 的活动列表中。此外,在 smali 字节码层面,这些字段没有对应的 move-result-object / sput-object——解码结果会被丢弃。这部分代码是无效的,或者说是一个存根,不提供任何实际功能 。
f28 中也存在不活跃的华为推送域名:
2.7 当它有效时
主要触发条件: 每次应用切换到前台时(您打开或返回 MAX 时):
r87.java:82 → 应用程序前台回调
→ 检查 PMS 标志(e28.java:142-146)
→ 如果已启用且没有活动检查
→ 启动 c28(完整流程)
此外: 登录时(AccountInitializer),后台唤醒时(one.me.background.wake.HostReachabilityChecker)。
甚至在授权之前: y18.java:66-100 中的代码表明,网络检查会根据会话状态(未连接/已连接/已登录)以不同的模式运行。网络指纹识别在用户登录之前 就开始了。
结论
MAX 是一款预装在超过 1 亿台设备上的应用程序,它具有一个系统,每次打开它时都会执行以下操作:
- 通过 6 项隐藏服务查找您的 IP 地址
- 确定 VPN 是否已启用
- 检查您的网络是否提供俄罗斯和国际服务。
- 将所有这些都链接到您的真实账户
- 保证数据传输到 VK 服务器——无损且可重复传输
该系统由服务器管理,无需更新应用程序即可为所有人、用户组或特定用户启用。服务地址经过特殊隐藏,请求路由绕过标准网络库。
我区分代码中的功能 和已确认的使用情况 。服务器端标志可能并非对所有人启用。但代码就在这里,请查看。
接下来会发生什么?
IP地址收集和VPN检测只是冰山一角。我在MAX代码中还发现了许多其他有趣的东西,计划在以后的文章中分享。
请在评论区写下您希望首先分析的内容。
技术参考
APK 版本: 26.12.1 (6679)开发者: OOO “COMMUNICATION PLATFORM” (VK Group, Moscow)方法: 反编译 APK 的静态分析 (JADX) SHA256: 47420c41b742e67daae85ee75e0aa76935736c7491bab9da942c012e2115ffa1
关于文件名的说明: APK 中的大多数类都使用 ProGuard 进行了混淆。您不会看到像HostReachabilityManager.java这样有意义的文件名,而是会看到f28.java、c28.java和w18.java等文件名。在 JADX 中,这些文件名会被放入 defpackage/ 目录(默认存放没有指定包名的类的目录)。这对于混淆后的代码来说是正常的。具有正常文件名的类(例如 VpnPanelWidget.java)会保留其原始路径。我在这里会指定它们的完整路径。
如果发现错误,请告诉我,我会改正。我注重的是准确性,而不是夸大其词。