恶意软件

Midnight Mimosa:新手机里,谁在替你安装应用

Bitdefender 新披露的 Midnight Mimosa 研究发现,一批 Android 手机的预装系统组件能自行安装应用、授予权限,再把设备用于广告欺诈或住宅代理。组件已经获得系统信任,普通卸载和恢复出厂设置难以清除它,处理需要回到设备固件的来源。

浅暖纸手绘概念图:刚拆封的手机内部藏着安装机构,机主尚未使用,应用已经从底层进入设备。
文章导航

新手机还没有装过来路不明的应用,系统里却已经有程序能替机主安装下一批应用。Bitdefender 在 10 月 8 日公开、次日更新的 Midnight Mimosa 调查在一批低价、多品牌 Android 设备中追到了这样一条分发链:恶意组件预先进入固件,后来下载的模块借它的权限继续工作。报告覆盖的是一段长期活动,近期才公开这套技术分析。

最值得追问的是安装确认去了哪里。Android 原本会阻止普通应用悄悄替用户安装另一个应用,这次的组件却已经处在系统授予权限的位置。要理解机主为何没有收到询问,得先看清手机把谁当成了有权作决定的安装者。

1 一个叫“System”的应用,已经拿到了安装权

Bitdefender 分析的一个组件叫 com.android.system.lite,显示名称为 System。报告给出的清单及签名信息包含平台签名、android.uid.system 共享身份和持久运行声明。它携带的原生库再释放隐藏框架,加载后续模块。名称只是伪装,安装位置、签名、进程身份和实际授予的权限,才决定它能做什么。

平台签名是设备制造体系使用的签名身份。Android 官方文档把它定义为与平台包 android 使用相同或兼容证书的应用。这里的“平台”属于这台设备的系统,看到平台签名并不等于 Google 审核过程序的全部行为。

普通应用通常有自己的 Linux UID。共享 android.uid.system 则让组件使用系统身份运行,Android 的权限检查会因此走到不同分支。这个身份与 Linux 的 root 分开,仍受相应系统策略约束。报告列出的系统身份和特权,赋予了它安装与授权的能力。

这些权限在 Android 中有明确分类。固定 Android 13 提交 0d3ff311e6e8 的 core/res/AndroidManifest.xml 第 4570–4573 行把 INSTALL_PACKAGES 定义为签名或特权权限,普通应用发起安装所用的请求权限与它不同。设备在交付时把这种能力授予某个组件,机主后来选择只从商店下载应用,也无法撤回这项既有授权。

2 安装确认,是在哪个分支被省掉的

Android 13 的参考实现可以把这个过程讲得很具体。对于尚未获得用户批准的新安装会话,PackageInstallerSession.java 的 computeUserActionRequirement(),第 809–889 行检查本次安装有没有被明确要求展示确认。如果有,就返回需要用户操作。否则,它继续查询安装者的权限及身份。已经手动批准的会话在函数开头便会返回无需再次询问。

持有 INSTALL_PACKAGES,或以系统、root 等受信任身份安装的调用者,可以进入无需用户操作的分支。正常的系统更新、设备管理和应用分发需要这类能力,预装恶意组件也能沿同一套机制使用它。后面的安装流程根据这个返回值决定是否请求用户确认,见同文件第 2073–2114 行。返回无需用户操作时,安装便可继续,机主不会看到确认提示。

普通应用发起新安装时等待用户确认,受信任的系统安装者可进入无需确认的分支。图中两条路径均限定于尚未批准的安装会话。
图 1:安装者的身份决定确认流程。图中展示 Android 13 参考实现里尚未批准的新安装会话,明确要求确认时仍会进入用户操作分支。查看原图。

安装之后还有权限授予。系统组件能够调用授权接口,后装应用便可能获得超出普通交互安装的能力。PermissionManagerServiceImpl.java 第 1313–1465 行先要求调用者拥有 GRANT_RUNTIME_PERMISSIONS,再检查目标包、声明的权限、权限类型和限制标记。运行时权限、开发权限及满足条件的角色权限,仍需通过这些检查才能授予。

WRITE_SECURE_SETTINGS 允许应用写入受保护的系统设置。它在同一固定版本的权限定义第 3751–3754 行带有 development 属性,授权函数对这类权限设有专门分支。报告中的天气应用 com.dmstudio.weather 已使用这项权限。解释它为何能写入,需要追到实际安装过程和授权者。只看天气应用自己的图标或商店描述,看不到这段来历。

3 后装应用在轮换,留下的是安装它们的组件

