安卓取证学习指南(二)
原文:
annas-archive.org/md5/e5389ef3843690d1ee144f281791135b译者:飞龙
第五章:从 Android 设备中物理提取数据
本章将介绍物理数据提取,尽可能使用免费和开源工具。本章中大多数内容将使用我们之前在本书中讨论的Android 调试桥(ADB)方法。到本章结束时,读者应熟悉以下内容:
-
物理提取意味着什么
-
使用
dd、nanddump和 Magnet ACQUIRE 进行物理数据提取 -
RAM 成像和分析
-
SD 卡数据获取
-
JTAG 和芯片拆卸方法
物理提取概述
在数字取证中,物理提取是电子媒体的精确位对位镜像,这一定义同样适用于移动设备。在传统计算机取证中,这通常涉及从嫌疑人的计算机中取出证据硬盘,并通过写保护器进行成像,而不启动该硬盘,从而得到一个包含嫌疑人硬盘精确副本的镜像文件。输出通常称为原始镜像,或简而言之是二进制(.bin)文件。物理提取与逻辑提取的区别在于,物理提取是设备内存的精确副本,包括未分配的空间、文件空白、卷空白等。
在移动取证中,结果是相同的——设备的精确位对位镜像——但方法略有不同。例如,将闪存从设备中拆卸下来进行成像既费时又昂贵,而且需要大量专业知识(尽管这可以做到,正如本章后面的芯片拆卸部分所讨论的那样)。此外,除非使用先进的 JTAG 或芯片拆卸方法,否则设备必须至少启动一定程度(并且在许多情况下写入)才能访问数据。最后,找到一个可以解析最终镜像文件的工具可能非常困难。硬盘镜像和文件系统早已被文档化和研究,而移动镜像和文件系统则经常变化;在某些情况下,移动文件系统甚至是特定厂商独有的。知道获取镜像后该怎么处理,可能和获取镜像本身一样具有挑战性!
在第四章中讨论的许多技术,从 Android 设备中逻辑提取数据,在这里仍然适用:启动自定义恢复模式仍然是最符合取证要求的过程;如果可能的话,应避免物理获取一个活跃的设备。
可以通过物理方式获取哪些数据?
简短的回答是:一切。由于物理采集是设备的精确映像,设备上的每一比特数据都会出现在映像文件中。如前所述,在物理提取中,检查员通常仅受限于他们找到相关数据的能力。通常,这是因为移动取证领域缺乏良好的映像分析工具。更糟糕的是,应用程序已知会对用户数据进行编码或其他形式的混淆,因此仅仅通过十六进制编辑器浏览映像往往会错过宝贵的证据。本章将介绍各种挂载或以其他方式查看物理提取文件系统的方法,而第七章《安卓应用程序取证分析》将专注于分析来自特定应用程序的数据。
Root 权限
再次强调,就像逻辑提取一样,root 权限在物理提取中也至关重要。为了手动创建设备映像,我们必须通过 ADB shell 在设备上执行命令,而这些命令需要 root 权限。如果无法获得 root 权限,SD 卡通常仍然可以创建映像。除此之外的唯一备选方法是 JTAG 或芯片拆除方法。
使用dd命令提取物理数据
dd命令对于任何做过传统硬盘取证的检查员来说应该都很熟悉。dd是一个 Linux 命令行工具,定义上用于转换和复制文件,但在取证中常常用于创建整个硬盘的逐比特映像。dd有很多变种,如dcfldd、dc3dd、ddrescue和dccidd,这些工具在实际操作中也很常见。由于dd是为 Linux 系统设计的,它经常包含在 Android 平台中。这意味着,创建设备映像的方法往往已经存在于设备上!
dd命令有许多可设置的选项;以下列表中仅涵盖与取证相关的重要选项。可以在man7.org/linux/man-pages/man1/dd.1.html查看完整的命令选项列表。dd命令的格式如下:
dd if=/dev/block/mmcblk0 of=/sdcard/blk0.img bs=4096 conv=notrunc,noerror,sync
让我们定义dd命令的前述格式:
-
if:指定输入文件的路径。 -
of:指定输出文件的路径。 -
bs:块大小。数据按指定的块大小读取和写入,如果未指定,则默认大小为 512 字节。 -
conv:转换选项:-
notrunc:不截断输出文件。 -
noerror:遇到错误时继续生成映像。 -
sync:与 no error 配合使用时,对于发生错误的块,它会写入\x00。这对于保持映像中的文件偏移量非常重要。
-
不要混淆if和of标志,因为这可能会导致覆盖目标设备!
请注意,bs、noerror和sync标志之间有一个重要的关系:如果遇到错误,将会为读取到的整个块写入\x00(这由块大小决定)。因此,较小的块大小会在发生错误时减少丢失的数据。缺点是,通常较小的块大小会导致较慢的传输速率。检查员需要根据是否优先考虑及时性或更准确的获取来做出决定。
如前一章所述,进入恢复模式进行成像处理是最具法医证据效力的方法。
确定要成像的内容
在对计算机进行成像时,检查员首先必须确定磁盘的挂载位置,例如/dev/sda。对 Android 设备的成像也是如此。第一步是启动 ADB shell,并通过以下命令查看/proc/partitions文件:
cat /proc/partitions
输出将显示设备上的所有分区:
在之前的输出中,mmcblk0是设备上整个闪存的代表。为了提取整个闪存的镜像,我们可以使用/dev/blk/mmcblk0作为dd命令的输入文件标志(if)。接下来的内容,由 p1-24 表示,是闪存的各个分区。每个分区的大小以块为单位显示。在本例中,块大小为 1,024 字节,总内存大小约为 16 GB。为了获取设备内部存储的完整镜像,我们需要运行dd命令,并将mmcblk0作为输入文件。
当然,我们并不关心设备上的每个分区,因为大多数分区几乎不包含任何相关信息。正如你所知道的,最感兴趣的部分是/data分区。通常它是最大的,所以它可能是mmcblk0p24,即 11,784,192 个块。让我们通过运行df命令来了解更多关于它的信息:
从前面的截图中可以看到,我们的判断是正确的——mmcblk0p24就是 userdata 分区。
写入 SD 卡
dd的输出文件可以写入设备的 SD 卡。只有在嫌疑人的 SD 卡可以移除并替换为法医无菌 SD 卡的情况下,才应进行此操作。这样可以确保dd输出不会覆盖证据。显然,如果你正在写入 SD 卡,确保 SD 卡的容量大于要成像的分区。
在较新的设备中,/sdcard分区实际上是一个指向/storage/self/primary的符号链接。在这种情况下,使用dd将/data分区复制到 SD 卡上是行不通的,且可能会损坏设备,因为输入文件实际上会被写入到自身。
让我们看看在/storage下还可以找到什么:
如你所见,我们还找到了6264-3264和emulated子目录。那么我们的 SD 卡挂载在哪里呢?我们来运行mount命令:
我们正在使用 128 GB 的 SD 卡,因此它必须安装在 6264-3264 下。现在我们已准备好开始镜像 /data 分区的过程:
现在,在 SD 卡上存在 /data 分区的镜像。可以使用 adb pull 将其拉取到检查人员的机器上,或者直接从 SD 卡中读取。
直接使用 netcat 将数据写入检查人员的计算机
如果无法将镜像写入 SD 卡,检查人员可以使用 netcat 将镜像直接写入其计算机。netcat 是用于通过网络连接传输数据的 Linux 工具。建议在 Linux 或 macOS 计算机上使用 netcat,因为它是内置的,尽管 Windows 版本也存在。以下示例是在 SIFT 工作站(Linux Ubuntu)上执行的。
在设备上安装 netcat
在过去,几乎没有任何 Android 设备预装了 netcat。要检查,只需打开 ADB shell 并键入 nc。如果返回 nc 未找到,则必须手动在设备上安装 netcat。可以在许多在线资源中找到为 Android 编译的 netcat;例如,github.com/MobileForensicsResearch/netcat。
如果我们回顾上一节中挂载命令的结果,可以看到 /dev 分区被挂载为 tmpfs。tmpfs 是 Linux 的一个术语,意味着该分区被视为设备上的实际文件系统,但实际上只存储在 RAM 中。这意味着我们可以在不对设备进行任何永久更改的情况下,将 netcat 推送到这里,使用以下命令在检查人员的计算机上进行操作:
adb push nc /dev/Examiner_Folder/nc
该命令应该在 /dev 中创建了 Examiner_Folder,并在其中放置了 nc。可以通过在 ADB shell 中运行以下命令来验证:
ls /dev/Examiner_Folder
在当前版本的安卓系统(从 Marshmallow 开始),Toybox ——一款免费且开源的软件,实现了一些 Unix 命令行实用程序,包括 netcat——已经预装,因此检查人员无需再次安装它。
使用 netcat
我们需要打开两个终端窗口,其中一个要打开 ADB shell。另一个用来监听从设备发送的数据。
现在,我们需要通过 ADB 在检查人员的计算机上启用端口转发:
adb forward tcp:9999 tcp:9999
9999 是我们选择用于 netcat 的端口;在 Linux 或 macOS 系统上,它可以是介于 1023 和 65535 之间的任意端口号(1023 及以下保留给系统进程,需要 root 权限才能使用)。Windows 则允许分配任何端口。
在具有 ADB shell 的终端窗口中运行以下命令:
dd if=/dev/block/mmcblk0p24 bs=1024 | toybox nc –l –p 9999
mmcblk0p24 是此设备上的 userdata 分区,但也可以使用此方法对整个闪存或其他任何分区进行镜像。在大多数情况下,最佳实践是对整个闪存进行镜像,以便获取设备中的所有可能数据。一些商业取证工具可能也要求整个内存镜像,并且可能无法正确处理单个分区的镜像。
在另一个终端窗口中,运行以下命令:
nc 127.0.0.1 9999 > userdata.dd
应该已经在检查员计算机的当前目录中创建了userdata.dd文件。当数据传输完成后,两个终端中的netcat将终止并返回命令提示符。这个过程可能需要相当长的时间,具体取决于镜像的大小。
使用 nanddump 物理提取数据
在我们迄今为止涵盖的所有示例中,分区都是 MMC 块,这通常出现在较新的设备中。然而,旧设备更有可能由内存技术设备(MTD)块组成。我们过去见过dd无法正确镜像 MTD 块的情况,尽管通常情况下它工作正常。如果dd失败,有一个广泛分发的工具叫做 MTD-Utils,用于读取和写入 MTD 块;nanddump是 MTD-Utils 的一部分,可以像dd一样用于从 MTD 块中读取。在dd失败的情况下,nanddump总是能够成功。
适用于 Android 的nanddump版本可以在许多地方找到;我们使用的是在此处找到的版本:github.com/jakev/android-binaries/blob/master/nanddump。
将nanddump放置到设备上的过程与之前使用netcat的方法相同:
adb push nanddump /dev/Examiner_Folder/nanddump
chmod +x /dev/Examiner_Folder/nanddump
就像dd一样,nanddump也可以通过netcat写入 SD 卡或检查员的计算机:
- 从终端窗口运行以下命令:
adb forward tcp:9999 tcp:9999
- 在 ADB Shell 中的另一个终端窗口中运行以下命令:
/dev/Examiner_Folder/nanddump /dev/block/mmcblk0p34 | /dev/Examiner_Folder/nc –l –p 9999
- 在第一个终端窗口中,使用
adb forward时,运行以下命令:
nc 127.0.0.1 9999 > data_partition.img
使用 Magnet ACQUIRE 物理提取数据
ACQUIRE 是 Magnet Forensics 提供的一款免费工具,可以用于获取各种潜在的数字证据来源,从硬盘和智能手机到云数据。当然,它支持对 Android 设备进行逻辑和物理提取,直到最新的运行 Android Pie 的设备。注册后可以在此处下载该工具:www.magnetforensics.com/magnet-acquire/。
在这个示例中,我们将对一部运行 Android Oreo 的 rooted 智能手机进行镜像:
- 从列表中选择合适的设备:
如您所见,我们的设备具有特权访问权限 — 这意味着它已 root。此外,我们立即获得了一些元数据,如操作系统版本、设备序列号等。如果因某种原因要镜像的设备未列出,可以使用“没有显示我要查找的设备”选项。这包含了关于如何使工具检测到它的逐步指南。
- 一旦选择了正确的设备,您可以选择镜像类型:
-
有两个选项:完整和快速。第一个是物理获取,不总是可用,而第二个是逻辑获取,适用于任何 Android 设备。由于我们的设备已 root,因此我们可以选择完整选项。
-
最后,选择文件夹和镜像名称,目标以及必要时填写其他字段:
- 单击获取按钮将启动获取过程。在我们的示例中,对 16 GB 存储的成像仅需 10 分钟。如果查看日志文件 (
activity_log.txt),您会注意到实际使用了相同的工具 —dd和toybox:
如您所见,使用 Magnet ACQUIRE 对 Android 设备进行影像的方式比使用 dd 和 netcat 要简单得多,但在底层,这个过程是相同的。有时,该工具甚至可以帮助您对非 root 设备进行物理获取,因为它包含多个能够获取临时特权访问权限的漏洞,以及可用于获取未加密设备完整镜像的 TWRP 自定义恢复。
验证完整的物理镜像
验证图像文件与设备相同是传统数字取证中的关键步骤。在 Android 设备上,这可能有点棘手,甚至不可能。可以使用检查人员通常使用的任何工具对已创建的图像进行哈希处理。通过 ADB shell 可以通过以下命令验证设备上的内存,其中给定的路径是已镜像的块或分区:
md5sum /dev/block/mmcblk0
然而,并非所有 Android 设备都包含 md5sum 命令。如果没有包含在内,鉴定人员可以尝试在网上找到适用于其设备的编译版本,并将其推送到设备的 tmpfs 分区中,就像之前展示的那样,使用 netcat 和 nanddump。
另一个问题是如果图像是在现场获取的,即不是在恢复模式下获取的,如前一章讨论的。可以几乎肯定地说,MD5 散列值将不匹配,因为设备上的数据不断变化(即使是 RF 屏蔽或处于飞行模式)。在这种情况下,鉴定人员必须记录设备在获取时处于活动状态,并解释散列值不匹配是预料之外的情况。
分析完整的物理镜像
一旦通过前面的方法获取了镜像,检查员可能会手动浏览镜像并提取每个分区,但通常会更倾向于避免这样做。幸运的是,有各种各样的移动取证工具可以处理物理镜像,例如 Cellebrite UFED、Oxygen Forensic、Magnet AXIOM、Belkasoft Evidence Center 等等。不幸的是,这些工具都不是免费的或开源的;目前最流行的免费开源分析工具是由 Basis Technology 开发的 Autopsy。
Autopsy
Sleuth Kit 最初是一套基于 Linux 的命令行工具,用于取证;后来,加入了一个名为 Autopsy 的基于浏览器的 GUI。最近,Autopsy 被作为独立平台在 Windows 上发布,并支持分析 Android 镜像。以下截图展示的是版本 4.9.0。加载和分析镜像的完整过程将在第八章中介绍,Android 取证工具概览。
可以从www.sleuthkit.org/autopsy/download.php下载 Autopsy。
图像加载完成后,展开图像会显示 Autopsy 找到的所有卷:
这些卷之一将是数据分区,如以下截图所示:
请注意,前面截图中的媒体目录就是 SD 卡,因为它与数据分区进行了符号链接。/data 分区中的 data 文件夹将包含应用程序数据:
每当安装一个应用程序时,系统会为其创建一个目录。
请注意,文件夹上显示红色 X 图标表示该文件夹已被删除,这意味着应用程序已从设备中移除。
最后,Autopsy 能够自动提取一些数据供检查员使用,但和所有取证工具一样,这些信息应手动验证。我们将在第七章中介绍,Android 应用程序的取证分析:
分析物理转储时的问题
我们在许多取证论坛和邮件列表上看到的最常见问题是,检查员获取了物理转储后,无法将其加载到声称支持该设备的工具中。绝大多数情况下,这是因为检查员没有考虑到带外(OOB)区域。
OOB 区域,有时称为备用区域,是闪存中的一小部分,专门保留用于元数据。元数据通常包含错误纠正码(ECC)、坏块信息,有时还包含文件系统信息。这对检查员来说是一个问题,因为大多数移动取证工具没有考虑 OOB 区域;它们假设图像中不包括此区域。当工具遇到包含备用区域的图像时,通常不知道该如何处理,导致无法正确解析数据。
工具无法考虑 OOB 区域的原因是,OOB 区域未包含在dd图像中,而大多数工具使用dd来创建图像。当使用nanddump时,OOB 区域可能会被包含在内,但根据使用的二进制文件,可能会有一个选项来排除它。OOB 区域通常会包含在芯片脱离和 JTAG 图像中。
为了正确地将图像加载到取证工具中,首先需要去除 OOB 区域。一个常见的经验法则是,OOB 大小基于设备的页面大小;每 512 字节的页面大小会有 16 字节的 OOB 空间。例如,一个页面大小为 2,048 字节的设备,可能会在每个页面的末尾有 64 字节的 OOB 区域。然而,这完全取决于内存制造商。在尝试移除 OOB 区域之前,检查员应该查找特定内存芯片的数据手册,以确认页面和 OOB 区域的大小。通常可以通过在手机的电路板上找到内存芯片,并搜索该芯片的型号来完成此操作。
以下是一个 Python 脚本示例代码,用于从图像中移除 OOB 区域。正如上一章所述,我们并不声称自己是 Python 专家,我们确信有更好、更高效的方法来实现这一点,但它确实有效:
import sys
file_to_parse = open(sys.argv[1],'rb')
file_after_removal = open('file_out.bin','wb')
while file_to_parse:
lines_out = file_to_parse.read(2048)
if lines_out:
file_after_removal.write(lines_out)
file_to_parse.seek(64,1)
if not lines_out:
break
print 'Done'
file_to_parse.close()
file_after_removal.close()
如果该文件名为OOB_Remover.py,则可以使用以下命令执行:
python OOB_Remover.py C:\Users\Android_Examiner\physicaldump.bin
输出文件将命名为file_out.bin,并存放在执行脚本的目录中,该文件不包含 OOB 区域。原始文件不会以任何方式进行编辑或修改。
请注意,代码的编写假设页面大小为 2,048 字节,OOB 大小为 64 字节;这两个数字需要根据图像所提取的内存芯片的具体大小进行编辑。之后,输出文件应该能够加载到商业移动取证工具中。
映像和分析 Android 内存
由于需要 root 权限,提取 Android 内存在许多情况下是不可行的。大多数公共 root 过程涉及重启手机,这会清除易失性 RAM,这意味着当检查员获得 root 权限以进行 RAM 成像时,已经太晚,因为 RAM 已经被清除。因此,由于这个原因,可能还有其他原因,商业取证领域对 Android RAM 成像和分析的支持并不强大。然而,也有一些情况可以使用 RAM 成像,并可能对案件至关重要。如果设备在被扣押时已经 root,那么 RAM 成像应该成为扣押过程中的必备步骤。由于关闭手机会清除 RAM,因此设备应该设置为飞行模式(并禁用所有其他网络连接,如 Wi-Fi 和蓝牙),并应立即对 RAM 进行成像,以避免设备电池耗尽前无法提取 RAM。
RAM 分析的主要挑战是数据处理。RAM 是完全原始的、无结构的数据;没有文件系统。当在十六进制编辑器中查看时,RAM 看起来只是一个巨大的数据块,几乎没有任何规律或提示来帮助检查员理解他们正在查看的内容。这个难度因现代设备通常有数 GB 的 RAM 而加剧。RAM 可以使用传统的取证工具和方法通过关键词进行搜索,但这要求检查员完全知道他们在寻找什么。
在 RAM 中可以找到什么?
任何写入闪存的数据都必须经过 RAM;处理器与闪存的通信只能通过 RAM 进行。这意味着,几乎所有在设备上进行的操作都可能出现在 RAM 转储的内容中。根据设备的使用情况,数据可能会在 RAM 中无限期存在,直到需要被覆盖。RAM 转储通常包含设备上输入的文本,包括用户名和密码,以及没有永久存储在设备上的应用数据。例如,Facebook 应用程序曾将用户新闻源的内容存储在其应用文件夹中的数据库里。新版本不再保存用户的新闻源,但它仍然存在于 RAM 中。
使用 LiME 对 RAM 进行成像
Android RAM 获取最常用的工具是Linux 内存提取器(LiME),之前称为 DMD。LiME 是免费的开源工具,但并不是非常用户友好,因为它要求用户从源代码编译,这只能在 Linux 系统上完成。编译过程还必须为每个被检查的设备的每个 Android 版本单独进行,这在一定程度上限制了它在实际应用中的可用性。这是必要的,因为 LiME 不是二进制工具(像我们之前使用的netcat和nanddump工具);相反,它是一个内核模块,必须为每个将要加载的内核专门编译。
为了确保正确的内核源代码被下载,我们需要确定设备的型号和软件版本,可以通过滚动手机菜单至设置 | 系统 | 关于手机来完成。或者,这些信息也可以通过在 ADB shell 中运行以下命令来获取:
cat /system/build.prop
型号的软件版本应该位于文件顶部的前几行。
幸运的是,大多数 Android 厂商都会发布他们的内核源代码;通过快速的 Google 搜索,通常可以找到每个型号和软件版本的源代码。以下是一些主要厂商的开源发布网站:
-
谷歌(Nexus 设备):
source.android.com/source/building-kernels.html
必须使用正确的型号和版本源。使用错误的内核源来编译 LiME 至少会导致设备无法运行。加载不兼容的内核模块也可能导致设备崩溃。
要获取 LiME 的源代码,请访问 github.com/504ensicsLabs/LiME,选择“Download ZIP”选项,然后解压 .zip 文件。
网上有许多优秀的资源解释了如何为特定内核编译 LiME,甚至如何创建自定义的 Volatility 插件来检查生成的 RAM 转储,因此这里不会重复介绍:
-
Linux 内存提取器:
github.com/504ensicsLabs/LiME/tree/master/docV -
波动性:
github.com/volatilityfoundation/volatility/wiki/Android
获取 Android SD 卡
如本章及之前章节所讨论的,SD 卡可以指物理的外部 SD 卡或闪存内的一个分区。可拆卸的外部 SD 卡可以通过写保护器与典型的计算机取证工具分开成像,或者使用之前展示的 dd/nanddump 技术进行成像,尽管前者通常由于不需要通过 netcat 写入数据而更快。
物理成像 SD 卡与我们之前讨论的物理成像非常相似;事实上,如果 SD 卡与 /data 分区符号链接,它将作为 /data 分区的一部分被获取,如 Autopsy 部分的截图所示。唯一的不同之处在于,如果正在对 SD 卡进行成像,输出文件不能写入到 SD 卡中!这意味着,使用我们之前讨论的 netcat 方法是进行内置 SD 卡物理成像的最佳选择。
SD 卡上可以找到什么?
默认情况下,SD 卡通常用于存储大文件,包括下载的内容和用设备拍摄的照片。许多应用程序还会在 SD 卡上创建自己的目录,用于存储通过聊天应用发送或接收的图像等数据。在某些情况下,正如在第八章《Android 取证工具概述》中所看到的,甚至有些应用程序会定期将所有数据备份到 SD 卡。这对取证检查员特别有用,因为他们可能无法访问内部存储器,原因可能是安全设置或无法获取 root 权限,但他们可能能够访问 SD 卡。
常见的 SD 卡位置包括但不限于以下内容:
-
/Alarms: 可能包含自定义闹钟 -
/Android/data: 一些应用程序数据的存储位置 -
/DCIM/Camera: 包括用设备相机拍摄的照片 -
/Download: 可能包含下载的文件 -
/Movies: 可能包含下载的视频文件 -
/Notifications: 可能包含自定义通知 -
/Pictures: 可能包含不同的图像,包括在设备上拍摄的截图 -
/Podcasts: 可能包含下载的播客 -
/Ringtones: 可能包含自定义铃声
即使应用程序已被删除,/Android/data 文件夹仍然可能存在。文件夹的内容将被删除,但文件夹可能会保留,这表明该应用程序之前曾安装在设备上。
这些只是常见的默认位置;如果设备已获取 root 权限,用户可以将任何内部存储的数据转移到 SD 卡上。
第六章:从 Android 设备恢复已删除的数据
本章将介绍数据恢复技术,使我们能够查看已从设备中删除的数据。已删除的数据可能包含高度敏感的信息,因此数据恢复是移动取证中的一个关键方面。
本章将涵盖以下主题:
-
数据恢复概述
-
从 SD 卡中恢复已删除的数据
-
从 SQLite 数据库中恢复数据
-
从手机内部存储中恢复删除的数据
-
使用文件雕刻恢复已删除的数据
数据恢复概述
数据恢复是数字取证中的一个强大概念。它是从设备或 SD 卡中检索已删除数据的过程,当这些数据无法正常访问时,恢复数据至关重要。能够恢复用户已删除的数据有助于解决民事或刑事案件。这是因为许多被告只是删除设备上的数据,希望证据被销毁。因此,在大多数刑事案件中,已删除的数据可能至关重要,因为它可能包含用户希望从 Android 设备中擦除的信息。例如,考虑一下从恐怖分子那里查获的手机。如果知道他们删除了哪些项目,岂不是最为重要吗?获取任何已删除的短信、图片、拨打的号码等信息可能至关重要,因为它们可能揭示大量敏感信息。
从普通用户的角度来看,恢复已删除的数据通常意味着参考操作系统内置的解决方案,比如 Windows 中的回收站。虽然从这些位置恢复数据是可能的,但由于用户意识的提高,这些选项往往不再有效。例如,现在人们在桌面计算机上使用Shift + Del来完全删除文件。同样,在移动环境中,用户知道应用程序提供的恢复操作等。尽管存在这些情况,数据恢复技术仍然使法医调查员能够访问已从设备中删除的数据。
就 Android 而言,可以恢复大部分已删除的数据,包括短信、图片、应用程序数据等。但重要的是要以正确的方式查封设备并遵循某些程序,否则数据可能会被永久删除。为确保已删除的数据不丢失,建议牢记以下几点:
-
查封手机后,切勿进行任何操作。已删除的短信仍存在于设备中,直到某些其他数据占用该空间,因此必须避免对手机进行任何操作,以防止数据被覆盖。
-
即使手机没有使用,且没有我们干预,数据仍然有可能被覆盖。例如,接收的短信会自动占用空间,从而覆盖已删除的数据。此外,远程清除命令也可以擦除设备上存在的内容。为了防止这种情况发生,可以考虑将设备放入法拉第袋中,正如第一章《介绍 Android 取证》一文中所解释的那样。这样,应特别小心避免通过任何通讯方式传送新消息或数据。
如何恢复已删除的文件?
当用户从设备中删除任何数据时,数据并不会被实际擦除,而是继续存在于设备上。被删除的是指向该数据的指针。所有文件系统都包含元数据,它保存有关文件层次结构、文件名等的信息。删除操作并不会真正擦除数据,而是移除文件系统的元数据。因此,当文本消息或其他文件从设备中删除时,它们只是对用户不可见,但文件仍然存在于设备上,只要没有被其他数据覆盖。因此,在新数据添加并占用空间之前,仍有恢复它们的可能。删除指针并标记空间为可用的操作与实际擦除设备上的所有数据相比是一个极其快速的操作。因此,为了提高性能,操作系统仅删除元数据。
恢复 Android 设备上已删除数据涉及三种情况:
-
恢复从 SD 卡删除的数据,如照片、视频等
-
恢复已删除的 SQLite 数据库数据,如短信、聊天记录、网页历史等。
-
恢复已删除的设备内部存储数据
以下章节将介绍可以用于从 SD 卡、SQLite 数据库和 Android 设备内部存储中恢复已删除数据的技术。
从 SD 卡恢复已删除的数据
存储在 SD 卡上的数据能够揭示许多在法医调查中有用的信息。事实上,照片、视频、语音录音和应用数据都存储在 SD 卡上,这进一步证明了这一点。如前几章所述,Android 设备通常在其 SD 卡上使用 FAT32 或 exFAT 文件系统。这样做的主要原因是这些文件系统被包括 Windows、Linux 和 macOS X 在内的大多数操作系统广泛支持。FAT32 格式化驱动器上的最大文件大小约为 4GB。随着现在越来越高的分辨率格式的出现,这一限制常常被突破,这就是为什么较新的设备支持 exFAT:这种文件系统没有这样的限制。如果外部 SD 卡可以作为驱动器挂载,恢复已删除的数据相对容易。
如果 SD 卡是可移动的,可以通过使用卡读器将其连接到计算机,从而将其作为驱动器挂载。在挂载时,可以向 SD 卡转移任何文件。某些使用 USB 大容量存储的旧设备也会在通过 USB 电缆连接时将设备挂载为驱动器。如前所述,在取证中,为确保原始证据不被修改,通常会对磁盘进行物理镜像,所有后续实验也都在镜像文件上进行。类似地,在 SD 卡分析中,也需要制作 SD 卡的镜像。镜像过程与第五章中解释的从 Android 设备中物理提取数据相似。一旦镜像完成,我们将得到一个原始镜像文件。在我们的示例中,我们将使用 AccessData 的 FTK Imager,这是一个镜像工具。除了创建磁盘镜像外,它还可以用来探索磁盘镜像的内容。
以下是使用此工具恢复 SD 卡内容的步骤:
- 启动 FTK Imager,点击菜单中的“文件”,然后选择“添加证据项...”,如以下截图所示:
向 FTK Imager 添加证据来源
-
在“选择源”对话框中选择“映像文件”,然后点击“下一步”。
-
在“选择文件”对话框中,浏览到下载
sdcard.dd文件的位置,选择它,然后点击“完成”,如下面的截图所示:
在 FTK Imager 中选择用于分析的图像文件
-
FTK Imager 的默认显示将展示 SD 卡内容,显示在右下角的查看窗格中。你还可以点击左下角的属性标签查看磁盘镜像的属性。
-
现在,在左侧窗格中,驱动器已打开。可以通过点击加号打开文件夹。当选中一个文件夹时,右侧窗格会显示其内容。选择一个文件后,其内容会显示在底部窗格。
-
如下图所示,被删除的文件会在其文件扩展名图标上方显示一个红色的
X:
被删除的文件在图标上显示红色 X
- 如下图所示,要导出文件,请右键点击包含图片的文件,然后选择“导出文件...”:
有时,只能恢复文件的一部分,这部分无法直接读取或查看。在这种情况下,我们需要查看空闲或未分配空间中的更多数据。文件雕刻技术可以用来从空闲和未分配的空间中恢复文件。PhotoRec 是可以帮助你完成此操作的工具之一。接下来的部分你将学习如何使用 PhotoRec 进行文件雕刻。
从 SQLite 数据库恢复已删除的记录
安卓中大部分的应用数据都存储在 SQLite 数据库中。与短信、电子邮件以及大多数应用数据相关的数据都存储在 SQLite 数据库中。这些数据库可以在数据库内部存储已删除的数据。用户标记为删除的记录不再出现在活动的 SQLite 数据库文件中。因此,通过分析这些 SQLite 文件,可以恢复已删除的数据,例如短信、联系人等。SQLite 页面中有两个区域可以包含已删除的数据:未分配块和空闲块。大多数商业取证工具通过扫描 SQLite 页面的未分配块和空闲块来恢复已删除的数据。解析已删除的数据可以使用例如 Belkasoft Evidence Center 等工具进行。该商业取证工具的试用版可以在这里下载:belkasoft.com/get。
在我们的例子中,我们将从安卓设备中恢复已删除的短信。恢复已删除的短信是设备取证分析中常见的请求,主要因为它是最流行的通信方式。有不同的方法可以恢复安卓设备上的已删除短信。但是,就解析 SQLite 文件来进行恢复而言,我们需要了解短信存储在设备上的位置。在第四章,从安卓设备中逻辑地提取数据,我们解释了安卓设备上存储用户数据的重要位置。
让我们来查看bugle_db,这是一个包含通过 Android 消息应用程序发送或接收的短信的 SQLite 数据库。该数据库位于/data/data/com.android.messaging/databases目录下。如果你有设备的物理镜像,你可以使用 FTK Imager 提取数据库,就像提取已删除的文件一样。如果你想直接从设备中提取,可以使用adb pull命令(设备必须已经 root)。
找到已删除记录的最简单方法是使用商业移动取证工具,如 Belkasoft Evidence Center、Cellebrite UFED Physical Analyzer、Oxygen Forensic Detective 等,但也有一些开源工具能够从未分配空间和空闲列表中恢复数据。一个这样的工具是由 Mari DeGrazia 开发的 SQLite Deleted Records Parser。你可以在她的 GitHub 上下载这个工具:github.com/mdegrazia/SQLite-Deleted-Records-Parser。
该工具有三种版本:Python 脚本、命令行版本和 GUI 版本。为了演示,我们将使用 GUI 版本,如下所示的例子所示:
使用该工具非常简单,您只需要选择源数据库和目标文件,然后点击处理。结果将得到一个 TSV 文件(如果选择了格式化输出),其中包含恢复的记录,包括其来源(未分配空间或空闲块)、偏移量和长度。
SD 卡安全
在旧版安卓系统中,简单地将手机插入计算机,通常会自动挂载 SD 卡并允许检查员访问其数据。在某个版本的安卓系统(可能是 3.0 版)中,这一行为发生了变化,尽管我们在多个变更日志中没有找到具体版本的描述。新版本的安卓系统如果启用了屏幕锁定,将不会自动允许从计算机访问 SD 卡,这意味着需要绕过屏幕锁定才能访问 SD 卡。唯一的例外是,物理外部 SD 卡仍然可以被取出,并使用传统的计算机取证方法进行分析。
SD 卡也可以被加密,如果是内置 SD 卡,则通过设备的全盘加密进行加密;如果是外部 SD 卡,则通过第三方应用程序进行加密。在某些情况下,启用全盘加密会使 SD 卡保持未加密状态,尽管这取决于设备制造商。
在安卓 Lollipop 系统中引入的全盘加密也对 SD 卡进行了加密。
高级取证方法
除了前几章中讨论的方法,还有一些更先进的、专业化的方法可供使用。JTAG 和芯片拆卸方法在许多常见情况下是非常有用的工具,但它们需要高级培训(并且在处理实际证据之前需要大量的实践!)。最后一种高级方法——冷启动攻击以恢复加密密钥,更加理论化。
JTAG
JTAG,联合测试行动小组(JTAG)是由电气和电子工程师协会(IEEE)制定的标准。在设备生产过程中,JTAG 用于通过专用接口与处理器进行通信,进行测试。幸运的是,对于取证检查员来说,它还允许他们直接与处理器通信,并获取闪存的完整物理映像。
要执行 JTAG 提取,设备必须拆开,直到电路板。电路板上将包含多个接点(设备电路板上的物理接触点),虽然它们通常没有标签,且接点数量通常远多于 JTAG 所需的数量。为了确定正确的接点,检查员必须查找引脚图(可以在网上找到,或随所选工具提供),或使用电子测试设备确定每个接点的功能。
检查员接下来需要将一根线焊接到每个接点上,或者使用商业上可用的适配器(有时称为夹具),并通过提供的适配器将其连接到 JTAG 盒子:
HTC Evo 在连接 JTAG 前后的情况(感谢 lowcostwin4n6.blogspot.com/)
JTAG 听起来可能很复杂(因为它确实很复杂),但它有许多有用的用途:
-
它不需要设备开机:
-
即使设备损坏,也可能成功
-
无射频屏蔽问题
-
-
它不需要 root、ADB 或 USB 调试:
-
可用于绕过设备的 PIN 码/密码
-
可以映像整个闪存
-
许多制造商生产 JTAG 工具,许多用于移动取证的常见工具可以在 teeltech.com/mobile-device-forensic-software/teel-tech-jtag-box-sets/ 找到。该网站上列出的 RIFF box 可能是最常用于移动取证的工具,因为它支持(包括针脚排布)多种设备。
JTAG 并不总是成功,甚至有时无法实现。尽管接口几乎总是在电路板上,制造商可以选择在设备制造后禁用它。
拆芯片
拆芯片涉及加热设备的电路板,直到固定组件的焊接点融化,然后拆除闪存芯片。随后,可以使用商业工具读取内存芯片,从而获得完整的物理映像。拆芯片技术,像 JTAG 一样,源自商业电子生产过程。熔化焊料的过程(通常称为回流或返工)用于将组件放置到电路板上或从电路板上移除,读取内存所使用的设备用于读取和写入内存芯片,通常以批量形式进行操作:
从损坏的手机中取出的内存芯片(感谢 www.binaryintel.com)
拆芯片具有与 JTAG 相同的优点:它不需要设备开机,并且可以用来绕过锁定设备的 PIN 码/密码。拆芯片通常被视为一种破坏性过程。虽然内存芯片可以被替换,但这是一个技术要求较高的过程,需要进一步的培训。但是,作为最后的手段,拆芯片是对于那些否则无法检查的设备来说是一个极好的替代方案。
拆芯片比 JTAG 显著更昂贵,因为需要专用的返工站和商业内存读卡器。有数十种返工站可供选择,它们提供的功能基本相同。也有多种内存读卡器,尽管我们在使用这个价格合理的型号时取得了很大成功:www.dataman.com/programmers/universal/dataman-48pro2-super-fast-universal-isp-programmer.html。返工站和读卡器并不是拆芯片唯一的成本;大多数读卡器还需要为每个要读取的芯片型号配备特定的适配器。
总结
本章中,我们讨论了几种用于物理成像内部存储或 SD 卡的技术,以及它们相关的一些常见问题:
| 技术 | 相关问题 |
|---|---|
dd |
-
通常预安装在设备上
-
可能无法在 MTD 块上使用
-
无法获取带外区域
|
nanddump |
|---|
-
设备上通常没有此功能,必须将其推送到设备上
-
与 MTD 块配合良好
-
可以基于使用的二进制文件中的选项获取带外区域
|
此外,每种成像技术可以用于将图像保存到设备上(通常是 SD 卡),或使用netcat将文件写入检查员的计算机:
| 技术 | 特性 |
|---|---|
| 写入 SD 卡 |
-
简单,不需要将额外的二进制文件推送到设备上
-
对大多数检查员来说很熟悉
-
如果 SD 卡与正在成像的分区存在符号链接,则无法使用
-
如果正在成像整个内存,则无法使用
|
使用netcat |
|---|
-
通常需要将另一个二进制文件推送到旧设备上
-
稍显复杂,必须严格按照步骤操作
-
无论成像的是什么,都能正常工作
-
可能比写入 SD 卡更费时
|
还介绍了一些可以用于 RAM 成像的工具:
| 工具 | 特性 |
|---|---|
| LiME |
-
必须为每个被检查的设备编译
-
非常复杂的过程
-
具有已知且良好文档化的分析程序
-
输出是所有 RAM 的转储
|
最后,我们简要讨论了芯片拆卸和 JTAG 技术的入门级内容。
在下一章中,我们将演示如何从物理镜像(如本章创建的镜像)中恢复已删除的数据。
恢复内部存储已删除的数据
从 Android 的内部存储中恢复已删除的文件,如应用数据等,并不像从 SD 卡和 SQLite 数据库中恢复这些数据那样简单,但当然并非不可能。许多商业取证工具能够从 Android 设备中恢复已删除的数据,当然,前提是物理获取是可能的,并且 userdata 分区没有加密。但对于现代设备,尤其是运行最新操作系统版本(如 Oreo 和 Pie)的设备,这并不常见。
大多数安卓设备,尤其是现代智能手机和平板电脑,使用 EXT4 文件系统来组织其内部存储中的数据。该文件系统在基于 Linux 的设备中非常常见。因此,如果我们想从设备的内部存储中恢复已删除的数据,我们需要一款能够从 EXT4 文件系统中恢复已删除文件的工具。一个这样的工具是 extundelete。该工具可以在此下载:extundelete.sourceforge.net/。
为了恢复一个 inode 的内容,extundelete 会在文件系统的日志中查找该 inode 的旧副本。inode 中包含的信息帮助工具定位文件在文件系统中的位置。为了恢复文件的内容及其名称,extundelete 可以在目录中查找已删除的条目,将文件的 inode 编号与文件名匹配。
要使用这个工具,你需要一台 Linux 工作站。大多数法医 Linux 发行版已经自带该工具。例如,下面是来自SIFT Workstation的截图——这是一个由 Rob Lee 和他的 SANS 学院团队创建的流行数字取证和事件响应 Linux 发行版(digital-forensics.sans.org/community/downloads):
extundelete 命令行选项
在开始恢复过程之前,你需要挂载一个之前已镜像的 userdata 分区。在这个示例中,我们将使用通过芯片脱离技术镜像的 Android 设备——你已经在第五章中了解过这种技术,物理提取 Android 设备数据。
首先,我们需要确定 userdata 分区在镜像中的位置。为此,我们可以使用来自Sleuth Kit的mmls,如下所示的截图:
Android 设备分区
如截图所示,userdata 分区是最后一个,起始扇区为9199616。为了确保 userdata 分区是 EXT4 格式的,我们可以使用fsstat,如下所示的示例:
fsstat 输出的部分内容
现在你需要做的是挂载 userdata 分区并运行 extundelete,如下所示的示例:
extundelete /userdata/partition/mount/point --restore-all
所有恢复的文件将被保存在当前目录的子目录RECOVERED_FILES中。如果你有兴趣恢复指定日期之前或之后的文件,可以使用--before date和--after-date选项。请注意,这些日期必须采用 UNIX 纪元格式。有很多在线和离线工具可以转换时间戳,例如,你可以使用www.epochconverter.com/。
如你所见,这种方法不太简单且速度较慢,但有一种更好的方法:使用 Autopsy,这是一款开源数字取证工具,已在第三章中介绍过,理解 Android 设备上的数据存储。
在下面的示例中,我们使用了内置的文件扩展名过滤器,找到了 Android 设备上的所有图片,并发现了大量已删除的文件:
使用 Autopsy 从 EXT4 分区恢复已删除的文件
使用文件系统日志恢复已删除的文件并不总是可能的,这正是文件雕刻派上用场的地方。
使用文件雕刻恢复已删除的数据
文件雕刻是取证中一种非常有用的方法,因为它可以恢复已删除或隐藏的数据进行分析。简而言之,文件雕刻是从没有文件系统元数据的碎片中重新组装文件的过程。在文件雕刻中,会在二进制数据中搜索并提取指定的文件类型,从而创建分区或整个磁盘的取证镜像。文件雕刻仅基于文件结构和内容,从驱动器的未分配空间中恢复文件,而不依赖任何匹配的文件系统元数据。
未分配空间是指驱动器中不再包含任何文件信息的部分,这些信息由文件系统结构如文件表指示。
通过扫描磁盘的原始字节并重新组装它们,可以恢复或重建文件。这可以通过检查文件的头部(前几个字节)和尾部(最后几个字节)来完成。
文件雕刻方法是根据所使用的底层技术进行分类的。头尾雕刻方法依赖于根据文件的头部和尾部信息恢复文件。例如,JPEG 文件以 0xffd8 开头,以 0xffd9 结尾。头部和尾部的位置被识别出来,介于这两个端点之间的内容会被雕刻出来。类似地,文件结构雕刻方法基于文件的内部布局来重建文件。但传统的文件雕刻技术,如我们已经解释过的那些,如果数据是碎片化的,可能无法奏效。为了克服这一问题,新的技术,如 智能雕刻,利用多种流行文件系统的碎片特征来恢复数据。
一旦手机映像完成,就可以使用如 PhotoRec 等工具进行分析。PhotoRec 是一个强大的免费工具,可以雕刻文件。该工具分析块数据库存储,识别已删除的文件并恢复它们。Scalpel 是文件系统无关的,并且已知能够在多种文件系统上工作,包括 EXT4、exFAT、FAT32 等。以下步骤说明了如何在 Windows 工作站上使用 PhotoRec 恢复文件:
-
从
www.cgsecurity.org/wiki/TestDisk_Download下载工具。将压缩包解压到你选择的目录中。 -
使用管理员权限打开命令提示符,并运行
photorec.exe,并将 Android 物理镜像作为参数。 -
选择你想从中雕刻数据的分区,在我们的例子中是
USERDATA。如下截图所示:
在 PhotoRec 中选择分区
- 如果你只想雕刻特定的文件类型,可以前往
File Opt。在我们的例子中,我们只关心 JPG 图像,因此我们只选择了一种文件类型,如下图所示:
在 PhotoRec 中选择文件类型
- 选择文件系统类型,在我们的例子中是 EXT4,如以下示例所示:
在 PhotoRec 中选择文件系统类型
- 现在,你应该选择工具是只扫描空闲空间,还是扫描整个分区。第二个选项会给你带来更多的数据,但它将与那些未被删除的文件混合在一起。以下示例展示了这些选择:
选择是否需要分析所有空间
- 最后,选择恢复的文件将存储的文件夹。你可以使用箭头键来完成此操作,然后按 C,如以下截图所示:
恢复的文件将保存在所选目录下名为 recup_dir 的子目录中。
总结
数据恢复是从设备中恢复已删除数据的过程,因此它是取证中非常重要的概念。在本章中,我们介绍了从 SD 卡和内部存储中恢复已删除数据的各种技术。虽然从可移动 SD 卡恢复数据相对容易,但从内部存储中恢复数据则涉及一些复杂性。SQLite 文件解析和文件雕刻技术有助于取证分析人员恢复 Android 设备内部存储中已删除的项目。
在下一章中,我们将尝试理解取证视角以及对 Android 应用程序的分析。
第七章:Android 应用程序的法医分析
本章将覆盖应用程序分析。本章将重点分析通过 第四章 从 Android 设备中逻辑提取数据 和 第五章 从 Android 设备中物理提取数据 中详细描述的任何逻辑或物理技术恢复的数据。本章还将大量依赖于 第二章 设置 Android 法医环境 中讨论的存储方法;我们将看到来自该章节中描述的文件层次结构内不同位置的 SQLite 数据库、XML 文件以及其他文件类型。到本章结束时,读者应当熟悉以下内容:
-
应用程序分析概述
-
为什么要进行应用程序分析?
-
第三方应用程序以及流行应用程序用于存储和混淆数据的各种方法
应用程序分析概述
法医分析应用程序既是一门科学,也是一门艺术。应用程序可以通过各种方式存储或混淆其数据。即便是同一版本的应用程序,其数据存储方式也可能不同。开发者在选择数据存储方式时,实际上只受限于他们的想象力(以及 Android 平台的限制)。正因为这些因素,应用程序分析是一项不断变化的工作;分析人员今天使用的方法,明天可能就完全不再适用。
法医分析应用程序的最终目标始终是相同的:了解应用程序的用途,并找到用户数据。
本章将探讨许多常见应用程序的当前版本。由于应用程序可能会通过更新更改其数据存储方式,本章中的内容并不是分析这些应用程序的权威指南。相反,我们将查看各种不同的应用程序,以展示它们存储数据时所使用的多种不同方法。大多数情况下,我们将重点关注非常常见的应用程序(例如,Google Play 上有数百万次下载的应用程序),除非在分析一些冷门应用时能揭示出有趣的新数据存储方式。
为什么要进行应用程序分析?
首先,Android 设备上的标准电话功能,如联系人、通话和短信,都是通过应用程序来实现的,因此即使是获取基本数据也需要分析应用程序。其次,一个人使用的应用程序可以告诉你很多关于他们的信息:他们去过哪里(以及何时去的),他们与谁沟通过,甚至他们未来可能会有什么计划。
许多手机预装了超过 20 个应用程序。检查员实际上无法知道这些应用中哪些可能包含对调查有用的信息,因此必须对所有应用进行分析。检查员可能会想跳过那些看起来似乎没有什么有用数据的应用,如游戏。然而,这样做是个坏主意;许多流行的游戏都有内置聊天功能,可能会提供有价值的信息。我们的分析将重点关注消息应用程序,因为我们的经验表明,这些应用在法医分析中通常最有价值。
本章布局
对于我们检查的每个应用程序,我们将提供一个包名和相关文件。所有应用默认将其数据存储在 /data/data 或 /data/user_de/0(较新的设备)目录下;如果应用在安装时请求此权限,应用也可以使用 SD 卡。包名是该应用在这些目录中的文件夹名称。相关文件 部分中的路径是从包名根目录开始的。SD 卡上的数据路径以 /sdcard 开头。请不要期望在应用的 /data/data 或 /data/user_de/0 目录中找到以 /sdcard 开头的数据路径!
我们将从一些谷歌应用程序开始,因为这些应用通常预装在大多数设备上(尽管并非必须如此)。然后,我们将查看可以在 Google Play 上找到的第三方应用程序。
确定安装了哪些应用
若要查看设备上有哪些应用程序,检查员可以导航到 /data/data 并运行 ls 命令。但这并不会提供格式良好的数据,无法在法医报告中显示得很好。我们建议提取 /data/system/packages.list 文件;该文件列出了设备上每个应用的包名和其数据路径(如果该文件在设备上不存在,adb shell pm list packages –f 命令是一个不错的替代选择)。例如,以下是 Google Chrome 的一条记录(我们测试设备上的完整文件包含 120 条记录):
这是数据存储方法 1:纯文本。我们常常看到应用以纯文本形式存储数据,甚至包括一些你意想不到的数据(例如密码)。
也许更有趣的是 /data/system/package-usage.list 文件,它显示了某个包(或应用)最后一次被使用的时间。这个文件并不完美;文件中显示的时间与我们最后一次使用该应用的时间并不完全一致。看起来应用更新或接收通知(即使用户没有查看它们)也可能影响时间,然而它对于一般了解用户最后使用的应用来说是有用的:
如果你想知道那一行中哪里可以找到时间,它采用的是被称为 Unix 纪元时间的格式。
理解 Unix 纪元时间
Unix 纪元时间,也称为 Unix 时间或 Posix 时间,是以自 1970 年 1 月 1 日午夜 UTC 以来的秒数(或毫秒数)表示的。10 位数值表示秒数,13 位数值表示毫秒数(至少对于智能手机上常见的时间,因为自 2001 年以来,9 位秒数和 12 位毫秒数值已不再出现)。在我们的示例中,值为1422206858650;表示自 1970 年 1 月 1 日午夜以来,Google Chrome 上次使用的时间是 14 亿 2 千 2 百 20 万 6 千 8 百 58 秒 650 毫秒!不用担心,我们也不知道这是哪个日期/时间。可以下载许多脚本和工具来将其转换为人类可读的格式;我们喜欢 DCode,这是一个免费的工具,可以在这里找到:www.digital-detective.net/digital-forensic-software/free-tools/。
在 DCode 中,只需从下拉列表中选择Unix: 毫秒值,在要解码的值字段中输入值,然后点击解码:
可以选择添加偏差字段,将时间转换为所需的时区。
另外,您还可以使用一个非常有用的在线纪元计算器,网址为www.epochconverter.com/。
使用任一方法,我们可以看到 Google Chrome 实际上是在 2015 年 1 月 25 日 17:27:38.650 UTC 上次使用的。Unix 纪元时间在 Android 设备中经常用于存储日期/时间值,并且在我们的应用分析中会反复出现。
Wi-Fi 分析
Wi-Fi 技术上不是一个应用程序,但它是一个宝贵的数据来源,应该进行检查,所以我们在这里简要讨论一下。Wi-Fi 连接数据位于/data/misc/wifi/wpa_supplicant.conf中。wpa_supplicant.conf 文件包含用户选择自动连接的接入点列表(当新接入点连接时,默认情况下会设置此选项)。用户通过设备设置忘记的接入点不会显示。如果接入点需要密码,密码也以明文形式保存在文件中。在以下示例中,NETGEAR60 接入点需要密码(ancientshoe601),而 hhonors 则不需要:
文件中存在的 SSID 并不意味着该设备已连接到该接入点。这些设置保存在用户的 Google 帐户中,并在该帐户设置时添加到设备中。检查者只能得出结论,用户从某个 Android 设备连接了这些接入点,而不一定是正在检查的设备。
联系人/通话分析
联系人和通话记录存储在同一个数据库中。用户无需显式添加联系人,当通过 Gmail 发送电子邮件、在 Google+ 上添加联系人或通过其他许多方式时,联系人可能会自动填充。
包名:com.android.providers.contacts
关注的文件:
-
/files/:-
photos/ -
profile/
-
-
/databases/:-
contacts2.db -
calllog.db
-
files 目录包含用户联系人照片存储在 photos 目录中的照片,以及用户个人资料照片存储在 profile 目录中的照片。
contacts2.db 数据库包含用户 Google 帐户中所有联系人的所有信息:
| 表格 | 描述 |
|---|---|
accounts | 显示设备上有权限访问联系人列表的帐户。至少有一个帐户会显示用户的 Google 帐户电子邮件地址。该列表可能包括已安装的第三方应用程序,这些应用程序有权限访问联系人列表(我们将在 Tango、Viber 和 WhatsApp 部分看到这一点)。 |
contacts | 包含部分联系人信息(更多数据可以在 raw_contacts 表中找到)。name_raw_contact_id 值对应于 raw_contacts 表中的 _id 值。photo_file_id 值对应于在 /files/photos 目录中找到的文件名。times_contacted 和 last_time_contacted 显示该联系人通过设备拨打或接听的次数,以及最后一次通话的时间,时间格式为 Unix 时间戳格式。 |
data | 此表包含每个联系人的所有信息,如电子邮件地址和电话号码。raw_contact_id 列是每个联系人的唯一值,可以与 raw_contact_id 中的 _id 值相关联来识别联系人。请注意,每个联系人可能有多行记录,如相同的 raw_contact_id 值所示。共有 15 个数据列(data1-data15),包含一些关于联系人的信息,但没有明显的规律。同一列可能包含联系人姓名、电子邮件地址、Google+ 个人资料等。data14 列的值与 files/profiles 路径下的图片文件名相关联。data15 列包含联系人的个人资料照片缩略图。 |
deleted_contacts | 包含 contact_id 值和 Unix 时间戳格式的 deleted_contact_timestamp。然而,无法将其与其他表格关联以识别被删除联系人的姓名。不过,可能可以使用 第六章 中的已删除数据恢复技巧,从 Android 设备恢复已删除数据,来恢复联系人的姓名。contact_id 值对应于 raw_contacts 表中的 contact_id 列。 |
groups | 显示联系人列表中的群组,可以是自动生成的或用户创建的。群组的标题是群组的名称。似乎没有办法识别每个群组中的用户。 |
raw_contacts | 包含联系人列表中每个联系人的所有信息。display_name 显示联系人的姓名(如果有)。要确定联系人的电话号码、电子邮件地址或其他信息,必须将 _id 列的值与数据表中的 raw_contact_id 值匹配。sync3 列显示一个时间戳,但根据我们的测试,这不能假设为联系人添加的时间;我们有一些联系人已经好几年了,但这个月才同步。times_contacted 和 last_time_contacted 列仅适用于电话;发送电子邮件或 SMS 给联系人并不会增加这些值。我们无法识别任何方法来确定联系人是通过手机界面添加的、通过 Google+ 添加为好友的,还是通过其他方式添加的。 |
calllog.db 包含关于来电、去电和未接来电的所有信息:
| 表格 | 描述 |
|---|
| calls | 包含设备上所有进出通话的信息。number 列显示远程用户的电话号码,以及该通话是拨出还是接听。date 列是通话的日期/时间,存储为 Unix 时间戳格式。duration 列是通话的持续时间(秒)。type 列表示通话类型:
-
收件
-
外发
-
未接来电
name 列显示远程用户的姓名,如果该号码已存储在联系人列表中。geocoded_location 显示电话号码的位置,基于区号(美国号码)或国家代码。|
SMS/MMS 分析
SMS 和 MMS 消息存储在同一数据库中。根据我们的经验,无论使用什么应用程序发送 SMS/MMS(也就是说,通过 Google Hangouts 发送 SMS 将填充此数据库,而不是这里检查的 Hangouts 数据库),此数据库都会被使用,尽管第三方应用程序也可能在其自己的数据库中记录这些数据。
包名:com.android.providers.telephony
感兴趣的文件:
-
/files -
/databases/:-
mmssms.db -
telephony.db
-
files 目录包含作为 MMS 发送的附件,包括发送和接收的文件。
telephony.db 数据库较小,但包含一个潜在有用的信息源:
| 表格 | 描述 |
|---|---|
siminfo | 包含设备中使用过的所有 SIM 卡的历史数据,包括 ICCID、电话号码(如果它存储在 SIM 卡上)和 MCC/MNC,后者可用于识别网络提供商。 |
mmssms.db 数据库包含有关 SMS 和 MMS 消息的所有信息:
| 表格 | 描述 |
|---|---|
part | 包含关于 MMS 附件文件的信息。每条消息至少有两个部分:SMIL 头和附件—可以在 mid 和 ct 列以及附加的文件类型中看到。_data 列提供了在设备上查找文件的路径。 |
pdu | 包含每条彩信的元数据。date列标识消息发送或接收的时间,采用 Linux 纪元格式。_id列似乎对应于part列中的 mid 值;关联这些值可以显示特定图片发送的时间。msg_box列显示消息的方向(1 = 接收,2 = 发送)。 |
sms | 包含每条短信的元数据(不包括彩信信息)。地址列显示远程用户的电话号码,无论消息是发送还是接收。person列包含一个可以在contacts2.db数据库中查找的值,并与data表中的raw_contact_id对应。如果是发送的消息,或者远程用户不在联系人列表中,person列将为空。date列显示消息发送的时间戳,采用 Linux 纪元格式。type列显示消息的方向(1 = 接收,2 = 发送)。body列显示消息内容。seen列表示消息是否已读(0 = 未读,1 = 已读);所有发送的消息将标记为未读。 |
words, words_content, words_segdir | 似乎包含消息的重复内容;该表的具体目的尚不清楚。 |
用户字典分析
用户字典是检查员获取数据的一个不可思议的来源。每当用户输入一个未被识别的单词并选择保存该单词以避免被自动更正标记时,用户字典就会被填充。有趣的是,我们的测试设备中包含了许多我们从未输入或保存过的单词;这些数据似乎会与用户的 Google 账户同步,并在多个设备之间持久存在。从账户同步的单词按字母顺序添加到数据库的顶部,而手动添加的单词则按添加顺序出现在底部。
包名:com.android.providers.userdictionary
感兴趣的文件:
/databases/user_dict.db
| 表格 | 描述 |
|---|---|
words | word列包含添加到字典中的单词。频率列可能应被忽略;无论我们使用该单词多少次,它显示的值始终是(250)。 |
以下是用户字典中的一些示例条目:
Gmail 分析
Gmail 是由 Google 提供的电子邮件服务。在设备第一次设置时,通常会要求提供 Gmail 账户,虽然这不是必须的。
包名:com.google.android.gm
感兴趣的文件:
-
/cache -
/databases/:-
mailstore.<username>@gmail.com.db -
databases/suggestions.db
-
-
/shared_prefs/:-
MailAppProvider.xml -
Gmail.xml -
UnifiedEmail.xml
-
应用程序文件夹中的/cache目录包含最近的邮件附件文件,无论是已发送还是已接收的。这些附件即使没有被用户明确下载,也会保存在这里。
mailstore.<username>@gmail.com.db文件包含各种有用的信息。数据库中的有趣表格包括:
| 表 | 描述 |
|---|---|
附件 | 关于附件的信息,包括它们的大小和在设备上的文件路径(上文提到的/cache目录)。每一行还包含一个messages_conversation值;该值可以与对话表进行对比,以关联附件和它所在的邮件。filename列标识文件在设备上的存储路径。 |
对话 | 在旧版本中,可以恢复完整的电子邮件对话。在当前版本中,Google 不再在设备上存储完整的对话,可能假设用户会有数据连接来下载完整对话。现在,只能恢复主题行和一个片段。片段大致是应用通知栏或收件箱屏幕中显示的文本量。fromCompact列标识发件人和其他收件人。 |
suggestions.db数据库包含了在应用内搜索的术语。
shared_prefs目录中的 XML 文件可以确认与应用程序一起使用的账户。Gmail.xml包含了与我们测试账户关联的另一个账户,但该账户从未在应用中使用。UnifiedEmail.xml包含了一部分向该账户发送邮件的发件人列表,但没有明确的规律;许多发件人出现在列表中,但远不是所有的,而且它们没有特定的顺序。Gmail.xml还包含了应用程序上次同步的时间,格式为 Unix 时间戳。
Google Chrome 分析
Google Chrome 是一款网页浏览器,是许多设备的默认浏览器。设备上的 Chrome 数据有些独特,因为它包含的不仅仅是设备上的数据,还包含了用户在所有登录了 Chrome 的设备上的数据。这意味着,用户在台式电脑上浏览的数据很可能会出现在手机数据库中。然而,这也导致了考察者需要处理大量数据,但这也是一个好问题。
包名:com.android.chrome
感兴趣的文件:
-
/app_chrome/Default/:-
同步数据/SyncData.sqlite3 -
书签 -
Cookies -
Google Profile Picture.png -
历史记录 -
登录数据 -
Preferences -
热门网站 -
Web 数据
-
-
/app_ChromeDocumentActivity/
/app_chrome/Default文件夹中列出的所有文件,除了那个 PNG 文件、Bookmarks和Preferences,都是 SQLite 数据库,尽管它们没有文件扩展名。
SyncData.sqlite3 数据库非常有趣,因为它似乎包含了一份从用户账户在设备上同步到 Google 服务器的数据列表。我们的数据库中,活跃的 Chrome 账户包含超过 2700 条记录,包括浏览历史、自动填充表单信息、密码和书签。例如,我们能够找到其中一位作者在 2012 年搜索的一个术语,见下图:
| 表格 | 描述 |
|---|---|
metas | 数据库中有许多包含时间戳的列,在我们的数据库中,每个条目的时间戳似乎相差仅仅几秒。尚不清楚哪个时间对应于条目添加的确切时间,但所有时间大致与用户账户中活动的时间一致。包含时间戳的列有 mtime、server_mtime、ctime、server_ctime、base_version 和 server_version。non_unique_name 和 server_non_unique_name 列显示已同步的内容。例如,我们的一个条目显示:autofill_entry|LNAME|Tindall。这些列中的其他条目包括访问过的 URL、密码,甚至账户使用过的设备。 |
Bookmarks 文件是一个纯文本文件,包含与账户同步的书签信息。它包括每个书签站点的名称、URL 以及书签添加的日期/时间,时间以我们尚未遇到的格式存储:Webkit 格式。要解码这些值,请参见 解码 Webkit 时间格式 部分。
这是数据存储方法 3:Webkit 时间格式。
Cookies 数据库存储了访问过网站的 cookie 信息(取决于网站和 Chrome 设置),包括网站名称、cookie 保存日期以及最后访问 cookie 的时间,时间以 Webkit 时间格式存储。
Google Profile Picture.PNG 文件是用户的个人资料图片。
History 数据库包含用户的网页历史记录。
| 表格 | 描述 |
|---|---|
keyword_search_terms | 包含在 Chrome 中使用 Google 搜索的术语列表。术语列显示搜索的内容,而 url_id 可以与 URL 表进行关联,以查看搜索的时间。 |
segments | 该表包含一些访问过的 URL,但并非所有的 URL。尚不清楚是什么原因导致数据被输入到这个表中。 |
urls | 包含 Google 帐号在所有设备上的浏览历史记录,而不仅仅是从中提取数据库的设备。我们的历史记录追溯大约 3 个月,包含了 494 条记录,尽管 Google 帐号比这更早,我们在这段时间内肯定访问了超过 494 个页面。目前尚不清楚导致这种差异的具体原因,或者是什么决定了历史记录的截止日期。id 列是每行数据的唯一值。url 和 title 列分别包含访问的 URL 和页面的名称。visit_count 列似乎准确计数了访问该 URL 的次数。typed_count 始终小于或等于 visit_count,但我们不确定它具体表示什么。对于某些网站,可以通过计算通过书签访问网站而非直接输入 URL 的次数来解释这种差异,但并非所有情况都如此。last_visit_time 是访问该 URL 的最后时间,以 Webkit 时间格式表示。 |
visits | 包含每次访问 urls 表格中 URL 的记录;该表格中每个 URL 的条目数与 url 表格中的 visit_count 列值相对应。url 列值与 url 表格中的 id 列值相关联。每次访问的时间可以在 visit_time 列中找到,同样是 Webkit 时间格式。 |
Login Data 数据库包含保存在 Chrome 中的登录信息,并且会在使用 Google 帐号的所有设备之间同步:
| 表格 | 描述 |
|---|---|
logins | origin_url 是用户最初访问的网站,action_url 是如果用户被重定向到登录页面的 URL;如果第一个访问页面就是登录页面,那么两个 URL 是相同的。username_value 和 password_value 列显示为该 URL 存储的用户名和密码(明文);我们不会包括数据库的截图!date_created 是首次保存登录信息的日期/时间,以 Webkit 时间格式表示。date_synced 列是登录数据被同步到设备本地的日期/时间,同样采用 Webkit 时间格式。times_used 列显示登录信息在保存后由 Chrome 自动填充的次数(不包括第一次登录,因此某些值可能为 0)。 |
-
Preferences文件是一个文本文件,包含用户已登录 Chrome 的 Google 帐号。 -
Top Sites数据库包含最常访问的网站,这些网站在 Chrome 启动时默认显示。 -
Web Data数据库包含用户为自动填充网站表单而保存的信息。
| 表格 | 描述 |
|---|---|
autofill | 包含网页表单上的字段列表和用户输入的值。name 列显示用户输入的字段名称,value 列显示用户输入的内容。date_created 和 date_last_used 很容易理解,并以 Linux 纪元格式存储。请注意,尽管这可能是非常有价值的信息(例如,我们的数据库中包含了一些没有存储在其他地方的用户名),但也很少有上下文可供参考。无法确定存储这些信息的 URL,并且可能无法确定。 |
autofill_profile_emails | 包含用户保存的用于自动填写网页表单中 email 字段的所有值。 |
autofill_profile_names | 包含用户保存的用于自动填写网页表单中 First、Middle、Last 和 Full Name 字段的所有值。 |
autofill_profile_phonwa | 包含用户保存的用于自动填写网页表单中 Phone Number 字段的所有值。 |
autofill_profiles | 包含用户保存的用于自动填写网页表单中地址信息字段的所有值。 |
/app_ChromeDocumentActivity/ 目录包含设备上最近打开的标签页的历史记录文件。可以从这些文件中恢复访问过的网站的 URL。
解码 Webkit 时间格式
这是一个 Webkit 时间值的示例:13066077007826684。
乍一看,它似乎与 Unix 纪元时间非常相似,只是稍微长一些(也许它存储的是纳秒?)。尝试将其解码为纪元时间的检查员将得到一个 2011 年 5 月的日期,这看起来可能很准确,但实际上与正确日期相差了好几年!
Webkit 时间 是 一种纪元时间,它只是基于不同于 Unix 纪元时间的起点。Webkit 纪元时间是自 1601 年 1 月 1 日午夜以来的微秒数。是的,我们说的是 1601 年。一旦知道纪元的起点,将其转换为一个可识别的格式就只是一个数学问题。但,再次强调,我们还是更愿意使用 DCode。
这次在 DCode 中,选择 Decode Format 下拉菜单中的 Google Chrome Value,然后点击 Decode:
我们示例的实际值是 2014 年 11 月 2 日 18:04:33 UTC;这与我们如果以 Unix 纪元时间来解读所得到的值有显著不同!
Google Maps 分析
Maps 是由 Google 提供的地图/导航应用程序。
包名: com.google.android.apps.maps
感兴趣的文件:
-
/cache/http/ -
/databases/:-
gmm_myplaces.db -
gmm_storage.db
-
/cache/http 文件夹包含许多文件,扩展名为 .0 和 .1。.0 文件是对应 .1 文件的网页请求。.1 文件主要是图像文件,可以通过适当更改扩展名来查看;在我们的测试设备上,它们要么是 .jpg 文件,要么是 .png 文件。这些文件主要是用户附近的位置,不一定是用户特意搜索的位置。
这是数据存储方法 4:错误命名的文件扩展名
总是验证无法打开的文件的头部,或使用 EnCase 等自动化工具检测不匹配的头部/文件扩展名。验证文件签名的好资源是 www.garykessler.net/library/file_sigs.html。
gmm_myplaces.db 数据库包含用户保存的位置。这些位置与用户的 Google 账户同步,因此这些位置未必是通过该应用程序保存的。
gmm_storage.db 包含搜索点击和已导航至的位置:
| ** 表格** | 描述 |
|---|---|
gmm_storage_table | _key_pri 列似乎标识了位置的类型,bundled 看起来是一个在搜索中出现的点击,而 ArrivedAtPlacemark 标识了实际导航到的位置。 _data 列包含了位置的地址。 |
谷歌即时通讯分析
Hangouts 是 Google 提供的聊天/SMS 应用程序。在 Android 设备上,Hangouts 是默认的 SMS 客户端。
包名:com.google.android.talk
感兴趣的文件:
-
/cache/volleyCache/ -
/databases/babel#.db(我们的设备上有babel0.db和babel1.db) -
/shared_prefs/accounts.xml
cache 目录包含 .0 文件,如在 Google 地图示例中讨论的那样。这些文件包含一个用于获取联系人头像的 URL,以及文件中嵌入的 JPG。访问该 URL 或从文件中切割 JPG 将恢复联系人的图片。
babel#.db 文件包含所有的消息数据。在我们的测试设备上,babel0.db 是空白的,而 babel1.db 包含了活跃账户的所有数据。数据库中有许多值得查看的表格:
| 表格 | 描述 |
|---|---|
conversations | 包含会话数据。每个聊天都有一个唯一的 conversation_id。 latest_message_timestamp 是最近聊天的时间,采用 Linux epoch 格式。 generated_name 列列出了设备上的所有参与者,减去账户本身。 snippet_text 列是最近消息的内容;与 Gmail 类似,设备上不会存储整个聊天记录。 latest_message_author_full_name 和 latest_message_author_first_name 列标识了 snippet_text 列的作者。 inviter_full_name 和 inviter_first_name 列标识了发起会话的人。 |
dismissed_contacts | 列出了曾经发消息的联系人的姓名列表。这些在应用程序内被标记为 隐藏联系人。 |
messages | 如预期的那样,包含每个对话的详细消息历史记录。文本列包含消息内容,时间戳列是 Linux 时间戳格式的日期/时间。remote_url 列再次是一个 URL,用于检索消息中共享的图像,可以公开访问。author_chat_id 是一个值,可以与参与者表相关联,用来识别每条消息的作者。 |
participants | 包含与之聊天的人的列表。包括全名、个人资料图片 URL 和一个 chat_id 用于在消息表中标识该人。 |
accounts.xml 文件有一个 phone_verification 字段,包含与 Google 账户关联的电话号码,当 Hangouts 配置为发送 SMS 时使用。这可能非常有用,因为通常很难获取设备的电话号码,因为它通常不存储在设备中。
Google Keep 分析
Keep 是由 Google 提供的便签应用。它还可以用于设置提醒,提醒可以在某个特定日期/时间或用户位于指定位置时触发。
包名: com.google.android.keep
相关文件:
-
/databases/keep.db -
/files/1/image/original
/files/1/image/original 目录包含使用应用程序拍摄的照片。便签和提醒都可以与图像相关联。
Keep.db 包含所有关于便签和提醒的信息。再次提到,有几个重要的表格:
| 表格 | 描述 |
|---|---|
alert | 包含关于基于位置的提醒信息。reminder_id 可以与提醒表中的条目相关联。reminder_detail 表包含为提醒设置的纬度和经度。scheduled_time 是设置提醒的日期/时间,采用 Linux 时间戳格式。 |
blob | 包含 /files 目录中图像的元数据,包括文件名和大小。blob_id 可以与 blob_node 表中的 _id 列相关联。 |
blob_node | 包含 /files 目录中图像的创建时间值,采用 Linux 时间戳格式。 |
list_item | 存储设备上每个便签的数据。文本列包含每个便签的完整内容。list_parent_id 列是每个便签的唯一值;如果多行具有相同的值,则表示它们是在同一便签内作为列表创建的。time_created 和 time_last_updated 列分别是便签的创建时间和最后一次与 Google 服务器同步的时间,采用 Linux 时间戳格式。 |
reminder | 包含应用中设置的每个提醒的数据。如果提醒是基于时间的,julian_date 和 time_of_day 列将被填充。 |
转换 Julian 日期
儒略日类似于 Linux 纪元格式,只是从不同的日期开始。儒略日系统计算的是自公元前 4713 年 1 月 1 日中午以来的天数。美国海军天文台提供了一个优秀的儒略日计算器:aa.usno.navy.mil/data/docs/JulianDate.php。要从数据库中获取儒略日,只需将两列结合在一起,中间用小数点隔开,例如:
这将对应于儒略日2457042.46800000。当此值输入到网站时,我们可以得知设置的提醒日期是 2015 年 1 月 19 日,23:13:55.2 UT。如果设置了基于位置的提醒,location_name、latitude、longitude和location_address字段将会被填充。最后,time_created和time_last_updated字段分别表示笔记创建的时间和最后与 Google 服务器同步的时间,以 Linux 纪元时间表示。
数据存储方法 5:儒略日
从 Skype 恢复视频消息
如前所述,视频消息不会保存在设备上。幸运的是,我们可以通过互联网访问它们。第一步是通过查看body_xml列中的 Messages 表来验证视频消息是否已发送。接下来,记下该消息的convo_id字段:
我们的视频消息在convo_id为257。
然后,在 Chats 表中查找该convo_id在conv_dbid列中的记录,并找到dbpath值。这将是会话备份文件的名称:
要找到备份文件,请查看files/<用户名>/chatsync目录。每个会话都会有一个文件夹,文件夹的名称是备份名称的前两位数字。我们的备份将位于28文件夹中。
在十六进制编辑器中打开备份文件,并搜索videomessage。你应该能找到一个 URL 和一个用于访问视频的代码:
实际访问该 URL 可能需要额外的逮捕令或法律许可,这取决于当地的法律管辖区。由于这些数据不在设备上,且属于私人数据,未经法律指导访问这些数据可能会使视频中的任何证据无效。
Google Plus 分析
Google Plus 是一个基于 Google 的社交网络。它允许分享文本/视频/图片,添加朋友,关注他人并进行消息交流。根据用户的设置,Google Plus 还可能自动上传用户设备上拍摄的所有图片。
包名:com.google.android.apps.plus
感兴趣的文件:
/databases/es0.db
Es0.db包含了调查员期望从社交媒体账户中找到的所有信息:
| 表格 | 描述 |
|---|---|
all_photos | 包含一个 URL,用于下载用户共享或与用户共享的图像,以及以 Linux 纪元格式显示的创建日期/时间 |
activities | 显示在用户动态流中的数据(即他们的新闻推送)。每个帖子的创建和修改时间再次以 Linux 纪元时间格式存储。标题和评论列将包含帖子的标题以及至少一些评论。永久链接列包含一个可以点击查看帖子的 URL(如果帖子是公开分享的)。如果帖子是私密分享的,仍然可以从嵌入表中恢复其内容。相关表包含由 Google 自动生成的与帖子的相关标签,即使帖子是私密的,也会填充这些标签。 |
activity_contacts | 包含在活动表中发布的人员的姓名列表。 |
all_photos | 包含用户备份到 Google Plus 的所有照片的列表,无论这些照片是否已被分享。image_url 可用于下载用户的任何照片,并且是公开可用的。删除 URL 末尾的 -d 可以在不下载的情况下查看图片。时间戳列是图片被 拍摄 的日期/时间,基于图片的元数据;它不表示图片上传的时间。 |
all_tiles | 包含 all_photos 的一个未知子集,还包括用户共享的图像。 |
circle_contact | 包含用户已添加到其圈子中的人员列表。不包含姓名,但一些 link_person_id 值包含电子邮件地址。link_circle_id 值可以与圈子表关联,以识别每个圈子的名称。然后,link_person_id 可以与联系人表关联,以识别每个用户属于哪个圈子。 |
circles | 包含用户创建的所有圈子,以及每个圈子的成员数量。 |
contacts | 用户圈子中的所有联系人列表。 |
events | 用户被邀请的所有事件的列表,无论是否参加。名称列是事件的标题。creator_gaia_id 可以与联系人表中的 gaia_id 列关联,以识别事件的创建者。start_time 和 end_time 列表示事件的开始时间和结束时间,采用 Linux 纪元格式。event_data 列包含创建者输入的事件描述,以及如果有添加的地点信息。还列出了所有其他被邀请参加事件的用户。 |
squares | 用户加入的群组列表。 |
Facebook 分析
Facebook 是一款社交媒体应用,已在 Google Play 上被下载超过 10 亿次。
包名: com.facebook.katana
感兴趣的文件:
-
/files/video-cache/ -
/cache/images/ -
/databases/-
bookmarks_db2 -
contacts_db2 -
nearbytiles_db -
newsfeed_db -
notifications_db -
prefs_db -
threads_db2
-
/files/video-cache 目录包含来自用户新闻推送的视频,但似乎没有办法将这些视频与发布它们的用户关联起来。
/cache/images 目录包含来自用户新闻源的图片,以及联系人个人资料照片。该目录包含多个其他子目录(我们测试的手机上有 65 个),每个子目录可以包含多个 .cnt 文件。.cnt 文件通常是 JPG 文件或其他图像格式。
bookmarks_db2 数据库是显示在用户新闻源侧边的项目列表,如群组和应用程序。许多这些书签是 Facebook 自动生成的,但也可以由用户创建。
| 表格 | 描述 |
|---|---|
| bookmarks | 包含数据库中的所有信息。bookmark_name 列是显示给用户的书签名称。bookmark_pic 列包含一个可以公开访问的 URL,用于查看显示给用户的书签图标。bookmark_type 列标识组的类型;我们的测试显示包括 profile、group、app、friend_list、page 和 interest_list。最后,bookmark_unread_count 列显示该组中用户未读的消息数量。 |
contacts_db2 数据库,顾名思义,包含所有用户联系人的信息:
| 表格 | 描述 |
|---|---|
contacts | 包含关于用户所有联系人信息。fbid 列是唯一标识符,用于在其他数据库中标识该联系人。first_name、last_name 和 display_name 列显示联系人的姓名。small_picture_url、big_picture_url 和 huge_picture_url 包含联系人个人资料照片的公共链接。communication_rank 似乎是一个数字,表示该联系人与用户之间的沟通频率(考虑了消息、评论,可能还有其他因素);较高的数字表示与该联系人的沟通频率较高。added_time_ms 显示联系人作为朋友被添加的时间(以 Linux 纪元格式表示)。bday_day 和 bday_month 列显示联系人的生日日期,但不包括年份。data 列包含数据库中其他所有数据的副本,还包含联系人位置,这是数据库中其他地方找不到的。 |
nearbytiles_db 是一个包含用户附近可能感兴趣的位置的数据库;显然,这个数据库会持续更新,即使用户没有查看这些位置。这个数据库很有趣,因为,虽然它不是精确的位置(我们的大部分测试显示的地点距离我们的位置大约 6-10 英里),但它提供了一个粗略的用户活动区域:
| 表格 | 描述 |
|---|---|
nearby_tiles | 包含用户附近位置的纬度和经度值,以及从 Facebook 服务器获取该位置的时间(以 Linux 纪元格式表示)。 |
newsfeed_db 包含显示在用户新闻源中的数据。根据应用程序的使用情况,它可能是一个非常大的文件:
| 表格 | 描述 |
|---|---|
home_stories | fetched_at 列显示故事从 Facebook 服务器拉取的时间,通常与用户使用应用程序或查看故事的时间非常接近。story_data 列包含故事,作为数据块存储。当在十六进制或文本编辑器中查看时,可以找到发布故事的用户名。帖子内容也可以以纯文本形式找到,并且通常会以 text 标签作为前缀。下面是一个示例: |
请注意,story_data 列中的这个单元格的实际内容包含超过 10,000 字节的数据,尽管实际消息只有大约 50 字节。
notifications_db 包含发送给用户的通知:
| 表格 | 描述 |
|---|---|
gql_notifications | seen_state 列显示通知是否已被查看和阅读。更新列包含通知更新的时间(即如果未读则为发送时间,或者为阅读时间),以 Linux 时间戳格式显示。gql_payload 列包含通知的内容以及发送者,类似于 newsfeed_db 中的 story_data 列。消息内容通常会以 text 标记为前缀。少量数据(显示通知文本)可以在 summary_graphql_text_with_entities 和 short_summary_graphql_text_with_entities 列中找到。profile_picture_uri 包含一个公共 URL,用于查看发送者的个人资料图片,而 icon_url 列则有一个链接,用于查看与通知相关的图标。 |
prefs_db 数据库包含应用程序偏好设置:
| 表格 | 描述 |
|---|---|
preferences | /auth/user_data/fb_username 行显示用户的 Facebook 用户名。/config/gk/last_fetch_time_ms 值是应用程序最后一次与 Facebook 服务器通信的时间戳,但可能不是用户最后一次与应用程序互动的确切时间。/fb_android/last_login_time 显示用户通过应用程序登录的最后时间。数据库中包含许多其他时间戳,当这些时间戳组合在一起时,可以用来构建一个不错的应用使用情况档案。/auth/user_data/fb_me_user 包含关于用户的数据,包括他们的姓名、电子邮件地址和电话号码。 |
threads_db 数据库包含消息信息:
| 表格 | 描述 |
|---|---|
messages | 每条消息在 msg_id 列中都有一个唯一的 ID。文本列包含消息的纯文本。发送者列标识消息发送者的 Facebook ID 和姓名。timestamp_ms 列是消息发送的时间,采用 Linux 时间戳格式。附件列包含一个公共 URL,用于检索附加的图片。坐标列将显示发送者的经纬度,如果他们选择显示位置的话。来源列标识消息是通过网站还是应用程序发送的。 |
Facebook Messenger 分析
Facebook Messenger 是一款独立于主 Facebook 应用程序的消息应用。它在 Play Store 上的下载量超过 5 亿。
包名: com.facebook.orca
感兴趣的文件:
-
/cache/-
audio/ -
fb_temp/ -
image/
-
-
/sdcard/com.facebook.orca -
`/files/ rti.mqtt.analytics.xml` -
/databases/-
call_log.sqlite -
contacts_db2 -
prefs_db -
threads_db2
-
/cache/audio 目录包含通过应用程序发送的音频消息。这些文件的扩展名为 .cnt,但实际上是 RIFF 文件,可以使用 Windows Media Player、VLC 媒体播放器等程序播放。
/cache/fb_temp 路径包含通过应用程序发送的图片和视频的临时文件。文件将保留多久尚不明确;在我们的测试中,我们发送和接收了共五个文件,且一周后所有五个文件仍然保留在临时文件夹中。
/cache/image 目录包含许多其他目录(我们测试的手机上有 33 个),每个目录可以包含多个 .cnt 文件。应验证每个文件的文件头,因为其中一些是视频文件,另一些是图片。我们找到了几个来自 fb_temp 文件夹的文件,以及一些联系人的头像。
SD 卡上的 fb_temp 文件夹仅包含已发送的图片和视频。
该应用程序还包括一个选项(默认情况下禁用),用于将所有接收到的图片/视频下载到设备的图库中。如果选择此选项,所有接收到的图片/视频将出现在 SD 卡上。
/files/rti.mqtt.analytics.xml 文件包含用户的 Facebook UID。
call_log.sqlite 数据库包含通过应用程序进行的通话记录。person_summary 表包含相关数据:
| 表格 | 描述 |
|---|---|
person_summary | user_id 列包含远程用户的 Facebook ID;可以通过与 contacts_db2 中的 fbid 列关联来确定该用户的名字。last_call_time 列包含上次通话的时间,采用 Linux 时间戳格式。此表不包含通话方向的信息(发送或接收)。 |
contacts_db2 文件是一个 SQLite 数据库,尽管没有文件扩展名。该数据库中有用的表包括:
| 表格 | 描述 |
|---|---|
contacts | 此表包括用户添加的联系人,以及从用户手机簿中抓取的联系人(如果手机簿联系人使用 Facebook Messenger)。它包含每个联系人的名字和姓氏,以及该联系人的 Facebook ID(如在 call_log.sqlite 表中讨论)。added_time_ms 显示每个用户添加到应用程序的时间。这可以一定程度上揭示联系人是手动添加还是自动添加;在几毫秒内添加的大量联系人很可能是在应用程序安装时自动创建的。small_picture_url、big_picture_url 和 huge_picture_url 列包含联系人公开的个人资料图片链接。联系人的电话号码可以在数据列中的信息块中找到。需要注意的是,我们不知道此数据库中的某些联系人来源。他们不是我们 Facebook 账户的好友,也不是设备电话簿中的联系人,但是在抓取电话簿时被添加进来。我们最好的猜测是我们电话中的一些联系人具有 Facebook 关联到其他用户的电话号码。 |
favorite_contacts | favorite_contacts 表显示用户添加为收藏的联系人。它们由 fbid 列标识,可以与联系人表关联。 |
prefs_db 数据库包含有关应用程序和账户的有用元数据:
| 表格 | 描述 |
|---|---|
preferences | /messenger/first_install_time 值表示应用程序的安装时间,以 Linux 纪元时间为准。/auth/user_data/fb_username 值显示与应用程序关联的用户名。/config/neue/validated_phonenumber 值显示与应用程序关联的电话号码。用户的名字和姓氏可以在 /auth/user_data/fb_me_user 值中找到。 |
最后,threads_db2 数据库包含有关消息的数据:
| 表格 | 描述 |
|---|---|
group_clusters | 显示用户创建的文件夹。 |
group_conversations | 包含每个群组聊天的 thread_key 值;这可以与消息表相关联。 |
messages | thread_key 是为每个聊天会话生成的唯一 ID。文本列包含发送和接收的每条短信的内容。这也通过 You called Facebook User.、Facebook User called you. 和 You missed a call from Facebook User 这些短语来标识语音电话。发送者列标识每条消息(或每个电话)的发送者。timestamp_ms 列显示每条消息的发送时间,采用 Linux 时间戳格式。附件列将显示每个发送或接收的附件的数据,文件类型也可以在数据中看到。pending_send_media_attachment 显示设备上用于恢复已发送附件的路径。直接找到接收到的附件似乎是不可能的,尽管它们在 /cache/images 目录中被恢复,但没有办法将它们与特定的消息或发送者相关联。 |
Skype 分析
Skype 是一个语音/视频通话应用程序,也是一个由微软拥有的消息应用程序,在 Google Play 上已有超过 1 亿次安装。
包名:com.skype.raider
关注的文件:
-
/cache/skype-4228/DbTemp -
/sdcard/Android/data/com.skype.raider/cache/ -
/files/-
shared.xml -
<username>/thumbnails/ -
<username>/main.db -
<username>/chatsync
-
/cache/skype-4228/DbTemp 目录包含多个没有扩展名的文件。我们设备中的一个文件(temp-5cu4tRPdDuQ3ckPQG7wQRFgU)实际上是一个 SQLite 数据库,包含它曾连接过的无线接入点的 SSID 和 MAC 地址。
SD 卡路径将包含在聊天中接收到的任何图片或文件。如果下载了文件,它将保存在 SD 卡根目录下的 Downloads 文件夹中。
shared.xml 文件列出了账户的用户名,以及最后一次连接到 Skype 的 IP 地址:
<username>/thumbnails 目录包含用户的个人资料图片。
main.db 数据库,顾名思义,包含所有应用的使用历史记录。以下是一些重要的表格:
| 表格 | 描述 |
|---|---|
Accounts | 显示设备上使用的账户以及相关联的电子邮件地址。 |
CallMembers | 应用的通话记录。持续时间表是通话的时长,start_timestamp 是通话开始的时间,采用 Linux 时间戳格式;如果通话未接听,这两列都不会被填充。creation_timestamp 是通话的实际开始时间;它会在通话在应用中启动时立即填充,因此即使通话没有接听,仍然会显示在这一列中。ip_address 列显示连接通话时用户的 IP 地址。类型列指示通话是拨出还是接入(1 = 接入,2 = 拨出)。guid 列也显示通话方向,列出每个参与者从左到右,左侧的用户为发起通话的用户。call_db_id 列可以与通话表进行关联,找到有关通话的更多信息。 |
Calls | 与 CallMembers 非常相似,但信息较少。值得注意的是,此表中的 begin_timestamp 列与 CallMembers 中的 creation_timestamp 相同。还有一个 is_incoming 列显示通话的方向:0 表示外呼,1 表示接听。最后需要注意的是,某些通话的时长与 CallMembers 表中的数据不匹配。一个时长比另一个表中显示的多了一秒钟。看起来 CallMembers 表是根据 start_timestamp 计算通话时长,而 Calls 表是根据 begin_timestamp 计算时长。时长差异可能是由于用户接受通话所花费的时间。 |
ChatMembers | 显示每个聊天中的用户。adder 列列出了发起聊天的用户。 |
Chats | 列出了每个独特的聊天会话。时间戳列是对话开始的日期/时间,采用 Linux 时间戳格式。dialog_partner 列显示聊天中的用户,不包括设备上的账号。posters 表显示每个在聊天中发表评论的用户,如果设备上的账号有发表内容,也会包括在内。participants 列与 dialog_partner 列类似,但包括用户的账号。最后,dbpath 列包含存储在 <username>/chatsync 目录中的聊天备份文件的名称。这个信息在本分析中将会变得非常重要。 |
Contacts | 这是一个非常误导的表。在我们的测试中,我们将两个用户添加到联系人列表中,但 Contacts 表却有 233 条记录!is_permanent 列表示该表中列出的用户状态;如果为 1,则表示该用户被作为实际联系人添加到应用中。其他 231 条记录似乎是我们在搜索联系人时出现的名字,但我们并未与这些人进行过沟通或添加为联系人。 |
Conversations | 我们不清楚 Conversations 和 Chats 之间的区别。它们包含了几乎相同的信息,实际上似乎指向相同的聊天会话。 |
| Messages | 包含每一条来自聊天/对话的单独消息。convo_id 列为每个对话提供唯一的值;任何具有相同 convo_id 值的消息都来自同一对话。author 和 from_dispname 列显示每条消息的作者。时间戳列再次显示消息的日期/时间,采用 Linux 时间戳格式。type 列表示发送的消息类型;以下是我们测试时的值:
-
50: 好友请求
-
51: 请求已接受
-
61: 纯文本消息
-
68: 文件传输
-
30: 通话开始(语音或视频)
-
39: 通话结束(语音或视频)
-
70: 视频消息
body_xml 列包含消息的内容。对于纯文本消息和好友请求,内容就是消息的文字。文件传输显示文件的大小和名称。视频消息则显示它是视频消息,但不提供其他信息。通话记录显示如果通话已接通则显示时长,如果通话未接或被忽略则不显示时长。身份列显示每条消息的发送者,如果是设备上的用户账户发送的消息,可能为空。原因列似乎是用于通话,显示 no_answer 或 busy 来解释为什么通话未接通。
Participants | 与 ChatMembers 类似,显示每个参与聊天/对话的用户。 |
|---|---|
SMSes | 我们的测试没有包括 SMS 消息;然而,这张表中的每一列都是自解释的。 |
Transfers | 显示已传输文件的信息,包括文件名、大小和设备上的路径。partner_dispname 列显示开始文件传输的用户。 |
VideoMessages | 显示视频消息的作者和创建时间戳。请注意,视频消息不会存储在设备上;获取它们的方式将在下文的另一个部分介绍。 |
VoiceMails | 我们的测试没有包括语音邮件;然而,这张表中的每一列看起来都是自解释的。 |
Snapchat 分析
Snapchat 是一款图片分享和文本消息服务,下载量超过 1 亿次。它的标志性特点是,用户发送的图片和视频会在发送者设定的时间限制(1-10 秒)后“自毁”。此外,如果用户截取了图片的屏幕截图,发送者会收到通知。文本聊天没有过期计时器。
包名: com.snapchat.android
相关文件:
-
/cache/stories/received/thumbnail/ -
/sdcard/Android/data/com.snapchat.android/cache/my_media/ -
/shared_prefs/com.snapchat.android_preferences.xml -
/databases/tcspahn.db
/cache/stories/received/thumbnail 包含用户在设备上拍摄的图片的缩略图。/sdcard 路径包含完整尺寸的图片。即使时间限制已过且接收者无法再访问这些图片,它们仍然会保留。这些位置的文件可能没有正确的文件扩展名。
com.snapchat.android_preferences.xml 文件包含用于创建账户的电子邮件地址以及与账户注册的设备的电话号码。
tcspahn.db 数据库包含关于应用程序使用的所有其他信息。
| 表格 | 描述 |
|---|---|
Chat | 列出所有文本聊天。显示发送者、接收者、Linux 时间戳以及消息的文字内容。 |
ContactsOnSnapchat | 显示用户电话簿中也安装了 Snapchat 的所有联系人。isAddedAsFriend 列如果用户已被添加为联系人,则会显示 1。 |
Conversation | 包含每个打开对话的信息。包括发送方和接收方,以及最后发送和接收快照的时间戳(Linux 纪元格式)。 |
Friends | 类似于ContactsOnSnapchat,但仅包括已添加为朋友的用户。包含每个用户添加另一个用户的时间戳。 |
ReceivedSnaps | 接收到的图片和视频的元数据。一旦图片/视频被查看,它似乎在某个时刻从此表中移除。包含每条消息的时间戳、状态、是否截图以及发送方。 |
SentSnaps | 发送的图片和视频的元数据。一旦图片/视频被查看,它似乎在某个时刻从此表中移除。包含每条消息的时间戳、状态和接收方。 |
Viber 分析
Viber 是一款消息和语音/视频通话应用,下载量超过 1 亿。
包名:com.viber.voip
相关文件:
-
/files/preferences/-
activated_sim_serial -
display_name -
reg_viber_phone_num
-
-
/sdcard/viber/media/-
/User Photos/ -
/Viber Images/ -
/Viber Videos/
-
-
/databases/-
viber_data -
viber_messages
-
/files/preferences中的文件包含 SIM 卡的 ICCID、用户在应用中显示的名称以及用于注册应用的电话号码。
/sdcard/viber/media路径中的文件是用户联系人列表中使用 Viber 的人的个人资料照片(无论是否已经在应用中添加为朋友),以及通过该应用发送的所有图片和视频。
viber_data文件是一个数据库,尽管它没有.db文件扩展名。它包含有关用户联系人信息:
| 表格 | 描述 |
|---|---|
calls | 这个表没有填充数据,尽管我们从应用中拨打了电话。 |
phonebookcontact | 从法医角度来看,这个表格可能非常有价值。当 Viber 首次打开时,它会抓取用户的电话簿并将找到的所有条目添加到此数据库中。这意味着它可能包含关于用户联系人历史数据;如果用户稍后从电话簿中删除了某个条目,它可能仍然能在这个数据库中恢复。此表格仅包括电话簿中联系人的姓名。 |
phonebookdata | 类似于电话簿联系人,但还包括设备电话簿中联系人的电子邮件地址和电话号码。 |
vibernumbers | 显示设备电话簿中每个联系人使用 Viber 应用的电话号码。actual_photo中的值对应于/sdcard/viber/media/User/ Photos目录中的文件名。 |
viber_messages文件是一个数据库,尽管它没有.db文件扩展名。它包含关于应用使用的信息:
| 表格 | 描述 |
|---|---|
conversations | 包含每个唯一对话的唯一 ID、接收方和日期。 |
messages | 包含所有对话中的每条单独消息。地址是远程方的电话号码。日期列为 Unix 时间戳格式。类型列对应于消息的方向:1 表示发送消息,0 表示接收消息。如果共享了位置,location_lat 和 location_lng 列将被填充。共享的文件可以附带描述性文字;这些信息在描述列中找到。 |
messages_calls | 这个表格没有被填充,即使我们从应用内进行了通话。 |
participants_info | 包含与用户进行过对话的每个账户的个人资料信息。 |
Tango 分析
Tango 是一款语音/文本/视频消息应用,已在 Play Store 上拥有超过 1 亿次下载。
包名: com.sgiggle.production
这个包名看起来无害,可能会被检查人员误认为是一个游戏。这是每个应用都应该进行分析的原因之一。
感兴趣的文件:
-
/sdcard/Android/data/com.sgiggle.production/files/storage/appdata/-
TCStorageManagerMediaCache_v2/ -
conv_msg_tab_snapshots/
-
-
/files/-
tc.db -
userinfo.xml.db
-
/TCStorageManagerMediaCache_v2 路径在 SD 卡中包含了通过应用发送和接收的图片,以及联系人头像。然而,它也包含了许多从未在应用中查看或使用的图片;这些图片看起来要么是广告图片,要么是可以附加到对话中的表情符号类型的图片。可以通过与 tc.db 关联,找到在对话中使用的具体图片。
conv_msg_tab_snapshots 路径在 SD 卡中包含扩展名为 .dat 的文件。当在十六进制编辑器中查看时,我们能够找到部分明文的对话片段,以及发送和接收的图片路径和 URL。尚不清楚是什么原因导致这些文件的存在,但可能可以从这些文件中恢复在 tc.db 中已删除的内容。
tc.db 数据库是 Tango 用来存储所有消息信息的:
| 表格 | 描述 |
|---|---|
conversations | 每个对话在 conv_id 列中有唯一标识。 |
| messages | 包含通过应用发送和接收的消息。msg_id 列是每条消息的唯一标识,conv_id 列标识消息来自哪个对话。send_time 列标识消息发送或接收的时间,取决于消息的方向。方向列显示消息的方向:1 = 发送,2 = 接收。类型列标识消息的类型;根据我们的测试,类型如下:
-
0: 明文消息
-
1: 视频消息
-
2: 语音消息
-
3: 图片
-
4: 位置/坐标
-
35: 语音通话
-
36: 尝试过的语音通话(双方均未接听)
-
58: 附带的股票图片,例如在
TCStorageManagerMediaCache_v2路径下找到的表情符号
最后,负载列包含了消息的内容……可以这么说。这些数据是 Base64 编码的,下面会详细讨论。|
user_info_xml.db 包含有关账户的元数据,例如用户的姓名和电话号码。然而,它的数据完全是 Base64 编码的,就像 tc.db 中的消息一样。
数据存储方法 6:Base64
解码 Tango 消息
Base64 是一种常用于数据传输的编码方案;它不被视为加密,因为它有一个已知的解码方法,并且不需要唯一的密钥来解码数据。Base64 包含可打印的 ASCII 字符,但底层数据是二进制的(这会使我们的输出稍显杂乱!)。来自 tc.db 中消息表的负载列示例如下:
EhZtQzVtUFVQWmgxWnNRUDJ6aE44cy1nGAAiQldlbGNvbWUgdG8gVGFuZ28hIEhlcmUncyBob3cgdG8gY29ubmVjdCwgZ2V0IHNvY2lhbCwgYW5kIGhhdmUgZnVuIYABAKoBOwoFVGFuZ28SABoWbUM1bVBVUFpoMVpzUVAyemhOOHMtZyILCgcKABIBMRoAEgAqADD///////////8BsAHYioX1rym4AYKAgAjAAQHQAQDoAdC40ELIAgTQAgDqAgc4MDgwODg5yAMA2AMA2AXTHw==
注意我们消息末尾的等号;这是一个强烈的指示符,表明数据是 Base64 编码的。需要被编码的输入必须能够被 3 整除,以便 Base64 背后的数学方法能够正常工作。如果输入不能被 3 整除,它会被填充,导致输出中出现等号。
例如,考虑以下表格:
| 输入字符串 | 字符/字节数 | 输出 |
|---|---|---|
Hello, World | 12 | SGVsbG8sIFdvcmxk |
Hello, World! | 13 | SGVsbG8sIFdvcmxkIQ== |
Hello, World!! | 14 | SGVsbG8sIFdvcmxkISE= |
你可以看到,12 字节的输入(可被 3 整除)没有填充,而另外两个输入则有填充,因为它们不能被 3 整除。这一点很重要,因为它表明,虽然等号是 Base64 的强烈指示符,但没有等号并不意味着它就不是 Base64!
现在我们对 Base64 有了一定了解,并且认识到我们的负载列很可能是以 Base64 编码的,我们需要对其进行解码。有一些网站允许用户粘贴编码后的数据,并将其解密(例如:www.base64decode.org),但对于大量数据来说,这种方式不太方便,因为每条消息必须单独输入(而且在大多数情况下,将证据数据上传到互联网上也是不被推荐的)。同样,也可以在基于 Linux 的系统的命令行中解码,但对于大量数据同样不太方便。我们的解决方案是构建一个 Python 脚本,从数据库中提取 Base64 数据,解码后再写入到一个新文件中:
import sqlite3
import base64
conn = sqlite3.connect('tc.db')
c = conn.cursor()
c.execute('SELECT msg_id, payload FROM messages')
message_tuples = c.fetchall()
with open('tcdb_out.txt', 'w') as f:
for message_id, message in message_tuples:
f.write(str(message_id) + '\x09')
f.write(str(base64.b64decode(message)) + '\r\n')
要运行该代码,只需将此代码粘贴到一个新文件中,命名为 tcdb.py,将脚本与 tc.db 放在同一目录下,然后在命令行中导航到该目录并运行以下命令:
python tcdb.py
脚本将在同一目录下生成名为 tcdb_out.txt 的文件。用文本编辑器打开该文件(或将其导入到 Excel 中作为制表符分隔的文件)将显示 msg_id 值,以便检查员可以将消息与消息表关联,并且解码后的有效载荷显示为明文消息(在数据库中标注为类型 0):
请注意,现在消息内容以明文形式显示,并且前面是会话 ID。输出中还有大量的二进制数据,这很可能是 Tango 使用的元数据或其他信息。如果消息是收到的,用户的姓名也会出现在输出中(这里是 Tango)。
还有其他类型的消息值得查看。这里是视频消息的解码有效载荷条目:
请注意,在视频消息中,我们可以看到两个网址。它们都是公开的,意味着任何拥有链接的人都可以访问它们。以缩略图结尾的 URL 是视频的缩略图,而另一个 URL 将下载完整的视频,格式为 MP4。还显示了 SD 卡路径和图像文件名。
图片和音频消息以非常相似的格式存储,包含查看或下载文件的 URL,以及 SD 卡上的文件路径。
这是一个示例位置消息:
这一次,我们可以看到用户的确切坐标以及地址。同样,SD 卡路径也存在,并将显示该位置的地图视图。与其他消息类型一样,收到的消息也会显示发送者的姓名。
最后,让我们来看一下 userinfo.xml.db 数据库。以下是解码之前它的样子:
我们编写了另一个与第一个非常相似的脚本,用于解析 userinfo.xml.db 数据库:
import sqlite3
import base64
conn = sqlite3.connect('userinfo.xml.db')
c = conn.cursor()
c.execute('SELECT key, value FROM profiles')
key_tuples = c.fetchall()
with open('userinfo_out.txt', 'w') as f:
for key, value in key_tuples:
if value == None:
value = 'Tm9uZQ=='
f.write(str(base64.b64decode(key)) + '\x09')
f.write(str(base64.b64decode(value)) + '\r\n')
唯一的不同之处在于文件名、表名和数值发生了变化,并且这一次数据库中的两列都进行了 base64 编码。再次提醒,可以通过将其放在与 userinfo.xml.db 相同的位置并运行以下命令来执行它:
python userinfo.py
这是结果文件中相关部分的输出,显示了用户用于注册帐户的个人数据:
在输出的进一步部分,还有一个列表,列出了所有使用 Tango 的用户联系人,包括联系人的姓名和电话号码。
WhatsApp 分析
WhatsApp 是一款流行的聊天/视频消息服务,在 Google Play 上已有超过 5 亿次下载。
包名: com.whatsapp
感兴趣的文件:
-
/files/-
Avatars/ -
me -
me.jpeg
-
-
/shared_prefs/-
RegisterPhone.xml -
`VerifySMS.xml`
-
-
/databases/-
msgstore.db -
wa.db
-
-
/sdcard/WhatsApp/-
Media/ -
Databases/
-
/files/avatars 目录包含使用该应用程序的联系人头像的缩略图,而 me.jpg 是用户头像的全尺寸版本。该 me 文件包含与账户关联的电话号码。
与账户关联的电话号码也可以在 /shared_prefs/RegisterPhone.xml 中恢复。/shared_prefs/VerifySMS.xml 文件显示账户验证的时间(当然是 Unix 纪元格式),指示用户首次开始使用该应用的时间。
msgstore.db 数据库,顾名思义,包含消息数据:
| 表格 | 描述 |
|---|---|
chat_list | key_remote_jid 列显示用户与之沟通过的每个账户;表中的值是远程用户的电话号码。例如,如果值是 13218675309@s.whatsapp.net,那么远程用户的号码就是 1-321-867-5309。 |
group_participants | 包含群聊的元数据。 |
messages | 显示所有消息数据。再次强调,key_remote_jid 字段标识远程发送者。key_from_me 值表示消息的方向(0=接收,1=发送)。数据列包含消息文本,时间戳是发送或接收的时间,采用 Linux 纪元格式。对于附件,media_mime_type 标识文件格式;media_size 和 media_name 列应该不言而喻。如果附件有标题,文本将显示在 media_caption 列中。如果附件是位置,纬度和经度列将相应填充。thumb_image 列包含大量无用数据,但也包含设备上附件的路径。raw_data 列包含图片和视频的缩略图。 |
wa.db 数据库用于存储联系人信息:
| 表格 | 描述 |
|---|---|
wa_contacts | 和其他应用一样,WhatsApp 会抓取并存储用户的整个电话簿,并将信息存储在自己的数据库中。它包含联系人的姓名和电话号码,以及该联系人是否是 WhatsApp 用户的状态。 |
SD 卡是 WhatsApp 数据的宝藏。/sdcard/WhatsApp/Media 文件夹包含每种类型媒体的文件夹(音频、通话、图片、视频和语音笔记),并将该类型的所有附件存储在该文件夹中。发送的媒体存储在一个名为 Sent 的目录中。接收的媒体则直接存储在文件夹的根目录下。
Databases 目录是一个更大的信息源。WhatsApp 每晚都会备份 msgstore.db,并将备份存储在这里。这使得检查人员能够查看可能已被删除的历史数据;如果我今天删除了一条聊天记录,但你查看昨天的备份,你将能够访问我删除的数据。该应用程序甚至贴心地将日期包含在文件名中,例如:msgstore-2018-12-12.1.db.crypt12。唯一的问题是这些备份是加密的!
解密 WhatsApp 备份
幸运的是,现有工具可以用来解密备份。它可以在此找到,并附有详细的说明:andreas-mausch.de/whatsapp-viewer/。WhatsApp Viewer 可以用来解密不同版本的加密 WhatsApp 数据库。在此示例中,我们将解密其最新版本.crypt12:
-
转到文件 | 解密 .crypt12….
-
选择加密的数据库文件和密钥文件(可以在
/files目录中找到):
- 点击“解密…”按钮并选择解密后的数据库文件位置。
数据存储方式 7:加密文件
Kik 分析
Kik 是一个即时通讯应用,已在 Play 商店下载超过 1 亿次。
包名:kik.android
感兴趣的文件:
-
/cache/-
chatPicsBig/ -
contentpics/ -
profPics/
-
-
/files/staging/thumbs -
/shared_prefs/KikPreferences.xml -
/sdcard/Kik/ -
/databases/kikDatabase.db
/cache中的chatPicsBig和contentpics目录包含在应用中发送和接收的图像。contentpics中的文件包含看似嵌入在图像之前的Kik元数据;JPG 文件必须从这些文件中提取出来。在我们的测试中,contentpics中的所有文件也存储在chatPicsBig中,尽管随着应用使用的增加,情况可能会发生变化。用户的个人资料图片位于/profPics目录中。
数据存储方式 8:基本隐写术;一个文件存储在一个更大的文件中。
/files/staging/thumbs目录包含发送和接收图像的缩略图;我们的测试发现该位置的图像与/cache目录中的图像相同,但同样地,随着应用使用的增加,情况可能会有所不同。
/shared_prefs中的KikPreferences.xml文件显示了用户在应用中使用的用户名和电子邮件地址。有趣的是,它还包含用户密码的未加盐 SHA1 哈希值。
/sdcard/Kik目录包含在应用中发送和接收的全尺寸图像。文件名可以与kikDatabase.db messagesTable中的数据进行关联,以识别包含图像的消息。
kikDatabase.db数据库包含来自应用的所有消息数据:
| 表格 | 描述 |
|---|---|
KIKContentTable | 该表格包含已发送和接收图像的元数据。每条消息都分配有一个唯一的content_id值,该值与sdcard/Kik目录中的文件名相对应。每张图像的预览和图标值对应于/files/staging/thumbs中的文件名。每张图像还包含一个file-url值;这是一个公共 URL,可以用来查看该文件。 |
KIKcontactsTable | 该表显示了每个联系人对应的user_name和display_name。in_roster值似乎是为用户明确添加的联系人设置的(如果值为1);in_roster值为 0 的联系人似乎是自动添加的。jid列是每个联系人的唯一值。 |
messagesTable | 该表包含了通过应用发送和接收的所有消息数据。body列显示了消息中发送的文本数据。partner_jid值可以与KIKcontactTable中的jid列关联,识别远程用户。was_me列用于表示消息的方向(0 = 发送,1 = 接收)。read_state列显示消息是否已读(500 = 已读,400 = 未读)。时间戳仍然以 Linux 纪元格式表示。content_id列填充了消息附件,可以与KIKContentTable关联以获取更多信息。 |
微信分析
微信是一款在 Play 商店下载超过 1 亿次的消息应用。
包名:com.tencent.mm
请注意,这些路径中有些包含星号(*)。这表示一个唯一的字符串,每个账户都会不同。我们的设备在星号位置使用了7f804fdbf79ba9e34e5359fc5df7f1eb。
关注的文件:
-
/files/host/*.getdns2 -
/shared_prefs/-
com.tencent.mm_preferences.xml -
system_config_prefs.xml
-
-
/sdcard/tencent/MicroMsg/-
diskcache/ -
WeChat/
-
-
/sdcard/tencent/MicroMsg/*/-
image2/ -
video/ -
voice2/
-
-
/MicroMsg/-
CompatibleInfo.cfg -
*/EnMicroMsg.db
-
在/files/host中找到的*.getdns2文件可以作为文本文件或十六进制编辑器打开。文件中有一个名为[clientip]的部分,显示了用户连接的 IP 地址以及连接时间(以 Linux 纪元格式表示)。我们的设备包含了三个这样的文件,显示了三次不同的连接,但随着应用使用量的增加,可能会生成超过三个这样的文件。
/shared_prefs中的com.tencent.mm_preferences.xml文件记录了设备的电话号码,在login_user_name字段中。system_config_prefs.xml文件包含了用户设备上个人资料图片的路径,以及稍后需要的default_uin值。
SD 卡包含了大量的微信数据。/tencent/MicroMsg/diskcache目录中包含了一张从未在应用中使用过的图片;我们认为它是在附加另一张图片时放入的,因为微信会加载设备图库中的许多图片。/WeChat目录位于/sdcard/tencent/MicroMsg中,包含了从设备发送的图片。
/sdcard/tencent/MicroMsg/*中的/video、/voice和/voice2文件夹包含了它们所说的内容:通过应用发送的视频和语音文件。
微信的一个独特之处在于,它并不使用应用程序目录结构中的/databases目录;MicroMsg目录充当其等效物。CompatibleInfo.cfg包含设备的 IMEI,稍后会用到。
/MicroMsg目录中的*文件夹包含EnMicroMsg.db数据库。只有一个问题:该数据库是使用 SQLCipher 加密的!SQLCipher 是一个开源的 SQLite 扩展,能够加密整个数据库。幸运的是,与其他使用加密的应用一样,解密该文件的密钥存储在设备上。
数据存储方法 9:SQLCipher,完整的数据库加密
解密微信的 EnMicroMsg.db
幸运的是,Forensic Focus 网站有一篇非常好的文章,正是讲如何完成这项操作:articles.forensicfocus.com/2014/10/01/decrypt-wechat-enmicromsgdb-database/。
他们甚至提供了一个 Python 脚本来帮我们完成这项工作:gist.github.com/fauzimd/8cb0ca85ecaa923df828/download#。
要运行 Python 脚本,只需将EnMicroMsg.db文件和system_config_prefs.xml文件放在与脚本相同的目录下,然后在命令行中输入以下内容:
python fmd_wechatdecipher.py
脚本接下来会提示你输入设备的 IMEI。这可以在/MicroMsg/CompatibleInfo.cfg文件中找到,或者在设备上某个地方打印出来(如电池后面、SIM 卡托上,或设备背面刻印的位置),或者通过在键盘上输入*#06#来获取。
脚本应能正常运行,并在目录中生成一个名为EnMicroMsg-decrypted.db的文件。
现在我们可以检查EnMicroMsg-decrypted.db了:
| 表格 | 描述 |
|---|---|
ImgInfo2 | 包含发送和接收图像的路径信息。bigImgPath列包含图像的文件名;可以在 SD 卡上搜索该文件名来找到图像。或者,图像会存储在/sdcard/tencent/MicroMsg/*/image2目录下的文件夹中,文件夹名称与文件名相对应。例如,3b9edb119e04869ecd7d1b21a10aa59f.jpg文件可以在/3b/9e路径下的image2目录中找到。文件夹按文件名的前两个字节、然后是接下来的两个字节进行划分。thumbImgPath列包含图像缩略图的名称。 |
message | 包含应用程序的所有消息信息。isSend列表示消息的方向(0 = 接收,1 = 发送)。createTime列是消息的时间戳,采用 Linux 纪元格式。talker 列包含远程用户的唯一 ID,可以与rcontact表相关联来识别远程用户。content 列显示作为文本发送的消息数据,视频通话则标识为voip_content_voice。imgPath包含图片缩略图的路径,可以与ImgInfo2表相关联,以定位完整大小的图片。它还包括音频文件的文件名,可以在/sdcard/tencent/MicroMsg/*/voice2目录中搜索或找到。 |
rcontact | 包含联系人列表,并包括许多应用程序默认添加的联系人。用户名可以与消息表中的 talker 列相关联。昵称列显示用户的名称。类型列是一个指示联系人是手动添加还是自动添加的标志(1 = 设备用户,3 = 用户添加,33 = 应用程序添加)。例外情况是weixin用户,该用户是自动添加的,但类型值为 3。 |
userinfo | 该表包含用户信息,包括姓名和电话号码。 |
总结
本章深入研究了特定的安卓应用程序,以及它们如何/在哪里存储数据。我们研究了 19 个特定的应用程序,发现了 9 种不同的数据存储和混淆方法。知道应用程序以多种方式存储数据应该能帮助检查员更好地理解他们正在检查的数据,并希望在找不到他们期望应用程序有的数据时,促使他们更加仔细地寻找。检查员必须能够适应不断变化的应用程序分析世界;由于应用程序不断更新,检查员必须能够更新自己的方法和能力,以跟上步伐。
下一章将介绍几款免费的/开源的和商业的工具,用于镜像和分析安卓设备。
第八章:Android 取证工具概述
本章概述了免费/开源和商业的 Android 取证工具,并将展示如何使用这些工具处理常见的调查场景。在本章结束时,读者应熟悉以下工具:
-
Autopsy
-
Belkasoft 证据中心
-
Magnet AXIOM
Autopsy
Autopsy 是一个免费且开源的分析工具,最初由 Brian Carrier 开发。Autopsy 作为底层基于 Linux 的 SleuthKit 工具集的图形用户界面开始,但自版本 3 起,它已成为一款独立的 Windows 工具。Autopsy 可以从www.sleuthkit.org/autopsy/下载。
Autopsy 并不用于进行移动设备的获取,但可以分析大多数常见的 Android 文件系统(如 YAFFS 和 EXT)。在这个例子中,我们将加载通过dd从三星 Galaxy J7 获取的完整物理镜像。
在 Autopsy 中创建案件
打开 Autopsy 后,用户将被提示创建新案件、打开最近的案件或打开案件:
我们将创建一个新案件。请按照以下步骤操作:
- 填写完案件名称字段后,下一步按钮将变为可用:
- 可选的案件编号和检查员信息可以输入:
- 选择“完成”后,将显示选择要添加的数据源类型的屏幕。选择虚拟机文件的磁盘镜像选项:
- 点击“下一步”并使用浏览按钮选择要加载的镜像文件:
- 点击“下一步”按钮,进入配置导入模块向导:
导入模块是 Autopsy 内置的工具,可以在案件启动时运行,或者在之后的任何时间运行。以下是该版本 Autopsy 中的默认模块:
-
最近活动:提取最近的用户活动,如网页浏览、最近使用的文档和已安装的程序。
-
哈希查找:使用提供的哈希数据库识别已知和显著的文件,如标准 NSRL 数据库。允许我们导入自定义哈希数据库。
-
文件类型识别:根据二进制签名匹配文件类型。
-
嵌入式文件提取器:提取嵌入式文件(ZIP, RAR, DOCX, XLSX)。自动提取这些文件类型并将其内容放入目录树中。
-
退出解析器:导入 JPEG 文件并检索其 EXIF 元数据。
-
关键词搜索:使用关键词和正则表达式在列表中进行文件索引和定期搜索。允许加载自定义关键词/列表。
-
电子邮件解析器:此模块检测并解析 Mbox 和 PST/OST 文件,并在黑板中填充电子邮件证据。
-
扩展名不匹配检测器:标记具有非标准扩展名的文件,基于其文件类型。
-
E01 验证器:验证 E01 文件的完整性。
-
加密探测器:查找具有指定最小熵的文件。
-
有趣文件标识符:根据有趣项目规则集识别有趣的项目。
-
PhotoRec 切割器:使用 PhotoRec 从数据源中切割未分配的空间。
-
关联引擎:将属性保存到中央存储库以供后续分析。
-
虚拟机提取器:提取虚拟机文件并将其添加到案件中。
-
Android 分析器:提取 Android 系统和第三方应用程序数据。
请注意,许多这些模块在 Android 设备上是不需要的(例如 E01 验证器和电子邮件解析器)。仅选择有用的模块可以加快数据导入速度。还要注意,点击模块可能会显示更多选项。
- 点击 下一步 将加载数据源并开始导入过程。遇到的任何错误都将被记录:
- 选择“完成”将带领检查员进入主屏幕,以便分析已导入的案件:
在 Autopsy 中分析数据
即使案件仍在加载中,数据导入模块正在运行(如上图右下角的进度条所示),检查员也可以开始分析案件。通过扩展左上角的图像文件,可以显示 Autopsy 识别的分区/卷:
Autopsy 识别了我们设备上的 28 个分区。为了找到数据分区(因为我们知道大部分感兴趣的数据都存储在那里),我们可以简单地展开已分配的分区,直到找到看起来像数据分区的那个:
在我们的图像中,第 27 卷是数据分区。我们可以看到它有一个 app 目录(存储 APK 文件的地方)、一个 data 目录(存储应用程序数据的地方)以及一个 media 目录(SD 卡的符号链接位置)。
展开 data 目录将显示我们应该从第七章 Android 应用程序的法医分析中记住的信息:
立刻,我们可以看到 com.android.providers.telephony 和 userdictionary。如何分析这些应用程序的内容,请参阅第七章,Android 应用程序的法医分析;这就是如何使用 Autopsy 访问相关文件。例如,展开 com.android.providers.telephony 将显示用于分析 SMS 和 MMS 数据的 mmssms.db 文件:
“应用程序”标签让检查员在内置查看器中查看 SQLite 数据库:
现在,让我们来看看 Autopsy 的其他功能。在屏幕左侧展开“视图”部分将显示一些使用的获取模块的结果:
文件类型视图展示了由文件类型识别模块识别的文件。最近文件显示了来自最近活动模块的结果;在这种情况下,设备似乎已经六天没有使用,然后在最后一天被使用。查看这里识别的文件可以显示用户在该时间段内的活动。请注意红色的 X,它表示这些文件中的一些已被删除,但被 Autopsy 恢复了:
在我们的案例中,我们可以看到downloads.db和EmailProvider.db数据库已被修改。分析这些文件会显示一封带附件的电子邮件被接收,附件随后被下载到设备上。
最后,视图部分识别了已删除的文件(这些文件在移动设备上非常常见,因磨损均衡而被删除),以及大文件(这些文件有助于快速找到图像/视频,或识别隐写术)。
结果部分将显示来自Android 分析器和关键字搜索模块的输出:
在提取内容下看到的 Android 分析结果大多符合预期。值得注意的是,**联系人(1)**部分只指向 contacts.db 文件,并没有实际解析其中的数据。例如,通话记录显示了从contacts2.db提取的数据,如第七章中所述,安卓应用的取证分析:
检测到扩展名不匹配的结果还显示了我们在第七章中发现的数据,安卓应用的取证分析。有几个应用程序被描述为具有.cnt文件,而这些文件实际上是 JPEG 图像,这些文件被 Autopsy 正确识别:
双击任何一个文件将带用户到文件在文件系统中找到的位置。
关键字命中部分正确地找到了许多电子邮件地址和电话号码,但其中许多是在应用程序文件中找到的(即应用程序开发者的联系信息)以及其他并非由用户实际存储的地方(这在移动和计算机取证工具中非常常见)。
Autopsy 还有许多更高级的功能,这里没有涵盖;要了解更多,基础技术提供了一个 Autopsy 培训课程:www.autopsy.com/training/。
Belkasoft 证据中心
Belkasoft Evidence Center 是一个商业数字取证产品,允许检查员从不同来源获取、处理和分析数据,包括移动设备,如 Android 智能手机和平板电脑。
该产品的试用版可以从belkasoft.com/get下载。
在 Belkasoft Evidence Center 中创建案件
要开始在 BEC 中创建新案件,请执行以下步骤:
-
点击新建案件按钮,填写以下字段:
-
案件名称:案件名称或编号。
-
根文件夹:存储所有案件数据的文件夹。
-
案件文件夹:当前案件数据存储的文件夹。
-
调查员:检查员的姓名。
-
时区:显示时间戳时使用的时区(推荐使用 UTC)。
-
描述:案件概述:
-
- 创建并打开按钮将带你进入下一个窗口,即添加数据源窗口:
Belkasoft 提供了带有产品的测试镜像,因此我们可以使用一个 Android 备份进行演示。当然,也可以使用自己的镜像,包括逻辑镜像和物理镜像。如果你没有镜像,但想获取一个,可以在获取与分析部分选择移动设备选项:
- 由于我们决定使用提供的 Android 备份,因此可以直接点击下一步并选择要从中提取的工件:
一个好的策略是只选择与 Android 相关的工件,但有时选择更多的工件可能会带来更好的结果,所以如果你有足够的时间,可以选择所有类型的工件来处理镜像。
由于我们处理的是逻辑镜像,因此雕刻选项不可用。使用物理镜像时,该选项可用,因此检查员可以使用数据雕刻来恢复和提取更多数据。
- 点击完成按钮将初始化镜像处理过程。如果案件只有一个镜像,请在最后一个窗口点击否按钮:
在 Belkasoft Evidence Center 中分析数据
BEC 的不同功能分布在多个标签页中。我们先来看一些,首先是案件浏览器:
这里显示的是处理后提取的工件数量,在我们的案例中是 210 个。实际数据可以在右侧窗格查看。有多种视图选项:你可以查看项目的属性,或者以常规形式或十六进制形式查看它。BEC 还拥有一个强大的SQLite 浏览器,支持从预写日志(WAL)中提取数据,并从空闲列表和未分配空间中恢复已删除记录。
另一个有用的标签是时间线:
这对于 Android 恶意软件调查特别有用。你可以轻松找到恶意应用安装前发生的事情,例如,用户收到一条带有该应用链接的可疑短信,点击后用网页浏览器下载了该应用。当然,这也可以用于常规案件,例如,如果你需要了解用户在特定时间段内使用手机时做了什么。
最后,如果需要,你可以执行手动文件系统分析。在下一张截图中,你可以看到一个包含应用数据的文件夹内容:
如果你想使用关键词进行数据搜索,搜索结果标签也会非常有用,因为它是存放关键词搜索命中的地方。要在工件中进行搜索,你可以按Ctrl + F,点击主工具栏上的搜索图标,或者选择编辑主菜单中的**搜索...**选项。进行搜索时,你可以使用单个单词或短语、关键词列表、正则表达式,或者预定义的搜索,比如adult sites。
Magnet AXIOM
Magnet AXIOM 是另一款强大的商业数字取证产品,能够获取、处理和分析移动设备,包括运行 Android 操作系统的设备。
本产品的试用版可以从www.magnetforensics.com/try-magnet-axiom-free-30-days/下载。
在 Magnet AXIOM 中创建案件
要在 Magnet AXIOM 中创建案件,请执行以下步骤:
- 启动 AXIOM 进程并点击创建新案件按钮:
- 第一个窗口是案件详情;在这里,我们需要填写一些字段,如案件编号、类型、案件文件路径和已获取的数据:
- 证据来源窗口允许检查员选择数据源或直接从设备获取镜像:
- 为了演示,我们将使用三星智能手机的实物图片,因此请选择ANDROID选项:
- 由于我们决定使用一个预制的镜像,选择加载证据选项:
如果你想使用 Magnet AXIOM 创建一个镜像并进行处理,你可以选择获取证据选项。
- 由于我们使用的是镜像,在下一步中选择镜像选项:
现在我们可以看到,我们的证据源已添加到案件中:
让我们继续进行并配置处理细节:
-
添加关键词以进行搜索:你可以在处理开始之前添加关键词搜索词,甚至可以添加列表,这样你就能在 AXIOM Examine 的关键词过滤器下找到相关内容。
-
MAGNET.AI 聊天分类:AXIOM 使用内置类别对聊天记录进行分类,因此它可以通过机器学习自动从数千条消息中提取有用的证据。
-
搜索存档和手机备份:此选项对于计算机取证特别有用;如果 AXIOM 找到存档或手机备份,它会处理并将其数据添加到案件中。
-
计算哈希值:你可以导入哈希集以排除已知的好文件:
-
分类图片和视频:允许检查员使用来自 Project VIC 和 CAID 的已知媒体文件哈希集或 JSON 文件。
-
将 CPS 数据添加到搜索中:允许检查员导入并使用 儿童保护系统 (CPS) 网站的数据。
-
查找更多证据:允许检查员使用动态应用查找器查找当前不受产品支持的应用数据:
- 选择检查员希望提取的证据。由于我们的源是 Android 镜像,我们选择了所有移动设备证据:
当然,如果需要,证据列表是可以定制的:
现在我们准备开始图像处理:
AXIOM 检查窗口将自动打开,因此你可以在处理阶段开始分析。AXIOM 处理窗口仍然很有用,你可以监控处理进度。
在 Magnet AXIOM 中分析数据
案例仪表盘标签将为你提供 AXIOM 处理从数据源中提取的证据概览——在我们的案例中,共提取了42,156个证据:
案例仪表盘标签
要更详细地查看提取的数据,让我们进入 证据 查看器,你可以从下拉菜单中选择它(点击 案例仪表盘):
所以我们有相当多的证据,例如 230 个移动设备证据。它们是什么?让我们学习一下:
如你所见,AXIOM 提取了关于用户账户、通话记录、Wi-Fi 配置文件、Google Play 搜索记录和已安装应用的信息。
如果你更喜欢手动分析,可以使用 文件系统 查看器。你可以在以下截图中看到包含应用数据的文件夹:
这个查看器拥有进行手动分析所需的一切,包括 SQLite 浏览器和十六进制查看器。
总结
本章概述了几款可供 Android 法医检查员使用的免费和商业工具。当然,市场上还有更多商业工具,但我们选择了 Belkasoft Evidence Center 和 Magnet AXIOM,因为它们都有适用于每个人的试用版。
当然,解决一个案例并不总是需要复杂的工具,有时候你只需要一个好的 SQLite 浏览器,甚至是一个十六进制查看器。
下一章将向你介绍 Android 恶意软件,并带你了解一些识别其的方法。
第九章:识别安卓恶意软件
识别恶意软件是许多安卓取证检查中的典型任务。本章将首先介绍最常见的安卓恶意软件类型概述,然后带你了解使用不同方法识别安卓设备中的恶意软件的过程。
本章将涵盖以下主题:
-
安卓恶意软件简介
-
安卓恶意软件概述
-
识别安卓恶意软件
安卓恶意软件简介
如今,恶意程序在任何操作系统上都很常见,移动设备也不例外。即使是像运行 iOS 的设备、iPhone 和 iPad 这样的安全设备,也可能会感染恶意软件。一个很好的例子是Pegasus间谍软件,它在 2016 年被用于攻击阿拉伯人权捍卫者 Ahmed Mansoor。它能够越狱目标设备并植入间谍软件,从而使攻击者能够读取受害者的消息、追踪电话、收集密码、定位手机,并从不同的应用程序收集信息。
如果我们谈论安卓系统,情况更为严重。从不受信任的来源安装应用程序更容易,这使得安卓成为受恶意软件影响最严重的移动平台。更重要的是,安全研究人员经常在 Google Play 商店发现大量恶意软件样本!一个很好的例子是Android Grabos运动,它是在 2017 年底/2018 年初由 McAfee 发现的。这个运动将不需要的应用推送给毫无防备的用户——这通常被称为按下载付费骗局。安全研究人员发现并从 Google Play 中移除了 144 个应用程序。但在它们被移除之前,全球约有 1750 万台智能手机设备已经下载了这些应用。
现在让我们进一步了解最常见的安卓恶意软件类型。
安卓恶意软件概述
如你所知,不同类型的恶意软件有不同的目标,因此它们的功能也各不相同。一些恶意程序会监视受害者并试图窃取应用数据,例如短信和电子邮件,而另一些则仅仅是向用户显示不需要的广告。本节将向你介绍最常见的安卓恶意软件类型。
银行恶意软件
银行恶意软件是安卓平台上最常见的恶意软件之一。它可以伪装成假冒银行应用程序来窃取用户输入的银行信息,或者作为一个第三方应用从真实的银行应用中窃取信息。此外,银行木马通常可以拦截银行交易,并执行典型的间谍软件行为,例如发送、删除和拦截短信,以及键盘记录。一些银行木马甚至具有更高级的功能。一个很好的例子是MysteryBot——它还可以从受感染设备发送垃圾邮件,并具备勒索软件功能。
间谍软件
间谍软件监视、记录并将目标设备的重要信息发送到攻击者的服务器。这些信息可能包括短信消息、录音电话、截屏、按键记录、电子邮件或可能对攻击者感兴趣的任何其他应用程序数据。一个有趣的例子是 BusyGasper,由卡巴斯基实验室专家于 2018 年初发现。它不仅具有收集来自 WhatsApp、Viber 和 Facebook 等流行消息应用程序的信息的常见间谍软件功能,还具有设备传感器监听器,包括运动检测器。
广告软件
广告软件是另一种在 Android 设备上非常常见的恶意或不需要的应用程序类型。它相对容易检测,因为受害者会在其设备屏幕上接收持续的弹出窗口和广告。这些不受欢迎的程序并不总是无害的,因为弹出窗口可能导致下载另一种恶意软件,包括已提到的间谍软件和银行木马。
勒索软件
当然,勒索软件的主要目标是桌面 Windows 计算机和服务器,但它也存在于移动平台上,尤其是 Android。通常,它只锁定设备屏幕并附上勒索信息,但有时也会加密用户的数据。一个很好的例子是 2017 年针对中国 Android 用户的 WannaLocker 勒索软件,它使用 AES 加密用户的文件,除了其路径名以 . 开头和包含 DCIM、download、miad、android 和 com 的文件。
加密货币挖掘恶意软件
加密货币现在非常流行,因此这种类型的恶意程序甚至适用于 Android 等移动平台。此类应用程序的目标是使用受害者设备的计算能力来挖掘加密货币,例如 Monero。有时,这种类型的恶意软件甚至会使智能手机硬件处于风险之中。例如,具有加密货币挖掘功能的木马 Loapi 会让受害者的手机工作得非常辛苦,以至于其电池在不到 48 小时内膨胀!
下一节将指导您识别 Android 设备上的恶意应用程序。
Android 恶意软件识别
本节将指导您如何使用防病毒扫描器、VirusTotal 和 YARA 规则在取证镜像中识别 Android 恶意软件的过程。
使用防病毒扫描器在 Android 设备上识别恶意软件
使用防病毒扫描器是查找已知恶意软件的典型方法,因此这是选择低 hanging fruit 的推荐第一步。有许多防病毒扫描器,其中许多都有免费版本,移动取证检查员可以使用这些版本完成这些任务。其中大多数是基于 Windows 的,因此第一步是挂载先前创建的物理镜像,以便操作系统和防病毒扫描器可以访问它。
如你所知,大多数 Android 设备使用 EXT4 作为文件系统,尤其是从取证角度来看最有趣的分区——userdata 分区。默认情况下,Windows 不支持这种文件系统,因此我们需要一个第三方工具来挂载它,更重要的是,必须以只读模式进行挂载,因为我们不希望防病毒扫描器删除我们将要检查的镜像中的任何内容。
当然,取证检查员有这样的工具可以使用。它叫做Linux 文件系统 for Windows,其试用版可以在此下载:www.paragon-drivers.com/en/lfswin/。安装后,你就可以开始挂载 userdata 分区了。你需要 FTK Imager,但应该已经安装了它,因为我们在前面的章节中使用过它。以下是在 Windows 主机上挂载 ext4 分区的两步简单操作:
- 打开 FTK Imager,点击文件|映像挂载...
AccessData FTK Imager
- 选择镜像文件。在我们的例子中,它是一个 Android 9 userdata 分区的物理镜像。选择物理与逻辑作为挂载类型,选择块设备 / 只读作为挂载方式,然后点击挂载按钮:
使用 FTK Imager 挂载 EXT4 镜像
就这样!现在文件系统作为逻辑磁盘E:在我们的 Windows 10 主机上可用了:
Windows 资源管理器中挂载的文件系统的一部分
现在可以使用防病毒扫描器轻松扫描它。通常,用户安装的应用程序可以在/data/app目录下找到,因此,开始我们的恶意软件检测时扫描这个文件夹可能是一个非常好的主意。对于本例,我们将使用 ESET NOD32 防病毒软件(www.eset.com/int/home/antivirus/)。从取证的角度来看,它有一个非常有趣的选项——扫描不清除。这使得检查人员能够找到恶意软件,但不会删除或隔离它。要选择此选项,右键点击你选择的文件夹,然后进入高级选项。在我们的例子中,扫描只用了几秒钟,结果显示出了两个恶意对象:
防病毒扫描日志
如你所见,有时候,尤其是如果你知道在哪里查找,使用防病毒引擎可以非常快速、轻松地找到 Android 恶意软件。当然,你使用的软件可能没有包含相应的签名,可能会漏掉恶意应用程序,因此强烈建议使用多个引擎进行扫描。
使用 VirusTotal 识别 Android 恶意软件
VirusTotal 是一个免费的服务,可以用来分析可疑的文件和 URL 是否包含恶意软件。如你所见,Android 应用程序的文件扩展名为 .apk,所以如果你发现一个可疑文件,你可能会想把它上传到 VirusTotal,检查它是否真的是恶意的。为什么这比使用杀毒软件扫描更好?因为它会使用至少 55 个杀毒引擎扫描你的文件!更重要的是,你可能不希望将真实案例中的文件上传到互联网上,但这不是问题,因为你可以通过文件的哈希值 MD5、SHA1 或 SHA256 来查找已经上传的文件。此服务可以在这里使用:www.virustotal.com。
我们已经在 Android 9 镜像中发现了两个恶意文件,因此让我们将其中一个文件上传到 VirusTotal,看看它是如何被其他杀毒引擎检测到的。使用你选择的网页浏览器访问 VirusTotal,然后点击“选择文件”按钮:
VirusTotal 界面
如果文件的哈希值已经在数据库中,你将立即被重定向到包含结果的页面;如果没有,系统将需要一些时间来扫描该文件。在我们的例子中,文件的哈希值已立即找到,我们看到了结果:
VirusTotal 扫描结果
如你所见,我们的恶意软件样本已经被 56 个杀毒引擎中的 29 个检测到——表现还不错。但如果我们不想上传我们的样本呢?如前所述,你可以使用哈希值在 VirusTotal 上查找恶意文件。
若要获取可疑文件的哈希值,你可以使用 Eric Zimmerman 提供的免费工具 Hasher,该工具可在 ericzimmerman.github.io 上下载。接下来请按照以下步骤操作:
-
启动工具,进入工具 - 选项,选择哈希算法。在我们的案例中,我们选择了 MD5 和 SHA256。
-
要选择你想要哈希的文件,进入文件 - 选择文件,或者按 Alt + 1。你将在主窗口看到结果:
哈希值结果
要复制哈希值,点击相应字段并按 Alt + C。现在你可以前往 VirusTotal,点击搜索标签,并粘贴哈希值:
使用哈希值在 VirusTotal 上搜索
由于我们使用的是已经由 VirusTotal 扫描过的文件的 SHA256 哈希值,我们将被重定向到相同的页面。但即使我们没有上传文件,由于该文件已经被第三方上传,我们也能获得结果。
有时候,你需要扫描一大堆文件,逐个上传可能会很麻烦。为了自动上传一堆文件,你可以使用 VirusTotal Uploader,该工具可以在这里下载:support.virustotal.com/hc/en-us/articles/115002179065-Desktop-Apps。
要上传一个文件或多个文件,请单击“选择文件”并上传:
VirusTotal 上传工具界面
为了演示目的,让我们上传我们已经识别的第二个恶意文件。它的哈希值也被找到了,所以工具立即打开了包含扫描结果的浏览器选项卡:
VirusTotal 扫描结果
这个文件的检测结果更好 —— 60 个引擎中有 34 个。但如果文件没有被任何防病毒引擎检测到,因为没有对应的签名,法医检查员该怎么办呢?使用 YARA 编写您自己的规则吧!您将在接下来的章节中学习如何做到这一点。
使用 YARA 规则进行 Android 恶意软件识别
根据官方文档(可在yara.readthedocs.io/en/v3.8.1/找到),YARA 是一个旨在帮助恶意软件研究人员(当然也包括计算机和移动设备的法医检查员)识别和分类恶意软件样本的工具。
借助 YARA 的帮助,检查员可以基于文本或二进制模式编写规则。这里是这样一个规则的示例:
rule test_rule
{
meta:
description = "Test YARA rule"
author = "Oleg Skulkin"
strings:
$string = "teststring"
condition:
$string
}
此规则将检测包含teststring字符串的任何文件。让我们仔细看看规则的主要部分:
-
meta:此部分包含规则的元数据,例如它确切地检测到什么以及谁编写了它。它甚至可能不包含在规则中。 -
strings:这些是您的恶意软件样本必须包含的字符串,以便进行检测。您可以使用多个字符串或甚至二进制模式。字符串可以区分大小写,也可以是 ASCII 格式或宽字符形式(两个字节用于编码一个字符),或者两者兼有。 -
condition:这部分包含一个布尔表达式,告诉我们在什么情况下文件满足规则。它可以是在strings部分定义的所有字符串,也可以是其中有限数量的字符串。
让我们编写一个 YARA 规则来检测我们在前几节已经识别的恶意软件。首先,我们必须找到唯一的字符串。为了能够做到这一点,让我们使用 Eric Zimmerman 的另一个法庭工具 bstrings:ericzimmerman.github.io/。
这是一个命令行工具,因此您必须从 Windows 命令提示符中运行它。使用-f开关指定要从中提取字符串的文件:
使用 bstrings 从 APK 文件中提取字符串
从一开始就出现了一个有趣的字符串 —— com.example.horsenjnj。但我们如何确定它是否是唯一的呢?一个好主意是在 Google 或其他可用的搜索引擎中搜索这个字符串:
谷歌搜索结果
正如您所见,只有一个搜索结果,这使我们找到的字符串变得独特。而且,如果我们点击链接,它将带我们到我们在前一部分已经看过的 VirusTotal 页面。
如果我们滚动字符串的输出,我们会发现更多有趣的字符串,例如 res/xml/shit.xml—这个名称并不是应用程序资源中的常见 XML 文件名称。
让我们用我们发现的两个字符串编写一个 YARA 规则来检测我们的恶意软件样本。如您从前面的章节中记得,大多数杀毒引擎将其检测为 Android Banker,所以我们将我们的规则命名为 android_banker。同样可以在描述中写出—检测 Android Banker;我们会将其添加到 meta 部分。我们有两个字符串供规则使用。由于我们不知道它们的编码方式,我们可以在它们后面添加 ascii wide。最后一部分—条件(将被规则检测到的文件)必须包含这两个字符串,因此我们将使用 all of them 作为条件。
这是我们最终得到的结果:
rule android_banker
{
meta:
description = "Detects Android Banker"
author = "Oleg Skulkin"
strings:
$s1 = "com.example.horsenjnj" ascii wide
$s2 = "res/xml/shit.xml" ascii wide
condition:
all of them
}
要使用它,您必须将其保存为一个以.yar扩展名结尾的文件。现在,您需要的只是一个能够使用 YARA 规则的扫描器。您可以在这里获得: github.com/virustotal/yara/releases/。
扫描器是另一个命令行工具。使用 -r 开关递归扫描您选择的目录:
使用 YARA 规则扫描恶意软件
如您从前面的截图中看到的,我们的恶意软件样本已成功被 YARA 扫描器识别。
当然,您可以创建更复杂的规则,官方的 YARA 文档是一个非常好的参考资源。您可以在这里找到它:yara.readthedocs.io/en/v3.8.1/。
总结
本章向您展示了如何使用杀毒扫描器、VirusTotal 和 YARA 规则,在 Android 智能手机和平板电脑的取证镜像中识别恶意软件,以及如何编写您自己的规则。
最后一章将向您介绍 Android 恶意软件分析技术,包括恶意应用程序的动态和静态分析基础。
第十章:Android 恶意软件分析
在本章中,我们将对在上一章中识别的恶意 Android 应用进行动态和静态分析。我们将涵盖以下主题:
-
使用在线沙箱进行恶意 Android 应用的动态分析
-
恶意 Android 应用的静态分析:
-
解包 Android 应用
-
Manifest 文件解码与分析
-
Android 应用反编译
-
查看和分析反编译代码
-
恶意 Android 应用的动态分析
分析恶意 Android 应用的最简单方法是将其运行在受控环境中。你已经知道如何运行模拟器并通过 ADB 安装应用程序,因此你可以在干净的虚拟系统中安装一个可疑应用程序,并查看运行后留下的任何痕迹。例如,你可以找到恶意应用程序收集的数据的 SQLite 数据库,或其配置文件。
使用在线沙箱进行动态分析
更简单且高效的方法是使用预构建的沙箱进行恶意软件分析。其中一个沙箱是Joe Sandbox。它支持自动化的动态分析,涵盖多种应用类型,包括 Windows、macOS、Linux、iOS,当然还有 Android。你可以注册一个免费账户,每月启用 10 次免费的分析。Android 应用的沙箱可以在这里访问:www.joesandbox.com/#android。
只需要几个简单的步骤即可在沙箱中运行应用程序:
-
首先,使用**选择文件...**按钮选择你要分析的文件。
-
调整运行时间;你可以在沙箱中运行应用程序 30 到 500 秒。
-
接受条款和条件,并点击分析按钮。
一旦分析完成,你将收到一封带有分析结果链接的电子邮件。在我们的案例中,它是www.joesandbox.com/analysis/67297。
让我们浏览 HTML 报告并讨论其最重要的部分。
Joe Sandbox 有自己基于自动化分析结果的检测机制。在我们的案例中,样本得到了 72 分(满分 100),并被分类为恶意:
它还使用杀毒引擎和 VirusTotal 扫描上传的样本。根据报告,我们的样本被 Avira 检测为ANDROID/Spy.Banker.YD.G****en,并且 51% 的杀毒引擎在 VirusTotal 上也进行了检测,截图如下:
根据下一部分,我们的样本尝试提升其权限,通过运行 su 命令请求 root 权限,然后尝试添加新的设备管理员:
我们来看一下网络部分。看起来我们的示例尝试从www.poog.co.kr下载一个新的 APK 文件new.apk,但由于文件不可用,下载失败:
另一个有趣的部分是电子银行欺诈。我们的样本包含与银行相关的包名字符串;它们可能用于检测设备上安装的银行应用。此外,它还能够为其他应用添加覆盖层,并具有列出当前运行应用程序的权限:
接下来的部分显示分析的应用请求了在后台进行电话拨打、发送短信和写入短信存储的权限。此外,它还能够使用 SmsManager 发送短信并结束来电;这些行为是银行木马的典型特征:
系统摘要部分向我们展示了样本请求的潜在危险权限列表:
让我们仔细看一下它们:
-
CALL_PHONE:允许应用发起电话拨打 -
GET_TASKS:允许应用收集关于当前运行应用程序的信息 -
INTERNET:允许应用打开网络套接字 -
READ_CONTACTS:允许应用读取联系人数据 -
READ_PHONE_STATE:允许应用以只读模式访问电话状态,包括电话号码和蜂窝网络信息 -
READ_SMS:允许应用读取短信 -
RECEIVE_SMS:允许应用接收短信 -
SEND_SMS:允许应用发送短信 -
SYSTEM_ALERT_WINDOW:允许应用创建在所有其他应用上方显示的窗口 -
WAKE_LOCK:允许应用防止处理器进入睡眠状态或防止屏幕变暗 -
WRITE_CONTACTS:允许应用写入联系人数据 -
WRITE_EXTERNAL_STORAGE:允许应用写入外部存储,例如 SD 卡 -
WRITE_SETTINGS:允许应用读取或写入系统设置 -
WRITE_SMS:允许应用写入存储在手机或 SIM 卡上的短信,或删除它们
我们已经知道我们的样本尝试下载一个 APK 文件。如果我们查看持久性和安装行为部分,我们会发现它不仅能够下载应用程序,还能安装它们:
为了在重启后生存,样本请求了在手机重启后执行代码的权限(RECEIVE_BOOT_COMPLETED),创建了一个新的唤醒锁来保持设备处于开启状态,并能够启动一个服务以实现自启动功能:
让我们深入了解钩子和其他隐藏及保护技术部分。该样本能够中止广播事件;它帮助恶意应用隐藏电话事件,如接收到的短信:
另一个有趣的信息是,我们的样本请求了终止后台进程的权限:
Language, Device and Operating System Detection部分显示样本收集了有关 SIM 提供商国家代码、服务提供商名称、移动国家代码、移动网络代码、WiFi MAC 地址、语音邮件号码、操作系统版本以及唯一设备 ID 的信息,如国际移动设备身份识别码(IMEI)、移动设备识别码(MEID)和电子序列号(ESN):
以下截图显示了样本收集的唯一设备 ID:
下一部分显示应用程序监控外拨电话,能够创建短信数据,并检查是否安装了 SIM 卡:
更重要的是,它监控来电并读取来电号码,解析短信(正文和来电号码),并查询已安装的应用程序和包列表:
最后,如果我们查看Antivirus Detection部分的URLs子部分,我们可以看到我们的样本试图下载的 APK 文件被 Avira URL Cloud 检测为恶意:
你可能已经注意到在之前的截图中有更多的 URLs;这些可能是恶意软件的命令与控制服务器。
总结一下,让我们汇总从Joe Sandbox动态分析中得到的信息:
-
基于病毒检测和我们发现的伪装物品,我们分析的这款恶意软件是一个银行木马。
-
它能够从
www.poog.co.kr下载其他恶意软件。 -
它收集有关银行相关应用程序的信息。
-
它能够为其他应用程序添加覆盖层。
-
它能够监控进出电话,读取和写入短信,并拦截它们。
-
它能够终止其他应用程序的进程。
-
它能够收集运行设备的信息。
-
它请求在手机重启后执行代码,以实现持久性。
-
它可能使用
http://rtrjkrykki.iego.net/appHome/或http://192.151.226.138:80/appHome/作为命令与控制服务器。
接下来的部分将带你了解执行 Android 恶意应用静态分析所需的步骤。
恶意 Android 应用程序的静态分析
为了对之前识别的恶意 Android 应用程序进行动态分析,我们在 Joe Sandbox 的帮助下将其运行在受控环境中。与动态分析相比,静态分析允许检查员在不实际运行恶意软件的情况下理解其行为。让我们从解包开始,进行我们的恶意软件样本的静态分析。
解包 Android 应用程序
要查看 APK 文件的内容,你可以使用任何压缩工具。一个好的例子是 7-Zip,这是一个免费的开源压缩工具,可以在这里下载:www.7-zip.org/download.html。
要解压 APK 文件,右键点击它,选择 7-Zip,然后选择 打开压缩包:
APK 文件内容
现在你可以浏览 APK 文件的内容并导出其部分内容进行进一步分析。在下一节中,我们将重点关注 Android 清单文件:AndroidManifest.xml。
Manifest 文件解码与分析
Manifest 文件描述了应用程序的基本信息,供 Android 构建工具、Android 操作系统和 Google Play 使用。如果你在文本编辑器中打开这样的文件,你会看到大部分数据被编码,无法正常查看。
如果我们想分析其内容,我们需要使用 Android 二进制 XML 解码器。一个这样的解码器是 axmldec,可以在这里下载:github.com/ytsutano/axmldec/releases。
要解码提取的 manifest 文件,请在命令提示符下运行 axmldec,并使用以下参数:
axmldec.exe -i AndroidManifest.xml -o manifest_decoded.xml
输出文件可以通过你选择的文本编辑器轻松查看。该文件包含大量有用的信息。例如,我们可以获取包名:
<manifest android:versionCode="1" android:versionName="1.0" package="com.example.horsenjnj">
此外,我们还可以获取有关主活动的信息。主活动是用户启动应用时第一个出现的屏幕。每个活动可以启动另一个活动以执行不同的操作。在我们的例子中,主活动是 com.cc.MainActinn:
<activity android:label="type1/2131034112" android:name="com.cc.MainActinn" android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
还有另一个活动 – com.cc.WebInterfaceActivity:
<activity android:theme="type1/16973835" android:name="com.cc.WebInterfaceActivity" android:screenOrientation="1"/>
这个活动有若干 广播接收器。广播接收器允许应用程序接收系统或其他应用程序广播的 意图。意图是由意图对象定义的消息,描述了要执行的操作。当一个应用程序向系统发出意图时,系统会根据 manifest 文件中的意图过滤器声明,定位一个能够处理该意图的应用组件。
让我们从 com.cc.MyAdminReceiver 开始,它用于获取设备管理员权限:
<receiver android:label="type1/2131034112" android:name="com.cc.MyAdminReceiver" android:permission="android.permission.BIND_DEVICE_ADMIN" android:description="type1/2131034112">
<meta-data android:name="android.app.device_admin" android:resource="type1/2130968576"/>
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>
下一个广播接收器是 com.cc.BootRt:
<receiver android:name="com.cc.BootRt" android:enabled="true" android:exported="true">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.ACTION_SHUTDOWN"/>
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
</receiver>
如你所见,它接收以下信息:
-
设备是否完成了启动过程
-
设备是否正在关机
-
设备唤醒后是否有用户在场
另一个广播接收器是 com.cc.A123:
<receiver android:name="com.cc.A123">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
<action android:name="android.intent.action.TIMEZONE_CHANGED"/>
<action android:name="android.intent.action.TIME_SET"/>
<action android:name="android.intent.action.TIME_TICK"/>
<action android:name="android.intent.action.UID_REMOVED"/>
<action android:name="android.intent.action.UMS_CONNECTED"/>
<action android:name="android.intent.action.UMS_DISCONNECTED"/>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_CHANGED"/>
<action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
<action android:name="android.intent.action.PACKAGE_FIRST_LAUNCH"/>
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>
<action android:name="android.intent.action.PACKAGE_INSTALL"/>
<action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>
<action android:name="android.intent.action.PACKAGE_REPLACED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<action android:name="android.intent.action.PACKAGE_RESTARTED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTABLE"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<action android:name="android.intent.action.MANAGE_PACKAGE_STORAGE"/>
<action android:name="android.intent.action.MEDIA_BAD_REMOVAL"/>
<action android:name="android.intent.action.MEDIA_BUTTON"/>
<action android:name="android.intent.action.MEDIA_CHECKING"/>
<action android:name="android.intent.action.MEDIA_EJECT"/>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.MEDIA_NOFS"/>
<action android:name="android.intent.action.MEDIA_REMOVED"/>
<action android:name="android.intent.action.MEDIA_SCANNER_FINISHED"/>
<action android:name="android.intent.action.MEDIA_SCANNER_SCAN_FILE"/>
<action android:name="android.intent.action.MEDIA_SCANNER_STARTED"/>
<action android:name="android.intent.action.MEDIA_SHARED"/>
<action android:name="android.intent.action.LOCALE_CHANGED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED"/>
<action android:name="android.intent.action.HEADSET_PLUG"/>
<action android:name="android.intent.action.GTALK_DISCONNECTED"/>
<action android:name="android.intent.action.GTALK_CONNECTED"/>
<action android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE"/>
<action android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE"/>
<action android:name="android.intent.action.DOCK_EVENT"/>
<action android:name="android.intent.action.DEVICE_STORAGE_OK"/>
<action android:name="android.intent.action.DEVICE_STORAGE_LOW"/>
<action android:name="android.intent.action.DATE_CHANGED"/>
<action android:name="android.intent.action.CLOSE_SYSTEM_DIALOGS"/>
<action android:name="android.intent.action.CAMERA_BUTTON"/>
<action android:name="android.intent.action.BATTERY_OKAY"/>
<action android:name="android.intent.action.BATTERY_LOW"/>
<action android:name="android.intent.action.BATTERY_CHANGED"/>
<action android:name="android.intent.action.AIRPLANE_MODE"/>
<action android:name="android.intent.action.PROVIDER_CHANGED"/>
<action android:name="android.intent.action.ACTION_SHUTDOWN"/>
<action android:name="android.intent.action.USER_PRESENT"/>
<action android:name="android.intent.action.WALLPAPER_CHANGED"/>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
<action android:name="com.noshufou.android.su.REQUEST"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
<category android:name="android.intent.category.HOME"/>
</intent-filter>
</receiver>
它接收以下信息/执行以下操作:
-
如果设备完成了启动过程,手机状态
-
如果开始了一个新的外拨电话
-
是否连接了电源
-
是否断开了电源
-
如果时区发生变化
-
如果时间已设置
-
如果时间已更改
-
如果用户 ID 已被删除
-
如果设备已进入 USB 大容量存储模式
-
如果设备已退出 USB 大容量存储模式
-
如果已安装新的应用包
-
如果现有的应用包已被更改
-
如果用户已清除包的数据
-
如果应用程序首次启动
-
如果应用程序已从设备中完全移除
-
如果应用程序已下载并安装
-
如果需要验证包
-
如果安装了应用包的新版本
-
如果应用程序已完全或部分卸载
-
如果用户重新启动了一个包
-
如果现有的应用程序被新版本安装并覆盖
-
如果外部媒体存在但无法挂载
-
如果由于内存不足,需要启动包管理
-
如果外部媒体从 SD 卡槽中移除,但挂载点未被卸载
-
如果按下了媒体按钮
-
如果外部媒体存在并正在进行磁盘检查
-
如果用户表示希望移除外部存储媒体
-
如果外部媒体存在并已挂载
-
如果外部媒体存在,但使用了不兼容的文件系统或是空白的
-
如果外部媒体已被移除
-
如果媒体扫描器已完成扫描目录
-
请求媒体扫描器扫描一个文件并将其添加到媒体数据库
-
如果媒体扫描器已开始扫描目录
-
如果外部媒体因通过 USB 大容量存储共享而被卸载
-
如果当前设备的区域设置已更改
-
如果输入法已更改
-
如果插入或拔出了有线耳机
-
如果 GTalk 连接已断开
-
如果 GTalk 连接已建立
-
如果一组包的资源当前不可用,因为存储它们的媒体不可用
-
如果一组包的资源当前可用
-
如果设备的物理对接状态发生变化
-
如果设备上不再存在存储空间不足的情况
-
如果设备存储空间不足
-
如果日期发生变化
-
如果用户操作要求显示临时系统对话框以进行关闭
-
如果按下了相机按钮
-
如果电池在低电后已恢复正常
-
如果设备处于低电状态
-
充电状态、电池电量级别及其他电池信息
-
如果用户已将手机切换到飞行模式或退出飞行模式
-
如果服务提供商的数据发生变化,例如未读电子邮件数量发生变化
-
如果设备正在关机
-
如果设备唤醒后用户存在
-
如果当前系统的壁纸已更改
-
如果 Wi-Fi 已启用、禁用、正在启用、正在禁用或状态未知
-
调用
su二进制文件以获取 root 权限 -
如果网络连接发生变化
-
如果设备接收到新的基于文本的短信
此外,我们在恶意应用程序的清单文件中有关于三个服务的信息,com.cc.service.Int、com.cc.service.Ir和com.cc.service.Hearttttt:
<service android:name="com.cc.service.Int" android:persistent="true" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</service>
<service android:name="com.cc.service.Ir" android:persistent="true" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</service>
<service android:name="com.cc.service.Hearttttt" android:persistent="true" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</service>
与活动不同,服务没有可视的用户界面。如果你查看它们的意图过滤器,你会注意到每个服务在设备完成启动过程后都会接收到一个广播信号,因此它可以在后台自动启动。
清单文件的最后部分包含应用程序使用的权限:
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
我们已经在动态分析部分讨论过权限问题,因此这里不再重复。现在,让我们深入研究并开始进行代码反编译。
安卓应用程序反编译
在这一步中,我们需要从 APK 文件中获取另一个文件:classes.dex。为了将.dex(Dalvik 执行文件)转换为.class文件并打包到.jar容器中,我们需要进行反编译。我们可以使用dex2jar来完成这个任务,工具下载地址:github.com/pxb1988/dex2jar。
要反编译classes.dex,请在命令提示符中运行d2j-dex2jar.bat,并使用以下参数:
d2j-dex2jar.bat classes.dex -o classes.jar
就是这里。现在,我们有一个classes.jar文件,里面包含了classes.dex中的所有 Java 类。我们将在下一部分查看和分析这个.jar文件。
查看和分析反编译的代码
现在我们可以查看和分析我们在之前步骤中解压和反编译的数据。我们可以使用 JD-GUI 来进行这个操作。JD-GUI 是一个免费的工具,能够显示.class文件的 Java 源代码。你可以在这里下载这个工具:jd.benow.ca/。
这是 JD-GUI 显示的classes.jar内容:
classes.jar的内容
我们已经知道了很多关于银行木马的信息,现在让我们通过代码分析来学习一些新的东西。通过动态分析,我们识别出了两个可疑的 URL,rtrjkrykki.iego.net/appHome/和192.151.226.138:80/appHome/。很可能这两个是同一个服务器,所以我们可以尝试在代码中使用 JD-GUI 查找至少一个 URL:
使用 JD-GUI 搜索 URL
好的,现在我们知道 URL 位于ConstantDatas.class中。让我们看一下:
ConstantDatas.class内容的一部分
如果我们搜索BANKURL,我们会发现它在MainActinn.class中被使用:
MainActinn.class内容的一部分
看看这一行:"ConstantDatas.URL = ConstantDatas.BANKURL;"。现在让我们搜索ConstantDatas.URL。我们会在Hearttttt.class中找到一个很好的匹配:
Hearttttt.class内容的一部分
在这里,你可以看到应用程序收集关于设备的信息,包括安装的操作系统、已安装的银行应用程序、移动国家代码和移动网络代码、唯一的用户订阅 ID 等,并将这些数据以 JSON 格式发送到192.151.226.138:80/appHome/servlet/OnLine。
如你所见,通过静态代码分析,你可以获得大量的附加信息;有时这相对简单,有时则不然,因为恶意软件样本可能会高度混淆。
为了以更高的成功率进行代码分析,我们强烈建议你开始学习 Android 编程。请参考深入阅读部分提供的书籍。
总结
本章介绍了恶意 Android 应用程序的动态和静态分析。你已经学习了如何使用在线沙箱进行动态分析,如何解包 Android 应用程序,分析其清单文件,并反编译其代码。最后,你已经了解了反编译代码分析的概念。
深入阅读
请参阅以下参考资料:
-
应用开发者文档:
developer.android.com/docs/ -
John Horton,《Android 编程入门(第二版)》:
www.packtpub.com/application-development/android-programming-beginners-second-edition