(并非)奇怪的组合 – 三星的Rubin与数字健康
又一年夏天飞逝。假期、出庭(是的!)、授课(同样,是的!),当然还有今年的会议季(现在仍在进行中)。事情逐渐放缓,我终于有机会动笔写一些一直在研究的内容。如今,要找到时间静坐写作变得越来越困难。不过,我希望这个趋势能有所改变。
首先要谈的是三星。具体来说,是三星定制化服务(又名Rubin)和数字健康(DWB)。有不少人直接或通过工作联系我,询问关于这两者的问题以及它们表现出的一些奇怪行为——我认为“奇怪”可能是最好的形容。毕竟,这是三星,而在Android方面,他们喜欢以自己独特的方式行事。这让检验人员时刻保持警惕,也为Android增添了一些多样性。因为Android取证难道不正是缺乏多样性吗?
在测试过程中,我不得不应对三星的安全补丁级别和常规更新,这使得获取数据提取变得棘手和令人沮丧。有时我能获取到Rubin所需的关键材料,有时则不能。这完全取决于我进行提取时的情况。无论如何,S22手机得到了充分的“锻炼”。它运行的是Android 15(OneUI 7),并安装了2024年12月和2025年4月的SPL。我知道有一个7月的SPL,但由于手机已经让我很头疼,我选择维持现状。
如果你还没有读过三星DWB的实现,可以在这里阅读。如果你不熟悉三星Rubin,Cellebrite有一些资源,你都可以在这里找到。
这将是我迄今为止最短的帖子,但它很重要,因为它关系到可能被遗漏的数据。
锁定与解锁 – 相辅相成
标题已经说明了一切。如果检验人员遇到同时使用Rubin和DWB的手机,需要将这两项内容放在一起检查,才能最全面地了解设备上发生了什么。原因是,传统上由DWB保存的一条信息——设备解锁事件——在启用Rubin时会被转移到Rubin中。见图1。
图1. dwbCommon中没有一个解锁事件。
上图是dwbCommon.db中usageEvents表的一个摘录。截图覆盖的时间段本应有两次解锁事件(eventType=18),但却没有。为了再次确认,我手动检查了usageEvents表,发现根本没有eventType=18的值,这就引出了一个问题:手机怎么知道我在这段时间解锁了两次?事实证明,Rubin保存了这些数据。见图2。
图2. 屏幕解锁和锁定。
inferenceengine_logging.db中的screen_state_log表包含了设备解锁和锁定的信息。为了确定哪些记录代表哪个动作,需要结合使用列screen_state、user_present、use_keyguard和time(我用这个是因为我喜欢UTC时间)或time_string(事件发生时设备本地时间)。这个表还会告诉你屏幕何时被点亮。我观察到了以下组合:
- 解锁(生物识别或密码)
- screen_state = 1
- user_present = 1
- use_keyguard = 0
- 通过侧边按钮按下锁定
- screen_state = 0
- user_present = 0
- use_keyguard = 1
- 因达到屏幕超时阈值而锁定
- screen_state = 0
- user_present = 0
- use_keyguard = 0
- 屏幕点亮,但未发生解锁
- screen_state = 1
- user_present = 0
- use_keyguard = 1
再次强调,这些解锁事件并没有记录在dwbCommon.db(或其-WAL文件)中。然而有趣的是,一些锁定事件(eventType=17)被记录在了usageEvents(dwbCommon.db)中,但并非全部,而且它们与screen_state_log(inferenceengine_logging.db)中记录的动作时间大致相同。
这里还有一个额外的说明:即使用户关闭了Rubin,上述行为仍然适用。解锁事件仍然会记录到Rubin中,而不会出现在DWB里。
延迟写入与完成的启动
三星决定实现他们自己版本的DWB,这在谷歌的移动服务合同中是允许的。因此,他们在dwbCommon.db中实现并使用了一个名为Logging的表,顾名思义,它用于记录日志,其中几项内容从检验人员的角度来看可能很有用。第一项是设备启动。虽然我们一开始就能在usageEvents表中看到这个信息,但这次的探索让我们对什么才真正构成“启动”有了更清晰的认识。正是在这里,我发现了一些奇怪的行为。见图3和图4。
图3. 已完成的启动以及Logging表中的最后几条记录。
图4. usageEvents表中的最后几条记录。
图3和图4真正揭示了这种奇怪行为,因为我在测试期间多次遇到这种情况。图3是Logging表中的最后两条记录,有两条“BOOT_COMPLETED”条目。这些条目的有趣之处在于它们与usageEvents表中最后四条记录的关系:它们的时间戳比后者晚了12个多小时!这很有趣,因为这部手机上本应在8月4日发生并记录到usageEvents中的活动(包括两次启动动作)并没有出现在usageEvents中。然而,在几小时后进行了几次更多提取后,这些记录终于出现了。
我们这里遇到的是一个延迟写入的实例。我的意思是,使用数据在一段时间内既没有出现在主数据库中,也没有出现在相关的-WAL文件中。在测试中,我多次观察到这种行为,其他联系我的从业者也描述了相同的行为。我看到记录需要1小时到超过12小时的时间才能写入数据库或-WAL文件(我有几个实例中,记录出现花费了超过一天的时间)。我仔细检查了S22的提取数据,但找不到这些数据在最终被记录之前存放在何处。我最初怀疑是RAM,但重启设备似乎并没有强制写入。是什么触发了写入对我来说仍然是个谜,但检验人员应该知道,可能存在尚未写入的记录,特别是当他们检查Logging表并看到像图3中那样比usageEvents中最后一条记录时间晚很多的条目时。
这一发现也揭示了另一件事:Logging表中的“BOOT_COMPLETED”条目并不像看起来那么明确。在测试期间,S22重启了多次,但有时与BOOT_COMPLETED记录关联的时间戳远远晚于设备实际重启的时间。考虑这种情况:用户重启了手机,但没有立即解锁,而是让它放置了一段时间。最终,用户解锁手机以便开始使用。图5下面显示了一个例子。
图5. 两次重启。
上面有两次重启事件。第一次发生在2025-08-04 09:26(UTC -0400),但手机直到09:27(UTC -0400)才被解锁。第二次重启发生在2025-08-04 19:20(UTC -0400),但手机直到2025-08-05 08:29(UTC -0400)才被解锁。如上所示,BOOT_COMPLETED条目与手机首次解锁的时间相符。为了确认我在这里看到的情况,我查看了文件eRR.p(USERDATA/system/users/service/data/)。下面的图6显示了相关的时间段,对应的重启事件用各自的颜色编码标出。
图6. eRR.p中的重启事件。
那么发生了什么(或正在发生)?当S22在重启后首次被解锁时,在我输入PIN码后,屏幕显示了“Phone is starting…”。在此之前,手机处于BFU状态;它可以做一些事情,但并非全部。一旦我输入PIN码,手机“完成”了其启动过程并进入了AFU状态。看起来,就DWB而言,启动过程直到手机进入AFU状态才算完成。
注意,手机在上次提取过程中崩溃过,这解释了图6第292行中看到的KP事件(很可能是内核崩溃)。
没有Rubin?没问题。
到目前为止的讨论都围绕着Rubin和DWB共存于手机上的情况。但如果用户不使用Rubin呢?为了测试这一点,我重置了S22,但没有登录我的三星账户。我会提前说明,我仍然观察到记录以与之前相同的方式延迟写入数据库。然而,对于DWB,情况略有不同。见图7。
图7. 这看起来好多了。
在未启用Rubin的情况下,解锁事件(eventType=18)回到了usageEvents表中。并且和之前一样,设备启动记录(eventType=27)仍然指示的是启动/重启后手机首次被解锁的时间。图8显示了Logging表,其中一条BOOT_COMPLETED记录被高亮显示。注意它的时间与图7中看到的记录855(DEVICE_STARTUP)大致相同。
图8. BOOT_COMPLETED(无Rubin时)。
真快啊
虽然这是我最短的帖子……有史以来最短……但我认为单独强调这一点很重要。Rubin+DWB的配置不仅会引起问题,还可能导致取证工具遗漏重要的数据。这些是检验人员在过去五年中逐渐依赖的数据。此外,这种不立即写入记录的习惯可能会在并非所有数据都已写入时,给检验人员一种错误的安全感。记录可能正在等待写入而不可用(我仍然认为这些东西在磁盘上的某个地方——我会继续寻找),检验人员可能会因为数据缺失而得出错误的结论,因此了解这种行为的存在非常重要。