样本与分析范围

原作者分析的是 Fake Location 国内版 1.5.2 (1702),样本来自项目公开发布渠道。上游 GitHub Release 显示,该版本于 2026 年 8 月 19 日发布,APK 资产名为 FakeLocation_CN_v1.5.2_1702.apk。

  • APK SHA-256(原作者提供):5d2a2bad585e3d50c38621a002bcf7a8e0dcf5448fc045f58619fe7a491eaea1
  • APK 签名主体(原作者提供):CN=Lerist., OU=览一科技, O=成都览一科技有限公司, L=chengdu, ST=sichuan, C=CN
  • APK 签名 SHA-256(原作者提供):B5:5E:7F:6C:CB:63:31:8B:2C:C4:D3:C4:5E:6B:14:81:31:06:1A:2A:CD:0A:82:72:5F:E5:9E:11:8D:1D:DA:FC
  • 上游发布页:https://github.com/Lerist/FakeLocation/releases/tag/1.5.2

原作者使用 Codex CLI、Claude Code、Jadx、Frida、IDA Pro 和 baksmali 完成静态分析,并称后期进行了人工逆向复核。本文按其证据链整理;我没有下载、运行或动态调试该 APK,因此不能把下述结果表述为独立复现结论。

脱壳与定位方法

Jadx 直接反编译 APK 时只看到 4 个壳引导类。入口 com/lerist/app/FLApp 会在 attachBaseContext 中加载 native 库;实际代码位于 assets/yaqgdtadv.dat,运行时由 libyaqcore_gdtadv.so 解密。原作者据此判断该版本使用了腾讯乐固。

随后通过 frida-dex-dump 获取运行时 DEX,共得到 101 个 DEX 文件。对这些文件同时使用 Jadx 和 baksmali 检查后,关键逻辑被定位在 classes09.dex。实用的复核入口是:

  1. 在反编译后的 Java 中搜索业务码 10000。
  2. 在 Smali 中搜索其十六进制值 0x2710。
  3. 检查 C2776.AbstractC2778.m9064 与 C2776.m9060 的响应处理路径。
  4. 继续跟踪 z41.m5033、z41.m5039 及其调用方。

特殊业务码分支

原作者还原出的核心响应逻辑如下:

int code = envelope.getCode();
String message = envelope.getMessage();
if (code == 10000 && !TextUtils.isEmpty(message)) {
    z41.m5033(true, message);
    z41.m5033(false, message);
}
callback.onError(envelope.getCode(), String.valueOf(envelope.getMessage()));

信封类的成功判断仅接受业务码 200:

public boolean isSuccess() {
    return this.code == 200;
}

因此,HTTP 层失败不会进入该特殊分支;业务码 200 走普通成功回调;其他业务码走错误回调,而 10000 会在常规错误处理之前额外调用两次 z41.m5033。

命令执行器证据

z41.m5033 只是 m5039 的包装:

public static C0855 m5033(boolean z, String... strArr) {
    return m5039(strArr, z, true);
}

Jadx 无法完整反编译 m5039,原作者转而检查 Smali。关键指令显示:

  • 布尔参数为真时执行静态字段指定的 su 或 suu;为假时执行 sh。
  • 把传入字符串原样写入子进程标准输入,每条后追加换行并刷新。
  • 最后写入 exit\n,读取标准输出和标准错误,等待进程结束并销毁进程。

相关字段与检查逻辑表明默认使用 su,找不到时还会尝试 suu:

public static String f6973 = "su";

if (which("su") fails && find("su") == null) {
    if (which("suu") fails && find("suu") == null) return false;
    f6973 = "suu";
}

在原作者展示的调用点中,服务器响应里的 message 会直接作为命令字符串传给执行器;没有看到命令白名单、参数转义或固定操作映射。先尝试 root shell,再尝试普通 shell,意味着只要该分支被触发,命令会在设备可用的权限范围内执行。

原作者还在同一类中找到一个通过拼接 kill -9 <pid> 后调用 m5033(false, ...) 来终止当前进程的方法。这从侧面证明 m5033 确实是通用 Shell 命令执行器,而非只处理某个固定业务动作的函数。

触发路径与轮询