预装组件还把安装逻辑藏在了多层加载中。Bitdefender 记录的 libeasy.so 先解密释放 cn.kw.lib.hex 框架,框架读取远端配置,选取后续插件。插件把自带的 assets/mediaapp-release.apk 交给安装器,装入广告欺诈或住宅代理程序。只检查最外层 APK 的 Java 代码,会漏掉后来解密和下载的部分。服务端更换插件版本,送到同一台设备的应用也可以随之变化。

不断换应用也服务于赚钱的过程。系统进程中的广告插件安排展示时机、自动触发点击,再把事件上报。天气、笔记或 OCR 等掩护应用携带合法广告 SDK 和广告位标识,广告平台便把这些展示与点击记到掩护应用名下。操纵交互的程序藏在系统里,拿到广告收入的却是外观普通的工具应用。更换插件和掩护应用,仍能继续这条获利链。

住宅代理让别人的流量通过手机的网络进出,目的服务看到的连接来自这台手机。它与拿到系统安装权限属于不同能力,普通联网权限就可能支持一段代理程序工作。因此,需要分别调查谁把程序放进来,以及程序在网络上做了什么,不能因为后装程序没有系统 UID 就忽略它。

这套分工让清理变得困难。用户能看见的应用可以不断变化,保留在系统里的安装者仍能送来下一份程序。把某一个后装应用移除,只处理了当时能看见的那一层。

基础设施也需要按最新证据解释。原报告把 85.17.70.38:6000 写成在线控制端,随后加了勘误,确认该地址是研究用的 sinkhole,亦即接收恶意程序连接的受控汇聚点。表尾仍留有旧标签。查到这个地址时,应保留连接时间和样本关系,再采用勘误后的角色判断,避免把研究基础设施重新写成正在指挥攻击的服务器。

安装来源字段同样有可能误导判断。Android 13 的 PackageInstallerService.java 第 642–665 行允许持有安装特权的调用者指定另一个安装者名称。报告也记录了这种来源伪装。看到字段写着 com.android.vending,还需要核对实际安装事件、调用者及包签名,才能判断这个 APK 经历了怎样的分发过程。

4 恢复出厂设置,为什么可能留下它

出厂设置这个名字很容易让人想到一台干净的手机。恢复出厂设置通常清掉用户数据,保留当前安装的系统。经历过系统更新的手机也不会因此自动回到购机时的固件。如果恶意组件仍在当前系统镜像里,清掉数据就会把它留下。

Android 13 的参考恢复程序把这个区别写在代码里。固定提交 d0ab6ef7da71 的 install/wipe_data.cpp,WipeData() 第 81–108 行清理 /data,并按设备分区情况清理 /cache 和 /metadata,前后还调用设备钩子。这段通用流程没有重新安装 /system。具体厂商可以定制恢复程序,处理受影响设备仍须取得该型号可信的固件和明确清理办法。

启动验签也需要放回它的职责中看。Verified Boot沿硬件信任根验证引导及系统等分区的完整性和来源。当包含有害组件的镜像已经被设备信任的签名批准,启动链可以正常接受它。验签通过回答了软件是否符合既定信任来源,软件内部行为仍需要审查。

新版 Android 对部分平台签名应用增加了限制,也有明确适用范围。从 Android 15 起,官方的共享 UID 白名单在不可调试的生产构建中限制平台签名非系统应用加入共享身份,预装系统应用不受这项变化影响。签名权限白名单也主要约束这类非系统应用,但系统应用更新时新增请求的权限仍需要列入白名单。原有预装组件及原先请求的权限保持各自的规则,单凭“系统版本更高”判断已清除此类组件,会漏掉安装位置和固件内容。

5 清理要从可信固件开始

面对已经确认的预装感染,普通机主最需要的是设备厂商或销售方给出可核准的清洁固件和处理方案。Bitdefender 在 10 月 12 日的厂商说明也建议暂缓在可疑设备上使用重要账户,确认无法常规清除时联系销售方,考虑更换或退款。随意找一份第三方刷机包,会把尚未解决的来源问题换成另一个来源问题。

企业持有设备时,可以先保留固件版本、包路径、签名证书、UID、安装及联网记录,把预装组件与后装载荷分开确认。包名、设备型号和证书中的公司名称都只提供线索。报告还明确保留了供应链归属的未知:有证书标记,仍缺少证据确定是哪一环把组件放进固件。调查应沿实际设备和镜像继续,不能把芯片品牌、伪装的旗舰型号或证书署名直接变成责任结论。

这件事改变了一个很实际的使用前提。用户愿意逐次决定安装什么,手机却可能在交付前就把决定权交给了恶意程序。清理需要移除这个组件,关闭它持续安装后续应用的能力,正常系统安装器仍应保留。