原作者继续追踪到应用自己的配置请求路径:

C1619.m6836(Context)
  -> C1619.m6838()
  -> 构造 C1959 请求体
  -> C2776.m9059().m9061(...)
  -> Retrofit.create(InterfaceC4521.class)
  -> POST app/getAppConfigs
  -> enqueue(new C1624())
  -> 继承自 AbstractC2778 的 m9064(...) 处理响应

静态分析显示,应用初始化时会请求 app/getAppConfigs,成功后约每 252,000,000 毫秒(约 70 小时)再次执行。用户登录后还会以 604,800,000 毫秒(7 天)为间隔轮询 user/get;该接口使用包含同一特殊分支的静态处理器 C2776.m9060。

这说明代码不是孤立的未引用片段:至少两条正常运行路径可以到达包含 code=10000 分支的处理器。它证明的是“存在可达的远程命令执行通道”,并不等同于证明服务端历史上实际下发过该业务码。

网络端点与代码归属

原作者通过检查 C2776、网络层父类以及异或解码函数,得到两个 base URL:

  • 主地址:https://api.fakeloc.cc:4430/FakeLocation/
  • 备用地址:https://fakelocation.api.lerist.dev:4430/FakeLocation/

其归属判断基于以下链条:

  • C2776 处理 Fake Location 自己的 app/getAppConfigs 接口。
  • 回调类 C1624 处理 isAllowRun、地图密钥等应用核心配置。
  • 上层代码引用 com.lerist.lib.factory.utils.LOverrideActivity,位于应用自身命名空间。
  • 相关类具有同一份 R8 混淆结果的共同特征。
  • 两个 base URL 都属于 Fake Location 使用的域名。

项目的 GitHub Release 公开存在 1.5.2 及对应 APK,但上游仓库不含这一闭源 APK 的可审计源码,因此这些反编译结论仍需对指定哈希的二进制样本复核。

TLS 风险补充

原作者称,在复核中还发现 HTTP 客户端使用了恒返回 true 的 HostnameVerifier。若这一点准确,TLS 证书链验证仍可能存在,但主机名匹配会被跳过。其安全含义是:风险不必局限于后端主动返回特殊业务码;在满足证书信任等额外条件时,中间人也可能有机会伪造响应。

原作者尝试抓取生产 API 流量,但因双向 TLS 验证导致代理替换证书后握手失败,最终没有完成动态抓包。因此,TLS 配置、实际响应格式和服务端是否下发过 code=10000 均没有通过动态网络证据确认。

已证明与未证明的边界

根据原帖提供的静态证据,可以较有把握地复核:

  • 指定版本内存在对业务码 10000 的特殊处理。
  • 响应 message 会进入支持 su/suu 和 sh 的通用命令执行器。
  • app/getAppConfigs 与 user/get 两条正常请求路径可到达相关处理器。
  • 代码使用应用自身接口、命名空间和域名,而非仅存在于一个无关第三方 SDK 中。

原帖没有证明:

  • 服务端是否曾在真实环境返回过 code=10000。
  • 该通道是否已经被用于执行命令或造成实际入侵。
  • 所有 API 是否都会经过同一处理器。
  • 开发者设计该机制的主观目的。
  • 新版本是否已经移除或改变相关逻辑。

讨论区也有人指出,本次工作主要是静态分析,没有完成动态调试和抓包。原作者确认了这一局限,并明确表示无法证明该机制是否实际使用过。因此,“存在高危、可达的远程命令执行能力”与“已经发生恶意利用”必须分开表述。

防护建议

对正在使用该版本且在意风险的用户,原作者建议:

  1. 停止使用并卸载应用。
  2. 在 superuser 管理器中撤销残留的 root 授权。
  3. 如果曾以 root 模式运行并把 SELinux 设为 permissive,检查陌生应用、系统文件异常修改和可疑网络连接。
  4. 在开发者公开回应或独立审计确认后续版本移除相关逻辑前,不继续授予高权限。
  5. 做复核时先核对 APK 与签名哈希,避免分析到不同样本;优先在隔离测试设备中进行,不在主力手机上执行未知二进制。

原作者:bluefunny(BlueFunny)
原帖:https://linux.do/t/topic/2847507