2026年“美亚杯”手机数据库专题"

admin 2026-10-16 06:16:09 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

2026年“美亚杯”手机数据库专题

原创

小谢
小谢

小谢取证

2026年9月30日 17:42
上海

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

AI 取证实战 · 第 20 期

美亚杯手机数据库专题:iPhone 与安卓的库、表、字段一次讲清

从 Photos.sqlite 到 WhatsApp,从 Cocoa 时间戳到联表查询——把五年真题反复考的那些库、表和字段摊开讲,再附四张考场速查表

这篇是工具型长文,建议收藏当手册用。第 1—2 章讲清概念和找库的路径,第 3—5 章逐个拆解五届考过的库与表,第 6—8 章讲时间戳、联表查询和够用的 SQL,第 9 章把五届 87 道数据库题按届逐题还原,第 10 章把五年的考点做成地图(15 个考点谁年年考、谁刚成形),第 11 章是四张速查表(按平台、按问法、按字段反查),第 12—14 章给易错点清单、四级能力自测和五周练习路线。

全文所有库名、表名、字段名与真题问法,均取自 2021—2025 五届题解原文,涉及具体题目的地方都标了届次+题号,可回原文核对。

一、为什么手机题最后总要落在数据库上

先看一个真实场景。

题目问:「机主在 2025-04-25 17:11:37 使用 WhatsApp 拨打过哪个号码」。你用自动取证工具打开检材,WhatsApp 那一栏里能看到通话记录列表,也能看到那条记录——但你要的是一个精确到秒的时间点,列表里没有这一列。这时候你要么一个个点开来对,要么退回最原始的那一层:直接查 WhatsApp 自己的数据库文件。

这就是手机取证里最常见的岔路口。自动分析工具(火眼、X-Ways、Autopsy、iLEAPP、手机大师)把数据库读出来、翻译成人能看懂的界面,但它翻译的字段是它认为重要的那几个。出题人偏偏爱问它没翻译出来的那个。

i 一句话总结这五年的命题规律

2021—2025 五届美亚杯,手机检材的题目里,凡是「精确时间点、经纬度、某个 ID、某条被编辑前的原文、某个文件的落盘路径」这类问法,答案几乎都在数据库里。工具能给你 80%,剩下那 20% 的分,就是靠你会不会读库、会不会写一句 SQL。

1.1 手机里的数据,分三层

把手机想象成一栋楼,应用数据从上到下是三层:

层 是什么 取证时会碰到什么
第一层:文件 照片、视频、语音、文档这些「看得见」的东西 导出就能看,唯一难点是文件名叫什么、存在哪——而这两个信息恰恰存在数据库里
第二层:应用数据目录 每个 App 自己的一块私有地盘,安卓在 /data/data/<包名>/,iOS 在 /var/mobile/Applications/<BundleID>/ 目录结构杂乱、命名看不懂(group.net.whatsapp.WhatsApp.shared 谁记得住),但它是通往第三层的路
第三层:数据库 SQLite 文件(少数是 Core Data、Realm、Postgres) 所有「谁、什么时候、对谁、说了什么、传了什么、在哪」的结构化答案都在这

所以有一句在圈内流传的话:手机取证做到最后,就是一场 SQLite 阅读比赛。这话在美亚杯上几乎年年应验。

1.2 数据库其实你早就会——它就是一本 Excel 工作簿

「数据库」这三个字劝退了不少人,但 SQLite 和 Excel 的对应关系几乎是 1:1 的,把术语换成你说惯了的话,门槛立刻降一半:

数据库里的叫法 Excel 里的叫法 手机取证里长什么样
数据库(database) 一个 .xlsx 文件 一个 ChatStorage.sqlite 文件
表(table) 一个工作表 sheet ZWAMESSAGE 、message、ZASSET
字段(column) 一列的表头 ZTEXT (消息正文)、ZDATE(时间)
记录(row) 一行数据 一条消息、一张照片的元数据
主键(primary key) 行号(能被别人引用) Z_PK /_id,全表唯一
外键(foreign key) 「指向另一个 sheet 的某一行」的引用 ZMESSAGEINFO 里存着 ZWAMESSAGEINFO.Z_PK 的值

其中主键和外键这一对,是读懂一切联表题的钥匙。第 7 章会专门讲。

✓ 别被名字吓到

ZASSET 读作「Z-asset」,ZWAMESSAGE 读作「Z-W-A-message」。iOS 应用的数据库大多用苹果的 Core Data 框架生成,框架习惯给表名和字段名统统加一个 Z 前缀——所以你在 iOS 库里面看到的字段几乎全是 Z 开头,这不是加密,只是框架的命名口味。

1.3 五个必须分清的概念

新手最容易把这五个混成一团,而美亚杯恰恰喜欢在它们的边界上出题:

概念 一句话 形象说法 在库里的样子
文件后缀 文件名最后那截 包装袋上的字 .jpg ↔ 真实内容可能是 PNG
文件头 文件开头的几个魔数 身份证上的照片 FF D8 FF = JPEG
EXIF 元数据 照片自带的拍摄参数 照片背面写的字 存在 ZEXTATTR 表(iOS)
数据库元数据 系统给数据加的记账信息 图书馆的索书号 Z_METADATA /Z_PRIMARYKEY 表
应用配置 App 的设置项 电器的档位旋钮 com.tencent.mm_preferences.xml

举个 2025 年个人赛的例子:题目问「哪张照片可以确定不是由这台手机拍摄的」。答案不在文件名上(文件名都是 IMG_00xx),也不在文件本身,而在 Photos.sqlite 的 ZEXTATTR 表里——那里存着从 EXIF 抄过来的相机型号,写着「SONY」和「iPhone 14 Pro MAX」的那两条,显然不是同一台设备拍的。

1.4 「工具解析不出来」到底是什么意思

这是新手最常见的困惑。工具明明打开了检材,为什么还是解析不出来?通常是四种原因之一:

  • ① 数据库版本太新,工具内置的解析规则还没更新

——2025 年团体赛有一题问 n8n 平台的数据库有多少张表,因为工具还不支持那个版本的 PostgreSQL,参赛者只能手动导出、或者用十六进制工具硬看;同届个人赛还遇到过 Apple Notes 结构变化导致现成脚本集体失效,只能改脚本。
* ② 库根本没被识别成数据库

——文件后缀不是 .sqlite/.db,例如苹果的通话记录叫 CallHistory.storedata,很多人扫库的时候因为这后缀把它漏掉了。
* ③ 数据还在 WAL 日志里,没落进主库

——这是最阴的一种,第 2.5 节专门讲。
* ④ 工具只翻译了「常用字段」,你问的字段它没展示

——不是它读不出来,是界面没给你显示。这种只要自己拿 DB Browser 打开库,一眼就能看到。

这四条对应四种不同动作:①② 要自己手动看库,③ 要会处理 WAL,④ 只要把工具扔了直接看库。所以无论哪种,结论都一样:你得会自己开库。

1.5 这五年,手机数据库题考了多少

我把 2021—2025 五届团体赛+个人赛的题解逐题过了一遍,把「答案必须靠读数据库、或读数据库里某个字段」才能拿到的题目挑出来,按届归了一下,并给出可以回原文核对的题号——这样你既能看清趋势,也能自己抽查我有没有数错:

届次 密度 逐题收录 主要库(附可核对题号)
2021 (团体+个人) 起步 6 题 wa.db (2021G-Q30)、蓝牙设备库(2021I-Q9/Q32/Q33)、ChatStorage(2021I-Q8)、相册库(2021I-Q37)
2022 (个人) 明显上升 10 题 Photos.sqlite (2022I-Q33/Q34/Q35)、NoteStore.sqlite(2022I-Q37/Q38)、以及 iBooks/MTR/waze/Gmail 四个第三方库(2022I-Q10—Q12、Q20、Q31)
2023 (团体+个人) 上台阶 18 题 ChatStorage.sqlite (2023G-Q9、2023I-Q55)、msgstore.db(2023G-Q82)、CallHistory.storedata(2023I-Q64)、Photos.sqlite(2023I-Q58)
2024 (团体+个人) 成为主力题型 19 题 msgstore.db (2024G-Q11)、ChatStorage.sqlite(2024G-Q90)、message_2.sqlite(微信)(2024I-Q1/Q19)、CallHistory+AddressBook(2024I-Q2)、Photos.sqlite(2024I-Q22)
2025 (团体+个人) 绝对主力 34 题 ChatStorage.sqlite (2025G-Q183、2025I-Q50)、DeviceAgents.sqlite(2025G-Q158)、Photos.sqlite(2025I-Q40)、ZWAMESSAGE+ZWAMESSAGEINFO(2025I-Q58)、finder_main.db(2025I-Q48)

「逐题收录」那一列的 6 / 10 / 18 / 19 / 34,是把题目一道一道列出来数出来的,不是估算——每一道都写在第九章里,你可以拿着第九章的清单和这一列对账。

! 这个数字是怎么来的,以及它不是什么

手机题有个特点:同一道题的答案常常能从多个检材取得(2024 年团体赛题解自己就写「很多题目的答案来源都不止一处」)。所以我定的口径是:只收「必须动数据库才能拿到答案」的题——题目直接问库表字段的、必须写 SQL 才算得出的、以及火眼解析不出来只能手动开库的。
凡答案虽然存在库里、但火眼的聊天记录/图片分析已经能直接给出的题(比如「两人对话显示了什么关系」),没有计入。
另外,本表只统计手机检材;题解里还有一批服务器侧数据库题(2023G 的 MySQL 备份、2025G 的 n8n 与网站库等),不属于手机范畴,单列在第九章 9.8 节。

趋势很明确:从 2023 年开始,手机数据库题的比重明显上抬,2025 年几乎成了主力题型。而且考法在变——早期只考「在哪张表里」,现在考「两张表怎么接起来」「这个字段为什么和另一个字段打架」。

二、找库:手机的数据库都藏在哪

所有数据库题的第一步都是同一个动作:把这个库找出来。这一步不难,但路径不熟就会在水下摸半天。这一章把路径地图一次给全。

2.1 Android:路径整齐,一看就懂

安卓的规矩最简单——每个应用的私有数据都在自己包里:

/data/data/<包名>/databases/<库名>.db /data/data/<包名>/shared\_prefs/<配置>.xml /data/data/<包名>/files/ /data/data/<包名>/cache/  WhatsApp   → /data/data/com.whatsapp/databases/msgstore.db              /data/data/com.whatsapp/databases/wa.db 微信        → /data/data/com.tencent.mm/MicroMsg/<32位哈希>/EnMicroMsg.db 通讯录      → /data/data/com.android.providers.contacts/databases/contacts2.db 短信        → /data/data/com.android.providers.telephony/databases/mmssms.db 通话记录    → /data/data/com.android.providers.contacts/databases/calllog.db

看到没?包名 + databases 目录,就是安卓找库的全部秘诀。把 /data/data 当成一栋宿舍楼,每个 App 一间房,数据库都放在各自房间的 databases 抽屉里。

✓ 实战小抄

在火眼或 X-Ways 里直接搜 /databases/ 这个目录名,能一次性把所有 App 的库列出来。先看库的大小,几百 KB 到几 MB 的往往是重点——空的库(0 字节或只有几张空表)说明那个 App 装过但没用过。2023 年个人赛有一题「手机安装了什么即时通讯软件」,答案就得靠「有没有数据」来判:WhatsApp 和微信都装了,但微信库里没数据,说明装了没登录,最后只能选 WhatsApp。

2.2 iOS:路径乱,但规律在 BundleID 上

iOS 的路径看着长,规律其实也简单:应用名被写成 BundleID,数据放在包的 Documents 或 Library 下。

/var/mobile/Applications//Documents/ /var/mobile/Applications//Library/ /var/mobile/Containers/Data/Application//Documents/   ← 新版系统  WhatsApp → /var/mobile/Applications/group.net.whatsapp.WhatsApp.shared/               ChatStorage.sqlite        ← 聊天数据(重点)               DeviceAgents.sqlite        ← 已登录设备(2025 考过)               Media/Profile/             ← 群组/联系人头像 微信      → /var/mobile/Applications/com.tencent.xin/Documents/<32位哈希>/               finder/db/finder\_main.db   ← 视频号(2025 考过) 相册      → /var/mobile/Media/PhotoData/Photos.sqlite   ← 照片元数据(重点) 备忘录    → /AppDomainGroup-group.com.apple.notes/NoteStore.sqlite 通话记录  → /var/mobile/Library/CallHistoryDB/CallHistory.storedata 通讯录    → /var/mobile/Library/AddressBook/AddressBook.sqlitedb

注意三个「不像数据库」的名字,这是最容易漏掉的:CallHistory.storedata(通话记录)、NoteStore.sqlite(在共享域 AppDomainGroup 下,不在单个 App 包里)、Photos.sqlite(在 Media/PhotoData/,不在应用目录里)。

! 别用后缀筛库

如果用「后缀是 .sqlite 或 .db」去筛,CallHistory.storedata 这类文件会被整批漏掉。稳妥做法是同时看后缀和文件头:文件头是 SQLite format 3 的就是 SQLite 库,不管它叫什么名字。

2.3 iOS 备份检材:那四个必须认识的文件

近几年美亚杯的 iOS 检材大多是备份包(.zip)而不是完整镜像,解压之后在 /var 目录下一定会看到这几个文件,它们的名字和用途是固定的:

文件名 作用 取证上怎么用
Manifest.db 备份的文件清单数据库。记录每个文件的三件事:fileID(在备份里的哈希文件名)、domain(属于哪个 App 域)、relativePath(原始路径) 想知道「某个文件原来叫什么、在哪」,就查它。备份目录里文件全是随机哈希名,靠这张表才能还原
Manifest.plist 备份的总配置 其中 IsEncrypted 标志决定这份备份能不能直接分析
Status.plist 备份的状态信息 用于确认备份完整性、备份时间、UUID
\*\_DEC (带此后缀的 4 个文件) 提取工具生成的解密后版本 用它们覆盖掉同名加密文件,再把 IsEncrypted 改成 false,就能当普通文件集合挂载分析

2025 年个人赛题解给的正是上面这条流程。还有个更省事的变体:只删掉 Manifest.db 并把 Manifest.plist 的加密标志改掉,效果一样。两个都删也能挂载,但会缺一部分信息。

i 备份密码从哪来

iOS 备份若要保留 KeyChain 这类隐私数据,工具会强制设一个备份密码。赛方给检材时设的通常是 4 位数字弱口令,2025 年个人赛题解直接写明「大多数检材的密码为 0000 或 1234」。这就是第 8.5 节说的「先试默认值」——不是爆破,是撞常见值,两秒钟的事。

2.4 每个库都自带三张「说明书」表

这是新手最该记住的一招:打开任何一个陌生的库,先看这三张表,不用猜。

表名 是干什么的 常用查询
sqlite\_master 整个库的目录页——列出所有表、索引、视图的名字与建表语句 SELECT name FROM sqlite_master WHERE type='table';
Z\_PRIMARYKEY Core Data 的主键计数器,列出每个实体的名字和当前最大主键值 iOS 库里想快速看「这个库有哪些实体」,它是另一份目录
Z\_METADATA Core Data 的版本与元信息,通常只有一行 看库结构版本,判断这个库是哪个 iOS 版本生成的

2023 年个人赛有一题就是直接考这个:CallHistory.storedata 里「哪份表格显示了通话记录」,选项里混着 ZCALLRECORD、ZCALLBPROPERTIES、Z_METADATA、Z_MODELCACHE、Z_PRIMARYKEY——后面那三个正是 iOS 库里每张表都会有的「通用表」,它们当然是干扰项,答案是有实际业务含义的 ZCALLRECORD。

还有一题问「数据库里有哪两张表」(2023 团体赛,检材是一个 MySQL 备份文件),题解的做法就是直接看 dump 文件里的建表语句,找到 users 和 creditcard。可见无论 SQLite 还是 MySQL,「先列表名」永远是第一步。

2.5 一行 Python,把所有字段名导出来

知道表名之后,下一步是知道字段名。肉眼在 DB Browser 里翻很慢,2022 年个人赛的题解给了一段特别实用的脚本——那次考的正是「照片的哪个栏目标题能显示接收方式」,解题人干脆把全库字段导成 JSON 再搜:

import sqlite3, json  con = sqlite3.connect('./Photos.sqlite') cur = con.cursor() tables = cur.execute(     \"SELECT name FROM sqlite\_master WHERE type = 'table' ORDER BY name;\" ).fetchall()  tables\_parsed = {} for tablename in tables:     tablename = tablename[0]     tables\_parsed[tablename] = []     cols = cur.execute('PRAGMA table\_info(%s);' % tablename).fetchall()     for col in cols:         tables\_parsed[tablename].append(col[1]) con.close()  with open('./Photos.json', 'w') as f:     json.dump(tables\_parsed, f, indent=4)

这段代码做了三件事,值得逐句理解:

  • sqlite_master

→ 拿到所有表名;
* PRAGMA table_info(表名)

→ 拿到这张表的所有字段名
* (PRAGMA 是 SQLite 特有的「查元信息」指令,不含数据,秒回);
* 输出成 JSON → 之后用编辑器一个 Ctrl+F 搜字段名,比在图形界面里翻快十倍。

那题的题干里给了四个候选字段名(ZIMPORTEDFROMSOURCEIDENTIFIER、ZIMPORTEDBYBUNDLEIDENTIFIER、ZRECEIVEDFROMIDENTIFIER、ZRECEIVEMETHODIDENTIFIER),把它们塞进上面的 find 列表里一搜就发现:只有 ZIMPORTEDBYBUNDLEIDENTIFIER 存在,而且同时出现在 ZADDITIONALASSETATTRIBUTES、ZCLOUDMASTER、ZGENERICALBUM 三张表里。

✓ 这一招的通用性

「把全库表名+字段名导成一份清单,然后搜关键词」——这是所有数据库题的开局起手式,无论题目问什么。赛场上没有比这更快的方式了:你不知道叫什么,那就让它自己告诉你。

2.6 WAL 日志:你看到的数据可能是旧的

在库文件旁边,你经常会看到一对同名兄弟:

ChatStorage.sqlite ChatStorage.sqlite-wal      ← 预写日志(Write-Ahead Log) ChatStorage.sqlite-shm      ← 共享内存索引

SQLite 为了性能,写入时先写 WAL、延迟合并进主库。所以第一个坑是:主库文件里的数据可能落后于 WAL,最近几条消息、最近的编辑记录很可能只存在于 -wal 里。

  • 怎么办

:把 .sqlite、-wal、-shm三个文件放回同一目录再打开,DB Browser 会自动合并读取——单个文件拷出来是读不到最新数据的;
* 或者

先把 WAL 落盘:打开库执行一句 PRAGMA wal_checkpoint(FULL);;
* 注意

:分析时别在原检材上做任何写操作,先复制一份工作副本。

! 一个真实教训

2025 年个人赛有一题需要拿到 WhatsApp 里一条投票消息的完整信息,而投票详情并不在 ZWAMESSAGE 主表里,而是以 Protobuf 格式存在ZWAMESSAGEINFO 表的 ZRECEIPTINFO 字段中。这类「详细信息存在附属表、主表只放一个指针」的设计,加上 WAL 的延迟落盘,是两个最容易让新手得出「数据不存在」错误结论的地方。

三、iOS 相册库 Photos.sqlite:五年最重要的一个库

如果整篇文章只让你记一个库,那就是它。

2022、2023、2024、2025 四届都有题目直接落在 Photos.sqlite 上,考法从「字段名是什么」一路升级到「两张表的经纬度为什么不一样」。原因也不难理解:它是手机上信息密度最高的一个数据库——每张照片的拍摄时间、精确到小数点后六位的经纬度、拍摄设备型号、镜头、文件叫什么名字、什么时候进的相册、是不是从别的 App 收来的、是不是实况照片、是不是被删除过,全在里面。

3.1 库在哪

完整镜像:/var/mobile/Media/PhotoData/Photos.sqlite iOS 备份:/var/mobile/Media/PhotoData/Photos.sqlite  (在 Manifest.db 的 domain 里可定位) 旁支文件:Photos.sqlite-wal / Photos.sqlite-shm           (还有 Photos.sqlite-journal 等,同上,要一起带上)

注意路径——它在 Media/PhotoData/,不在应用沙盒里。这一点很关键:说明它是系统级数据,不受单个 App 的沙盒限制,也解释了为什么它能记录「这张照片是从哪个 App 收进来的」。

3.2 表族全貌:先认清这几张表

打开 Photos.sqlite,你会看到几十上百张表,但真正高频的只有下面这八九张。关键是记全称——因为公开的查询脚本(比如圈内常用的 iOS_Local_PL_Photos.sqlite_Queries)在 SQL 里习惯用缩写,你看题解时容易被绕晕:

表全称 脚本/题解里的写法 管什么
ZASSET ZASSET 主表 :一张照片/一段视频一条记录,绝大多数问题都从它开始
ZEXTENDEDATTRIBUTES ZEXTATTR EXIF 扩展属性 :相机型号、镜头、焦距、拍摄地经纬度、时区、方向
ZADDITIONALASSETATTRIBUTES ZADDASSETATTR 附加属性 :来源、导入方、原始资产标识、指纹
ZGENERICALBUM ZGENALBUM 相簿:相册名(ZTITLE)、创建时间
ZCLOUDMASTER ZCLDMAST iCloud 侧的主记录:云资产 GUID、云端创建时间
ZINTERNALRESOURCE ZINTRESOU 内部资源:缩略图、调整后版本等
ZUNMANAGEDADJUSTMENT ZUNMADJ 未经管理的调整信息(编辑过的照片)
ZSCENEPRINT ZSCENEP 场景识别结果
ZMEDIAANALYSISASSETATTRIBUTES ZMEDANLYASTATTR 媒体分析属性
ZSHARE ZSHARE 共享相簿信息

i 怎么确认一张表到底叫什么

别背,去查。用第 2.5 节那段脚本把全库表名导出来,或者直接用一句 SELECT name FROM sqlite_master WHERE type='table';。2022 年个人赛的题解就是这么确认的:它先列出全库字段,发现候选字段里只有 ZIMPORTEDBYBUNDLEIDENTIFIER 存在,并且同时存在于 ZADDITIONALASSETATTRIBUTES、ZCLOUDMASTER、ZGENERICALBUM 这三张表里——连表名一起确认了。

3.3 ZASSET 常用字段速查

下面这张表是本文最该收藏的一张。「真题实证」列的 √ 表示这个字段在近五年题解里被明确用到过,后面跟的是届次与题号;— 表示它在公开资料里是标准字段,但这五年题目里没有被单独点问过。

字段名 含义 取值与坑 真题实证
Z\_PK 本表主键,全表唯一 所有「关联到这张照片」的表都存这个值 —
ZUUID 资产唯一标识(UUID 字符串) 跨库关联的钥匙 :微信消息里的 m_assetUrlForSystem 存的就是它 √ 2024I-Q1/Q19
ZFILENAME 原始文件名 IMG_0008.HEIC 、5005.JPG √ 2024I-Q22
ZORIGINALFILENAME 导入前的原文件名 从别的 App 收来的照片,这里会留痕 —
ZDIRECTORY 相对目录 通常是 DCIM/100APPLE —
ZUNIFORMTYPEIDENTIFIER 统一类型标识(UTI) public.heic /public.jpeg/public.mpeg-4——判文件真实类型比后缀更靠谱 √ 2024I-Q22
ZDATECREATED 拍摄/创建时间 Cocoa 时间戳 ,见第 6 章 √ 2025I
ZADDEDDATE 加入相册的时间 收来的照片:创建时间早、加入时间晚,可据此判断「什么时候收到的」 √ 2025I
ZLATITUDE 纬度 注意:它和 ZEXTATTR 里那份可能不一致 √ 2025I-Q40
ZLONGITUDE 经度 同上 √ 2025I-Q40
ZEXTENDEDATTRIBUTES 指向 ZEXTENDEDATTRIBUTES.Z_PK 这是外键——想知道拍摄设备必须顺着它跳过去 √ 2025I-Q40
ZKIND 资产种类 0 = 照片,1 = 视频 —
ZKINDSUBTYPE 种类子类型 全景、慢动作、实况等细分 —
ZVIDEOCPDURATIONVALUE 附带视频片段时长 实况照片(Live Photo)这项不为 0 √ 2024I-Q22
ZTRASHEDSTATE 是否在「最近删除」 被删除的照片可能仍留在这张表里 —
ZTRASHEDDATE 删除时间 配合上一字段还原删除动作 —
ZHIDDEN 是否被隐藏 「已隐藏」相簿的成员 —
ZWIDTH /ZHEIGHT 像素宽高 常用来区分原图与缩略图 —
ZCLOUDASSETGUID 云端资产 GUID 与 ZCLOUDMASTER 呼应 —

3.4 ZEXTATTR:EXIF 真正的家

很多人第一次做这类题会犯一个错:在 ZASSET 里翻相机型号,翻了半天没有。因为设备信息不在主表,在 ZEXTENDEDATTRIBUTES。

2025 年团体赛就考了这个:题目要求「列出可以确定不是由这台手机拍摄的图片」。题解的做法是把查询结果导出成 CSV,然后在 ZEXTATTR 的ZCAMERAMODEL 列里筛选——结果看到两个文件分别来自「SONY 相机」和「iPhone 14 Pro MAX」,而题目限定了 HEIC(HEVC)格式,那两个文件一个是 MOV 视频、一个是 JPG 图片,自然都不符合,最后锁定 JPG 那个。

ZEXTENDEDATTRIBUTES 里值得记住的字段:

字段名 含义 考点
ZCAMERAMAKE 相机厂商 「这台照片是谁拍的」第一顺位
ZCAMERAMODEL 相机型号 判「是否本机拍摄」的关键
ZLENSMODEL 镜头型号 区分同一厂商的不同机型/外接镜头
ZFOCALLENGTH 焦距 配合镜头型号判断
ZFOCALLENGTHIN35MM 等效 35mm 焦距 同上
ZDIGITALZOOMRATIO 数码变焦倍率 >1 说明做过数码变焦
ZLATITUDE /ZLONGITUDE 拍摄地经纬度(EXIF 那份) 与 ZASSET 那份对照,用哪份是真题考点
ZGPSHORIZONTALACCURACY GPS 水平精度 精度值大说明定位粗
ZFLASHFIRED 是否闪光 辅助信息
ZORIENTATION 拍摄方向 辅助信息
ZTIMEZONENAME /ZTIMEZONEOFFSET 拍摄时区 时间换算前必看 ——同一时刻在不同时区显示不同
ZEXIFTIMESTAMPSTRING EXIF 原始时间字符串 未经换算的「原话」,可与换算结果互校

3.5 两份经纬度打架,用哪一份?(2025 个人赛真题)

这是 Photos.sqlite 系列里最值得讲的一道题,因为它把「读字段」升级成了「辨字段」。

题目:「APP『照片』中,IMG_0027.HEIC 的原地理位置信息(WGS84)是」,四个选项的经纬度极其接近,只有小数点后几位不同。

题解的做法是:过滤文件名之后,看到两组地理位置信息,一组来自 ZASSET 表、一组来自 ZEXTATTR 表。两组值不一样。怎么办?解题人用的是最朴素也最可靠的办法——对比拍摄时间相近的几张照片,发现 ZEXTATTR 那份才和邻近照片的轨迹连贯,于是判定它是真实信息。最后还去看了一眼文件的 EXIF,印证了同样的结果。

✓ 这类题的通用解法:三方对照

当同一个信息在不同表里出现两个值时,不要猜,去交叉验证。顺序是:① 看两个值分别来自哪张表(ZASSET 还是 ZEXTATTR);② 拿同一时段的其他照片做轨迹对比,看哪一组更连续;③ 导出文件本身看 EXIF,作为第三方印证。三条证据一致的,就是答案。

还有一个同类现象更该警惕:自动取证工具算出来的值,可能和数据库里存的值不一样。2025 年个人赛另一题要求「某群组在某时刻传送的 WGS84 坐标」,题解发现选项里没有一个与工具输出的完全一致,回去翻数据库才发现——工具那条记录的 GPS 与库里存的不同。解题人最后是通过定位该消息的媒体记录(ZMEDIAITEM 字段的值),再去 ZWAMEDIAITEM 表按 Z_PK 过滤,才拿到精确经纬度。题解原话写得很实在:「目前还不确定为什么火眼分析出的 GPS 信息会与数据库中存储的值不同」。

! 记住这句话

工具给的是「它算的结果」,数据库给的是「原始记录」。答案冲突时,考场上的正确做法是——回数据库,并说明你的取值依据。

3.6 「这张照片是怎么进来的」(2022 个人赛真题)

这道题的问法很典型:「根据照片的数据库资料,哪一个栏目标题可以显示这张照片的接收方式」。

注意题干用词——「栏目标题」翻成人话就是「字段名」。四个候选是:

A. ZIMPORTEDFROMSOURCEIDENTIFIER B. ZIMPORTEDBYBUNDLEIDENTIFIER C. ZRECEIVEDFROMIDENTIFIER D. ZRECEIVEMETHODIDENTIFIER

题解给的解法就是第 2.5 节那段脚本:把全库表名和字段名导成 JSON,再把四个候选逐个搜一遍。结果是——四个里只有 ZIMPORTEDBYBUNDLEIDENTIFIER 真实存在,并且同时出现在 ZADDITIONALASSETATTRIBUTES、ZCLOUDMASTER、ZGENERICALBUM 三张表里。

! 这里有一处题解内部的不一致,如实说明

题解记录的答案是 A(ZIMPORTEDFROMSOURCEIDENTIFIER),但题解自己的检索结果只找到了 B——原话是「只能找到 ZIMPORTEDBYBUNDLEIDENTIFIER 字段」。也就是说这道题在题解里是存疑的。
复现时按 B 去理解逻辑是通的(它确实存在,也确实承担「记录来源」的作用);但考场上如果原题选项与真题一致,仍以官方答案为准。把这个不一致标出来,比替你选一个更负责任。

而下一题(「承上题,这张照片通过什么方式接收」)问的是那个字段的值:它是 com.apple.sharingd。题解特意查了这个守护进程的说明:sharingd 就是系统里负责 AirDrop、共享电脑、远程光盘的那个服务。所以答案是「以上皆非」——它既不是 WhatsApp 传的,也不是蓝牙、Signal、网页下载,而是隔空投送。

两题连起来看,路径其实很清楚:先确定字段名,再看字段的值,最后把值翻译成人话。

字段 值举例 对应含义
ZIMPORTEDBYBUNDLEIDENTIFIER com.apple.sharingd 隔空投送(AirDrop)
ZIMPORTEDBYBUNDLEIDENTIFIER com.apple.mobileslideshow 系统相册自身
ZIMPORTEDBYDISPLAYNAME 导入方的显示名 常与上一字段配对出现
ZIMPORTEDFROMSOURCEIDENTIFIER 来源标识 外部来源
ZIMPORTSESSIONID 导入会话 ID 同一次批量导入共享同一个值

这类题的通用套路已经成型:先确定字段名(靠第 2.5 节的导字段脚本)→ 再取该字段的值 → 最后把值翻译成人话。值往往是 BundleID 形式(com.xxx.yyy),查一下这个包名属于哪个 App,答案就出来了。

3.7 怎么判断实况照片(Live Photo)

2024 年个人赛的一题:「以下哪张照片是实况照片(Live Photos)」,多选题。

题解的 SQL 只有三行,但把三个知识点塞在了一起:

SELECT Z\_PK, ZFILENAME FROM ZASSET WHERE ZFILENAME LIKE '%.HEIC'   AND ZUNIFORMTYPEIDENTIFIER = 'public.heic'   AND ZVIDEOCPDURATIONVALUE != 0;

  • ZFILENAME LIKE '%.HEIC'

——按文件名后缀过滤;
* ZUNIFORMTYPEIDENTIFIER = 'public.heic'

——按真实类型过滤(两者不一定一致,所以要双保险);
* ZVIDEOCPDURATIONVALUE != 0

——实况照片会附带一段几秒的视频,这个字段不为 0 就说明有视频分量,即 Live Photo。

题解还补了一句很实在的话:这题「有点白给」——因为选项里的 IMG_0005.HEIC 和 IMG_0006.HEIC 这两个文件根本不存在(实际扩展名是 PNG),多选题排除一下就出来答案了。「文件不存在但要靠数据库发现」——这也是 Photos.sqlite 的常见坑:库里有记录 ≠ 文件还在。

3.8 被删除的照片,痕迹在哪

照片实际被删、进「最近删除」、被隐藏,是三个不同状态,而 Photos.sqlite 把这三个状态都记下来了:

  • ZTRASHEDSTATE

:是否在「最近删除」里(等待 30 天自动清除);
* ZTRASHEDDATE

:进入「最近删除」的时间——这条时间线本身就有意义,能还原「什么时候动过手」;
* ZDELETEREASON

/ZTRASHEDBYPARTICIPANT:删除原因、由谁删除(共享相簿场景);
* ZHIDDEN

:是否被隐藏(隐藏相簿);
* ZCLOUDDELETESTATE

/ZPTPTRASHEDSTATE:云端删除状态、PTP 导入的删除状态。

✓ 删除类题目的答题骨架

① 这张表里还有没有这条记录(ZTRASHEDSTATE 是 1 还是 0)→ ② 什么时候被删的(ZTRASHEDDATE)→ ③ 原始文件还在不在 Media/DCIM/ 下 → ④ 有没有副本(缩略图、调整后版本、iCloud 侧记录)。四步走完,「删除」这个动作就还原完整了。

3.9 本章真题索引(附原题)

下面把本章涉及的真题逐题列出——题干与选项按题解原文照录(含原文的繁体用字、半角标点与大小写,不作改写);每题只标「考的是哪个库、哪张表、哪个字段」,完整答案与解题过程见第九章。

2022I-Q34 | 选择题

考的字段/表:ZIMPORTEDBYBUNDLEIDENTIFIER 等四个候选字段

根据照片的数据库资料,哪一个栏目标题可以显示这张照片的接收方式

A. ZIMPORTEDFROMSOURCEIDENTIFIER
B. ZIMPORTEDBYBUNDLEIDENTIFIER
C. ZRECEIVEDFROMIDENTIFIER
D. ZRECEIVEMETHODIDENTIFIER

考点:「栏目标题」= 字段名;题解答案写 A、检索结果只找到 B,属存疑

2022I-Q35 | 选择题

考的字段/表:该字段的值com.apple.sharingd

承上题,这张照片通过什么方式接收

A. WhatsApp软件传送
B. 蓝牙传送
C. Signal软件传送
D. 网页下载
E. 以上皆非

考点:把 BundleID 翻译成 AirDrop,答案「以上皆非」

2023I-Q58 | 填空/简答(原题无选项)

考的字段/表:ZASSET 视频 + ChatStorage 交叉

根据 Photos.sqlite 数据库中, 有多少段视频可能涉及 WhatsApp?

考点:两个库比对:库里 10 条,实际保存 7 条

2024I-Q22 | 选择题

考的字段/表:ZFILENAME/ZUNIFORMTYPEIDENTIFIER/ZVIDEOCPDURATIONVALUE

Emma 的 iPhone XR 内以下哪张照片是实况照片(Live Photos)?

A. IMG\_0002.HEIC
B. IMG\_0005.HEIC
C. IMG\_0004.HEIC
D. IMG\_0006.HEIC

考点:Live Photo 判定

2024I-Q1/Q19 | 选择题

考的字段/表:ZUUID(跨库)

2024I-Q1

Emma 和 Clara 的微信聊天记录, Emma 最后到警署报案并拍摄写有报案编号的卡片, 拍摄时的经纬值是多少?(检材:Emma 的手机)

A. 22.451721666667, 114.171853333333
B. 22.451553333333, 114.172845
C. 22.451928333333, 114.170503333333
D. 22.451638333333, 114.16993

2024I-Q19

Emma 的 iPhone XR 中\"IMG\_0008.HEIC\"的图像与相片名字为的\"5005.JPG\"看似为同一张相片, 在数码法理鉴证分析下, 以下哪样描述是正确?(检材:Emma 的手机)

A. 储存在不同的.db檔案里
B. 有不同哈希值
C. IMG\_0008.HEIC 为原图, \"5005.JPG\"为并非原图
D. IMG\_0008.HEIC 和名字\"5005.JPG\"是同一张相片

考点:微信消息 → 相册库,按 GUID 关联找经纬度

2025I-Q40 | 选择题

考的字段/表:ZASSET vs ZEXTATTR 的经纬度

APP \"照片\"中, \"IMG\_0027.HEIC\"的原地理位置信息(WGS84)是

A.(22.2816569, 114.1756115)
B.(22.2826366666667, 114.168503333333)
C.(22.2826216666667, 114.168525)
D.(22.2826216666667, 114.168503333333)

考点:两值冲突时如何取舍

2025I-Q30 | 选择题

考的字段/表:ZASSET 系列字段(含来源 App)

相册中有两张 GIF \"IMG\_0057.GIF\"及\"IMG\_0062.GIF\", 请指出由哪一个软件拍摄

A.Infltr
B.Discreet
C.Meitu
D.Prisma

考点:从相册库判照片由哪个软件产生

2025G-Q164/Q166 | 选择题

考的字段/表:ZEXTATTR.ZCAMERAMODEL

2025G-Q164

在此手机中, 请列出可以确定不是由此手机拍摄的图片文件(heic)完整文件名称(检材:冯子超的手机)

2025G-Q166

根据上一题,此图片文件是如何在此手机生成的(检材:冯子超的手机)

A. 接收自云端\"iCloud\"同步下载
B. 接收自即时通讯软件\"WhatsApp\"
C. 接收自即时通讯软件\"微信\"
D. 接收自空投(AirDrop)

考点:判「是否本机拍摄」;图片来源是 Safari 下载

四、WhatsApp:五年一届都没缺席的库

如果说 Photos.sqlite 是「信息密度最高」,那 WhatsApp 就是「出场次数最多」——2021 到 2025 五届,每一届的题目里都有它的身影。

届次 出现的库 典型问法
2021(团体/个人) wa.db (安卓) 某个账号下有哪些联系人、群组有哪些成员
2022(个人) ChatStorage 相关 机主安装了什么即时通讯软件
2023(团体/个人) ChatStorage.sqlite (iOS)、msgstore.db(安卓) 被编辑前的消息原文、锁定的对话、群组创建者
2024(团体/个人) msgstore.db 、ChatStorage.sqlite message_type 取值、媒体文件的本地路径
2025(团体/个人) ChatStorage.sqlite 、DeviceAgents.sqlite 已登录设备数、存档群组、投票记录、位置消息、群头像文件名、建群时间

有个规律值得注意:WhatsApp 的库读法在 iOS 和安卓上完全不同。它的安卓版和 iOS 版是两套独立实现,表名、字段名没有一点相似。所以做这类题的第一件事是先确认检材是哪个平台——看路径就知道:/data/data/com.whatsapp/ 是安卓,/var/mobile/Applications/group.net.whatsapp.WhatsApp.shared/ 是 iOS。

4.1 iOS:ChatStorage.sqlite

/var/mobile/Applications/group.net.whatsapp.WhatsApp.shared/ ├─ ChatStorage.sqlite        ← 聊天主库(核心) ├─ DeviceAgents.sqlite       ← 已登录设备(2025 考过) └─ Media/     ├─ Profile/              ← 头像(群组、联系人)     └─ <各种媒体子目录>      ← 收发的图片、视频、语音、文档

ChatStorage.sqlite 是标准的 Core Data 库,所以表名字段名全是 Z 开头:

表名 用一句话说 高频字段
ZWACHATSESSION 会话(一对一会话 + 群组会话都在这) 联系人 JID、昵称、存档标志、最后消息时间
ZWAMESSAGE 消息主表,一条消息一行 ZTEXT /ZFROMJID/ZTOJID/ZMESSAGETYPE/ZMESSAGEINFO/ZMEDIAITEM
ZWAMESSAGEINFO 消息的详细附加信息 ZRECEIPTINFO (Protobuf 格式的原始详情)
ZWAMEDIAITEM 媒体文件记录 文件本地路径、媒体类型、位置消息的精确经纬度
ZWAGROUPINFO 群组的元信息 群创建者 ID 、群主 ID
Z\_PRIMARYKEY /Z\_METADATA Core Data 通用表 查表名、库版本

4.1.1 ZWAMESSAGE:消息级提问的必查表

字段 含义 坑与实证
ZTEXT 消息正文 非文本消息这里可能是空或占位符,内容在别处
ZFROMJID 发送者 JID [email protected] 或群 ID [email protected]
ZTOJID 接收者 JID 群消息里收发双方都可能写成群 JID
ZMESSAGETYPE 消息类型枚举 实证:46 = 投票消息 (2025I-Q58)
ZMESSAGEINFO 指向 ZWAMESSAGEINFO.Z_PK 外键,要拿详情必须 JOIN 过去
ZMEDIAITEM 指向 ZWAMEDIAITEM.Z_PK 位置消息、图片、文件的实体信息在这
ZMESSAGEDATE 消息时间 Cocoa 时间戳
ZISFROMME 是否本机发出 判「谁发的」最直接的一个字段

4.1.2 ZWACHATSESSION:存档与群组

2025 年个人赛考「哪个聊天群被封存了」——题解特别提醒:「封存」是港台译法,大陆一般叫「存档」,英文是 Archive。对应的就是 ZWACHATSESSION 表里的那个存档标志字段(题解中记作 ARCHIVED,Core Data 风格命名通常带 Z 前缀,以你手上的库为准),值为 1 即为已存档。

同年团体赛还有一追问「这个群组的建立者完整手机号码」,靠的是 ChatStorage.sqlite 里的群信息记录。但 2023 年团体赛遇到了一个反例:题解发现 ZWAGROUPINFO 表中记着创建者 ID 的字段(ZCREATORJID)在三个目标群里全为空——这就是 4.3 节要讲的「群 ID 自带建群信息」那个技巧的用武之地。

4.2 群组 ID 本身就是一条线索(重点技巧)

这是近五年被反复考、但很多新手不知道的一个点:WhatsApp 的群组 ID(形如 [email protected])有两种格式并存,而老格式里直接编着建群者的手机号和建群时间。

格式 样子 能读出什么
老格式 <建群者手机号>-<建群时间 UNIX 时间戳>@g.us 例:[email protected] 建群者号码 = +852-63834763 建群时间 = 2019-07-20 15:26:13
新格式 <长数字 ID>@g.us 例:[email protected] 读不出建群信息,只能靠库里的记录

2025 年团体赛的那道题(问群组建立者的完整手机号码)就是靠解析群 ID 前那段数字拿到的,题解还额外用 ChatStorage.sqlite 里的建群时间记录做了交叉验证——把库里那个 Cocoa 时间戳换算成日期之后,和群 ID 里读出来的时间完全一致。

这道题还有后半段值得记:题解发现库里的「当前群主」和「建群者」不是同一个人,进而推断出这个群被转移过所有权。也就是说,两个 ID 不一样不是数据错,而是本身就有意义的线索。

✓ JID 的三种后缀

@s.whatsapp.net = 个人账号,@ 前面就是带国际区号的手机号(2023 年团体赛问「无人机卖家的电话号码」,答案就是从 JID 前半段读出来的);@g.us = 群组;@broadcast = 广播列表/状态。看到 @ 就自动去读前半段,这是条件反射级的基本功。

4.3 藏起来的详情:ZWAMESSAGEINFO 与 Protobuf

2025 年个人赛有一道高分题,问「总共在多少个投票活动中作出了投票」。这种题最容易被卡住——因为投票的选项、投票记录根本不在消息主表里。

题解的路径是这样的:先用 JID 过滤出目标群的消息,发现有投票消息,而它们的 ZMESSAGETYPE 都是 46;然后用 46 再筛,得到 3 条投票消息。但「投了几次票」这个信息还得往下钻——于是把 ZWAMESSAGEINFO 表 JOIN 进来:

SELECT ZWAMESSAGE.ZMESSAGETYPE,        ZWAMESSAGE.ZMESSAGEINFO,        ZWAMESSAGE.ZTEXT,        ZWAMESSAGE.ZFROMJID,        ZWAMESSAGE.ZTOJID,        ZWAMESSAGEINFO.ZRECEIPTINFO FROM ZWAMESSAGE RIGHT JOIN ZWAMESSAGEINFO         ON ZWAMESSAGE.ZMESSAGEINFO = ZWAMESSAGEINFO.Z\_PK WHERE ZMESSAGETYPE = 46;

关键在最后那一列 ZRECEIPTINFO——它存的是Protobuf 格式的十六进制字符串。题解把它丢进 CyberChef 解码,投票记录就出来了。而且题解还记了一个细节:只有群组内的投票保留投票记录,频道里的投票只留选项和 Reaction 信息——所以三个投票分别有 2、1、2 次记录,加起来是 3 次有效投票。

! 「主表只有一个指针」是通用设计

ZWAMESSAGE 里放 ZMESSAGEINFO,ZWAMESSAGEINFO 里放 ZRECEIPTINFO,而真正的复杂内容(投票、回复、引用、转发)藏在 Protobuf 里。凡是你觉得「这条消息明明有内容,库里却看不到」,就往这条链子上找:主表 → 外键 → 附属表 → Protobuf 字段。

4.4 位置消息:经纬度藏在 ZWAMEDIAITEM

2025 年个人赛连着考了三道位置题:某时刻发送的坐标是多少、以及那个坐标指向哪家餐厅。

题解给出的路径非常清晰,值得当模板背下来:

  • 第一步

:在会话里按时间定位到那条消息;
* 第二步

:读它的 ZMEDIAITEM 字段的值(题解里是 504);
* 第三步

:去 ZWAMEDIAITEM 表里 WHERE Z_PK = 504,拿到精确到一个极高小数位的经纬度;
* 第四步

:把坐标丢进地图工具反查地名(题解拿到的是某海鲜酒家)。

前面 3.5 节提到的「工具算的 GPS 与库里的不一致」那件事,就是在这一步被发现的——精确值只存在于 ZWAMEDIAITEM。

4.5 DeviceAgents.sqlite:登录设备数

2025 年团体赛问「这个 WhatsApp 账号连同本机在内一共登录了多少台设备」。答案不在聊天库里,而在旁边的 DeviceAgents.sqlite,表名 ZWASMBDEVICEAGENT——这张表里有几条记录,就是登录了几台设备。

✓ 这个库很容易被忽略

它静静躺在 WhatsApp 数据目录里,体量很小,但「多设备登录」这类题只有它答得了。养成习惯:把 WhatsApp 目录整个列一遍,别只盯着 ChatStorage。

4.6 安卓:msgstore.db

/data/data/com.whatsapp/databases/ ├─ msgstore.db          ← 消息主库(核心) ├─ msgstore.db-wal ├─ wa.db                ← 通讯录 └─ axolotl.db           ← 加密会话密钥

安卓版是一套完全不同的表结构,表名是普通的小写命名:

表名 作用 关键字段/关系
message 消息主表 _id (主键)、chat_row_id(→ chat._id)、message_type、text_data
chat 会话表 _id 、jid_row_id(→ jid._id)、会话名
jid 号码/账号表 _id 、user(JID 字符串)、raw_string
message\_edit\_info 消息的编辑记录 message_row_id (→ message._id)、编辑前后的内容
message\_ftsv2\_content 全文索引表,保留原始消息文本 docid (→ message._id)
media /message\_media 媒体文件 本地路径、文件哈希

4.6.1 经典联表:找出「被编辑前的原文」

2023 年团体赛那道题问「两部手机的对话曾被修改过,请找出修改前的内容」,是安卓 WhatsApp 联表查询的教科书级案例。题解把五张表串成了一条链子:

表 怎么接 拿到什么
message 起点,按会话筛出那 8 条消息 所有相关消息
message\_edit\_info message_row_id = message._id 筛出被编辑过的 4 条
chat _id = message.chat_row_id 确认这些消息属于哪个会话
jid _id = chat.jid_row_id 确认发送者是谁
message\_ftsv2\_content docid = message._id 原始消息内容 (编辑前的文本)

最后一条是点睛之笔:编辑功能只会改主表里的文本,而全文索引表里还留着没被改的那份。这也解释了一个新手常问的问题——「为什么同一个库里有两张表都存消息文本」。答案就一句:一张给前台看(改得动),一张给搜索用(改不着)。

4.6.2 message\_type 怎么查

2024 年团体赛问「message_type 为哪个值代表表情包(Sticker)」,答案是 20。题解的做法是:先在聊天记录里找到那条表情包消息,把它的接收时间转成时间戳,再去库里按时间筛出那一条,看它的 message_type。

这是这类题最稳的解法——不要背枚举表,用一条已知的消息反查。如果你不确定某个值是什么,用这句一次看清整个库的类型分布:

SELECT message\_type,        COUNT(\*) AS n,        substr(text\_data, 1, 30) AS sample FROM message GROUP BY message\_type ORDER BY n DESC;

每行给出一类消息的数量和一条样本内容,对照样本就能把枚举值反推出来。零记忆量,且绝对不会错。

i iOS 那边同理

ZWAMESSAGE.ZMESSAGETYPE 也可以这样自查:把 ZMESSAGETYPE 分组、每组抓一条 ZTEXT 看,就能自己建一张映射表。前面 4.3 节的「46 = 投票」就是这么来的。

4.7 本章真题索引(附原题)

下面把本章涉及的真题逐题列出——题干与选项按题解原文照录(含原文的繁体用字、半角标点与大小写,不作改写);每题只标「考的是哪个库、哪张表、哪个字段」,完整答案与解题过程见第九章。

2021G-Q30 | 选择题

库/表:wa.db · 联系人表

特普的电话中的 WhatsApp 账号 [email protected] 中,有哪些其他人的 WhatsApp 用户数据记录?

A. [email protected]
B. [email protected]
C. [email protected]
D. [email protected]

考点:从通讯录找 WhatsApp 账号

2021I-Q42 | 选择题

库/表:iOS WhatsApp 群组

多选题阿力士 iPhone XR 中的 WhatsApp 群组【团购-新鲜猪肉牛肉-东涌群组-9/30】有以下哪一个成员?

A. [email protected]
B. [email protected]
C. [email protected]
D. [email protected]

考点:群组成员判定

2023G-Q8/Q9 | 填空/简答(原题无选项)

库/表:ChatStorage.sqlite(ZWAGROUPINFO、ZWACHATSESSION)

2023G-Q8

无人机卖家的电话号码是多少?(检材:手机(Android))

2023G-Q9

李佩妍在 Facebook 建立了一个群组, 该群组的名称是什么?(检材:手机(IOS))

考点:群创建者;JID 前半段 = 手机号

2023G-Q82 | 填空/简答(原题无选项)

库/表:msgstore.db(五表联查)

在潘志辉手机华为 P30 Pro 的 WhatsApp 与华为 NOVA 5T 的 WhatsApp 的对话曾被修改过, 请找出修改前的内容.

考点:编辑前的消息原文

2023I-Q55 | 选择题

库/表:ChatStorage.sqlite

根据 ChatStorage.sqlite, 哪些对话已锁定?

A. [email protected]
B. [email protected]
C. [email protected]
D. [email protected]
E. status@broadcast

考点:「锁定」对话(题解翻遍全库未找到相关字段)

2024G-Q11 | 填空/简答(原题无选项)

库/表:msgstore.db · message_type

应用程序 WhatsApp 的数据库(msgstore.db)中, 哪个 message\_type 代表发送的内容是表情包(Sticker)?

考点:枚举值 = 20 是表情包

2024G-Q17 | 填空/简答(原题无选项)

库/表:WhatsApp JID

于\"三五成群\"群中,电子表格文件 Personal\_data.xlsx 是由哪一个电话号码发送到该群组的?

考点:从 JID 反推发送者号码

2024G-Q90 | 填空/简答(原题无选项)

库/表:ZWAMEDIAITEM.ZMEDIALOCALPATH

Alice 在 2024 年 8 月 19 日收到了一个包含 15 个人个人资料的 Excel 文件, 她是从哪一个平台下载的?

考点:文件落盘路径

2025G-Q158 | 选择题

库/表:DeviceAgents.sqlite · ZWASMBDEVICEAGENT

根据镜像文件\"FUNG\_CC\_mobile.zip\"已登录的 WhatsApp 账号, 连同本机在内已登录了多少个设备

A. 1
B. 2
C. 3
D. 4
E. 5个以上

考点:已登录设备数

2025G-Q181/Q182/Q183 | 填空/简答(原题无选项)

库/表:ChatStorage.sqlite+群 ID 格式

2025G-Q181

在所有手机中, 有哪一个 WhatsApp 群组是被封存的, 它的名称是什么(检材:冯子超的手机)

2025G-Q182

根据上一题, 该 WhatsApp 群组的 WhatsApp ID 是什么(检材:冯子超的手机)

2025G-Q183

根据上一题, 这个群组的建立者的完整手机号码(检材:冯子超的手机)

考点:存档群组、建群者、建群时间

2025G-Q187 | 填空/简答(原题无选项)

库/表:ChatStorage.sqlite · Media/Profile/

这个群组的现有的头像图片的完整文件名称

考点:群头像文件名

2025I-Q50/Q52/Q54 | 选择题

库/表:ZWACHATSESSION

2025I-Q50

即时通讯软件 WhatsApp 中, 封存了下列哪个聊天群?(检材:冯子超的手机)

A.凤凰VIP会员心得交流群
B.币淘 群组1
C.Sportsmen
D.Titus Wong Manson Finance

2025I-Q52

即时通讯软件 WhatsApp 中, 下列哪个是群组\"Investors\"的管理员(检材:冯子超的手机)

A.只有 i)
B.只有 i) 和 ii)
C.只有 ii) 和 iii)
D.以上皆是

2025I-Q54

即时通讯软件 WhatsApp 中, 社群名称是什么(检材:冯子超的手机)

考点:存档、群组管理员、社群名称

2025I-Q58 | 填空/简答(原题无选项)

库/表:ZWAMESSAGE+ZWAMESSAGEINFO

承上题, 总共在多少个投票活动中作出了投票

考点:投票消息与 Protobuf 详情

2025I-Q67/Q68/Q74 | 选择题

库/表:ZWAMEDIAITEM

2025I-Q67

在 WhatsApp 与 [email protected] 聊天对话中, 于 2025-05-16 11:33:39 时的信息所传送的座标(WGS 84)是(检材:梁燕玲的手机)

2025I-Q68

在 WhatsApp 与 [email protected] 聊天对话中, 于 2025-05-16 11:33:39 时的信息所传送的座标(WGS 84)所指的餐厅英文名称是(检材:梁燕玲的手机)

2025I-Q74

WhatsApp 聊天群组 Happy Sharing within 3 于 2025-04-17 10:12:34 传送的 WGS 84 座标是多少(检材:梁燕玲的手机)

A.22.323436345441, 113.276894376508
B.22.326923370361, 114.168403625488
C.21.239876452236, 115.925422314543
D.20.124955642236, 114.168403625488

考点:位置消息的精确坐标

五、其他六个常考库

除了相册和 WhatsApp,近五年还有几个库反复出现。它们的共同特点是体量小、表少、但每次都问到痛处。

5.1 NoteStore.sqlite:被加密的备忘录(2022 个人赛)

路径:/AppDomainGroup-group.com.apple.notes/NoteStore.sqlite

题目问「林浚熙手机里有一个备忘录被上了锁,这个备忘录的名称是」,下一题追问「承上题,上述备忘录的内容有一串数字是」。

核心表:ZICCLOUDSYNCINGOBJECT——这张表里能看到哪些笔记是加密的。题解特别指出一个坑:「这里有两个脚本被加了密」,也就是说光看「有没有加密」还不够,得解密之后才知道哪个里面真有数字。

解密是这题最难的部分,题解也踩了两个坑,值得完整记下来:

  • 坑一:现成解析脚本集体失效

——题解判断是 iOS 新版本 Notes 的库结构变了,「现有的解析脚本都不能顺利解析」。解法是改脚本里取字段的那两行:注释掉 AppleNoteStore.rb 中 Skipping Note ID 附近的整个 if/else 块,只保留赋值那一行;把 AppleNote.rb 里 to_csv、generate_html 两个函数引用的账号名、文件夹名改成空串;
* 坑二:环境必须在 Linux

——题解明说「不建议使用 Windows,因为在编译 Ruby 的 OpenSSL Gem 时会出问题」;如果 bundle install 卡住,是网络问题,换源到国内镜像即可;
* 最后一步

:拿弱口令字典跑 notes_cloud_ripper.rb,爆出密码 234567,解出备忘录标题 Halo、内容含 123456。

! 这题的知识点不在 SQL,在「工具链」

加密备忘录考的是你能不能把开源工具改到能用:看懂脚本在哪取字段 → 改掉不兼容的地方 → 换源解决依赖 → 跑起来。这也是本专题反复出现的一个信号:美亚杯的难题,难在工具链而不是知识点。

5.2 CallHistory.storedata:通话记录(2023、2024 都考了)

路径:/var/mobile/Library/CallHistoryDB/CallHistory.storedata

这张库有两个考点。第一是认表:2023 年个人赛问「哪份表格显示了通话记录」,答案是 ZCALLRECORD,干扰项是 ZCALLBPROPERTIES 和三个 Core Data 通用表。

第二是用表:2024 年个人赛要求「2024 年 8 月 30 日下午 2 点后 Emma 共致电 Clara 多少次」,题解只写了一句 SQL,把「时间过滤」和「按号码过滤」一次做完:

SELECT \* FROM ZCALLRECORD WHERE ZADDRESS = 63791704   AND ZDATE >= 746690400;

两个字段要记住:ZADDRESS(对方号码)和 ZDATE(通话时间,Cocoa 时间戳)。至于那个 746690400 是从哪来的——它是「2024-08-30 下午 2 点」换成的 Cocoa 秒数,第 6 章专门讲怎么算。题解还补了一句:Autopsy 里也能看到自动识别到的结果,但显示的是 UTC 时间——这就是时间题的第二个坑:时区。

5.3 AddressBook.sqlitedb:通讯录

路径:/var/mobile/Library/AddressBook/AddressBook.sqlitedb

2024 年个人赛用它来查号码归属:先在通讯录里找到 Clara 的手机号码,再拿这个号码去通话记录库里做条件。

这是「两个库接力」的标准范式,也是本专题最值得练熟的一条链:

✓ 「号码接力」三步

① AddressBook.sqlitedb 查出号码 ↔ 姓名的对应;② 拿号码去 CallHistory.storedata/WhatsApp 库/短信库做过滤条件;③ 结果再回通讯录翻译成人名。题目问「某人打了多少次电话」,考的就是这条链,不是某一张表。

5.4 sms.db:短信库(2023 个人赛点名)

iOS 的短信库在 /var/mobile/Library/SMS/sms.db,核心表是 message 和 chat——命名和 WhatsApp 安卓版很像(都是普通小写),容易混,注意区分路径。2023 年个人赛的候选题里点了它的名,考点是「短信记录在哪张表」这类认定题。

5.5 Manifest.db:iOS 备份的「文件总目录」

这个库不是 App 的,而是整份 iOS 备份的索引,路径就在备份根目录的 /var/ 下。

表/字段 含义 考点
Files 备份中所有文件的总表 想知道某个文件在备份里叫什么名字,查它
fileID 备份中的哈希文件名 备份目录下看到的那串乱码名
domain 所属域 如 AppDomain-com.tencent.xin、MediaDomain
relativePath 原始路径 还原「这个文件原本在手机上的哪个位置」
flags /file 标志与二进制内容 部分版本直接把小文件内容存在库里

结合 2.3 节讲的那四个文件(Manifest.db/Manifest.plist/Status.plist/*_DEC)一起记,iOS 备份这一关就通了。

5.6 安卓三大系统库

安卓的系统数据都由 Provider 提供,库名固定,遇到就是送分:

库 路径(均在 /data/data/ 下) 核心表 考点
contacts2.db com.android.providers.contacts/databases/ contacts 、raw_contacts、data、mimetypes 通讯录。注意要联 mimetypes 才能知道某一行数据是电话还是邮箱
mmssms.db com.android.providers.telephony/databases/ sms 、threads 短信。threads 是会话,sms 是单条
calllog.db com.android.providers.contacts/databases/ calls 通话记录。type 字段区分呼入/呼出/未接

i 安卓与 iOS 的命名差异,一眼区分

iOS 大多 Z 开头、驼峰式(ZASSET、ZCALLRECORD);安卓大多小写下划线(message、chat_row_id、text_data)。看到表名就能判断手上这个库来自哪个平台,考场上看错平台是很亏的。

5.7 微信相关:iOS 与安卓

微信在近五年的题量不算多,但 2024 年个人赛连着出了几道,值得单独记一下。

对象 路径/表 考点
iOS 聊天库 com.tencent.xin/Documents/<32位哈希>/message_2.sqlite 消息主表。图片消息存的是 XML 字符串,不是纯文本
iOS 视频号 .../finder/db/finder_main.db · 表 finderContactTable3 followState = 1 表示已关注 (2025I-Q48)。注意这是普通小写命名,不是 Core Data
安卓配置 com.tencent.mm_preferences.xml 最后登录的微信 ID(2024I-Q52)
iOS 配置 com.tencent.mm 相关 plist 微信 ID、版本号

5.7.1 微信图片消息的 XML:一个高频卡点

2024 年个人赛的解法里,有一个结构必须认识。题目要求找出「Emma 报案时拍摄卡片的经纬值」,题解的发现是:微信数据里编号最大的那个文件(314.pic)对应消息库里的编号,打开 message_2.sqlite 能看到这条消息的原始 XML:

        <![CDATA[F58B98FE-8010-44B7-8BF7-F23AF15DCFCA/L0/001]]>      

题解抓住了其中最容易被忽略的一节:m_assetUrlForSystem 里的那个 GUID(F58B98FE-...-F23AF15DCFCA),它是系统相册的资产标识。拿着这个 GUID 回到 iOS 相册库 Photos.sqlite 一搜,就找到了对应的照片记录,经纬度立刻出来了。

✓ 这条链子是本专题最漂亮的一环

微信消息库 → 消息 XML 里的 GUID → 相册库 ZASSET.ZUUID → 经纬度。跨了两个 App、三个库,靠一个 GUID 串起来。2024 年个人赛还有一题(比较 IMG_0008.HEIC 与 5005.JPG)走的是同一条链:先在相册库确认 IMG_0008.HEIC 的存在,再发现它的 UUID 出现在微信聊天记录里,从而判断后者是发送时生成的压缩副本。

同一道 XML 里另外几个字段也值得记一下,都是「文件在哪、是不是加密的」这类题的基础:

字段 含义 用途
aeskey 图片的 AES 密钥 图片文件本体被加密 ,要用它解密
encryver 加密版本标记 判断加密方式
md5 文件 MD5 与磁盘上的 .pic 文件比对,确认对应关系
originsourcemd5 原图 MD5 区分原图与压缩图
filekey 文件名键 格式为 <wxid>_<编号>_<时间戳>,编号与磁盘上的文件名对应,时间戳可换算成收图时间
m_assetUrlForSystem 系统相册 GUID 通向 Photos.sqlite 的桥

5.8 本章真题索引(附原题)

下面把本章涉及的真题逐题列出——题干与选项按题解原文照录(含原文的繁体用字、半角标点与大小写,不作改写);每题只标「考的是哪个库、哪张表、哪个字段」,完整答案与解题过程见第九章。

2022I-Q37/Q38 | 填空/简答(原题无选项)

库/表:NoteStore.sqlite · ZICCLOUDSYNCINGOBJECT

2022I-Q37

林浚熙手机里有一个备忘录被上了锁,这个备忘录的名称是(检材:林浚熙的手机)

2022I-Q38

承上题,上述备忘录的内容有一串数字是(检材:林浚熙的手机)

考点:加密备忘录:先判加密、再爆破解密

2023I-Q64 | 选择题

库/表:CallHistory.storedata · ZCALLRECORD

根据 CallHistory.storedata, 哪份表格显示了通话记录?

A. ZCALLBPROPERTIES
B. ZCALLRECORD
C. Z\_2REMOTEPARTICIPANTHANDLES
D. Z\_METADATA
E. Z\_MODELCACHE
F. Z\_PRIMARYKEY

考点:认表(干扰项是 Core Data 通用表)

2024I-Q2 | 选择题

库/表:CallHistory.storedata+AddressBook.sqlitedb

2024 年 8 月 30 日下午 2 点后 Emma 共致电 Clara 多少次?

A. 85
B. 86
C. 87
D. 88

考点:号码接力 + 时间过滤

2024I-Q52 | 填空/简答(原题无选项)

库/表:com.tencent.mm_preferences.xml

根据\"com.tencent.mm\_preferences.xml\", David 的手机最后登录微信的微信 ID 是?

考点:微信 ID

2024I-Q1/Q19/Q12 | 选择题

库/表:message_2.sqlite

2024I-Q1

Emma 和 Clara 的微信聊天记录, Emma 最后到警署报案并拍摄写有报案编号的卡片, 拍摄时的经纬值是多少?(检材:Emma 的手机)

A. 22.451721666667, 114.171853333333
B. 22.451553333333, 114.172845
C. 22.451928333333, 114.170503333333
D. 22.451638333333, 114.16993

2024I-Q19

Emma 的 iPhone XR 中\"IMG\_0008.HEIC\"的图像与相片名字为的\"5005.JPG\"看似为同一张相片, 在数码法理鉴证分析下, 以下哪样描述是正确?(检材:Emma 的手机)

A. 储存在不同的.db檔案里
B. 有不同哈希值
C. IMG\_0008.HEIC 为原图, \"5005.JPG\"为并非原图
D. IMG\_0008.HEIC 和名字\"5005.JPG\"是同一张相片

2024I-Q12

Emma 发送了多少张 .PNG 图片给 Clara, 证明自己正被人追债?(检材:Emma 的手机)

A. 6
B. 7
C. 8
D. 9

考点:图片消息 XML、跨库 GUID 关联

2025I-Q47/Q48 | 选择题

库/表:finder_main.db · finderContactTable3

2025I-Q47

请指出即时通讯软件 WeChat 的 WeChat ID(检材:冯子超的手机)

2025I-Q48

承上题, 这个 WeChat ID 关注了多少个视频号(检材:冯子超的手机)

A.1
B.2
C.3
D.4

考点:视频号关注(followState = 1)

2025I-Q10/Q30 | 选择题

库/表:App 列表 + 相册库

2025I-Q10

安装了以下即时哪个通讯软件?(检材:陈民浩的手机(iOS))

A.只有 i) 和 ii)
B.只有 i), ii) 和 iii)
C.只有 i), ii) 和 iv)
D.以上皆是

2025I-Q30

相册中有两张 GIF \"IMG\_0057.GIF\"及\"IMG\_0062.GIF\", 请指出由哪一个软件拍摄(检材:冯子超的手机)

A.Infltr
B.Discreet
C.Meitu
D.Prisma

考点:从应用与数据判「装了什么/用了什么」

六、时间戳:跨库比对的命门

先说一个判断:近五年手机数据库题里,超过一半的题目都会碰到时间——「某时刻的消息」「某天之后打了几次电话」「什么时候建的群」。而时间题的失分,九成不是不会 SQL,是没换算对。

所以这一章只有一件事:把时间戳讲透。

6.1 为什么不换算就必错

数据库里存的时间,绝大多数不是给人看的那种,而是一串整数——「从某个纪元开始数,过了多少秒」。你拿到的 746690400 看不出是几点,而题干问的是「下午 2 点后」。换算这一步不做,后面全废。

6.2 五种时间格式,一张表分清

格式 纪元起点 位数感觉 常见于
UNIX 时间戳 1970-01-01 00:00:00 UTC 10 位(秒)/13 位(毫秒) 安卓(多数为毫秒)、WhatsApp 安卓、日志
Cocoa Core Time 2001-01-01 00:00:00 UTC 8—9 位 iOS 全系 (ZDATE、ZDATECREATED)
WebKit/Chrome 时间 1601-01-01(Windows FILETIME 系) 17 位(微秒) 浏览器历史、部分系统日志
毫秒时间戳 同 UNIX,但单位是毫秒 13 位 安卓库最常见
可读字符串 — 如 2025-05-16 11:33:39 配置类、日志类。注意它不自带时区

✓ 一眼判断法是哪种

看位数。8 位半(746690400)左右,且算出来落在 2001 年之后 → Cocoa;10 位 → UNIX 秒;13 位 → UNIX 毫秒;17 位 → 微秒级。如果换算出来的年份离谱(比如 1970 或 2080),先怀疑纪元错了,再怀疑单位错了。

6.3 Cocoa ↔ UNIX:只差一个常数

这是本文最该背下来的一个数字:

Cocoa Core Time + 978307200 = UNIX 时间戳 UNIX 时间戳 - 978307200 = Cocoa Core Time  为什么?Cocoa 从 2001-01-01 起算, 而 2001-01-01 00:00:00 UTC 对应的 UNIX 时间戳正好是 978307200。

在 SQL 里换算成可读时间,就一句:

-- Cocoa → 可读时间(本地时间) SELECT datetime(ZDATE + 978307200, 'unixepoch', 'localtime');  -- UNIX(秒)→ 可读时间 SELECT datetime(ZDATE, 'unixepoch', 'localtime');  -- UNIX(毫秒)→ 可读时间 SELECT datetime(ZDATE / 1000, 'unixepoch', 'localtime');  -- 反向:把题干的时刻换成时间戳,用作筛选条件 SELECT strftime('%s', '2024-08-30 14:00:00') - 978307200;

最后那句反向换算是最实用的——题干给的是人话,你要给它换成库里那串数字。2024 年个人赛那道通话题用的 746690400,就是这么算出来的。

6.4 用真题验算一遍

空口说不算数,拿两道真题的数字实际算一次。

真题 库里那个数 换算 结果
2024I-Q2「8 月 30 日下午 2 点后」 746690400 (Cocoa) +978307200 = 1724997600,再转 UTC 2024-08-30 06:00:00 UTC 即香港时间 14:00 ✓
2025G-Q183「建群时间」 1563607573 (UNIX) 直接转 UTC 2019-07-20 07:26:13 UTC 即香港时间 15:26:13 ✓

两个结果都和题解一致。特别注意第二个——UTC 是 07:26,加上 8 小时才是题解写的 15:26。这就是下一节要说的时区问题。

6.5 时区:时间题最大的坑

同一个时间戳,在不同时区显示的时间是不同的。香港是 UTC+8,北京也是 UTC+8,所以美亚杯的答案通常按当地(香港)时间给。但工具默认可能显示 UTC。

  • 血泪案例

:2024 年个人赛题解明确写道,「在 Autopsy 中也可以看到自动识别到的结果(时间显示为 UTC)」——如果直接抄工具显示的数字,就会差 8 小时,和题目给的「下午 2 点」对不上;
* SQL 里的开关

:加 'localtime' 是按运行 SQL 的那台机器的时区换算。如果你的电脑不在东八区,结果会偏——稳妥做法是先按 UTC 算出来,再手动 ±8 小时,这样可控;
* 另一种更稳的写法

:datetime(值, 'unixepoch', '+8 hours'),直接写死偏移量,不依赖运行环境。

! 答题时养成一个习惯

凡是写时间的答案,在答案里带上时区或写明换算依据。例如「2025-04-29 08:31:02(HKT,即 UTC+8)」——这样即使阅卷方用的时区不同,也能看出你的思路是对的。

6.6 换算时的四个细节

细节 说明 怎么办
秒还是毫秒 安卓库常常是毫秒,比 Cocoa 大三个数量级 先看位数。13 位一律先 /1000
浮点数 ZDATE 可能是小数(含毫秒的小数部分) SQLite 的 datetime() 能处理小数,不必先取整
0 与负值 Cocoa 的 0 就是 2001-01-01;负值表示 2001 年之前 不要看到负值就以为数据坏了
NULL 空值 字段为空时换算结果是 NULL,在 WHERE 里会比较失败 先 WHERE ZDATE IS NOT NULL 过滤掉空值

第三点有个现成的例子:2023 年个人赛那道联表题,题解在分析正确选项时特意加了一句 date.arrival_timestamp_HK IS NOT NULL——就是为了排掉空值。它说明出题人知道新手会在这里栽。

七、联表查询:把两张表接起来

如果只能从这篇文章带走一个技能,带走这个。近五年难度高的数据库题,几乎都是联表题——因为单表能问的东西有限,一旦问「谁发的、发到哪个群、那个群叫什么名字」,就必然跨表。

7.1 为什么必须联表:一个典型结构

以安卓 WhatsApp 为例,信息是刻意拆开放的:

message 表                         jid 表 ┌────────┬──────────────┐       ┌──────┬────────────────────────┐ │ \_id    │ chat\_row\_id  │       │ \_id  │ user                   │ ├────────┼──────────────┤       ├──────┼────────────────────────┤ │ 101    │ 7            │──┐    │ 7    │ [email protected] │ │ 102    │ 7            │  │    └──────┴────────────────────────┘ └────────┴──────────────┘  │              ▲                            │              │ chat 表                    └──────────────┘ ┌──────┬──────────────┐ │ \_id  │ jid\_row\_id   │ ├──────┼──────────────┤ │ 7    │ 7            │ └──────┴──────────────┘

消息表里没有「是谁发的」,只有一个 chat_row_id;会话表里没有名字,只有一个 jid_row_id;号码在第三张 jid 表里。想知道「这条消息是谁发的」,必须穿过三张表。这不是设计得不好,而是数据库的规范做法——避免同一个号码重复存一万遍。

7.2 外键的三种长相

找外键这件事看着玄,其实命名很有规律。记住三种长相,能解决九成情况:

长相 例子 怎么猜它指向谁
X_PK ZASSET.Z_PK 、ZWAMESSAGEINFO.Z_PK 这是被指向方(主键)
X_行号 型 chat_row_id 、message_row_id、jid_row_id xxx_row_id → 指向 xxx 表的 _id
ZXXX 同名型 ZWAMESSAGE.ZMESSAGEINFO → ZWAMESSAGEINFO.Z_PK;ZASSET.ZEXTENDEDATTRIBUTES → ZEXTENDEDATTRIBUTES.Z_PK 字段名就是目标表的表名 (去掉 Z 前缀、补全称)

✓ 不确定指向谁?两条命令搞定

① PRAGMA foreign_key_list(表名); —— 如果建表时声明了外键,这里直接列出来;② 没声明的话,用值去试:把那个字段的值拿到候选表里 WHERE Z_PK = 那个值 查一下,命中就说明关系成立。第二种在 iOS 的 Core Data 库里特别常用,因为 Core Data 默认不在库里声明外键。

7.3 四种 JOIN,用「两本名册」理解

把两张表想成两本名册:左表是「消息名册」,右表是「号码名册」,两本都有「编号」这一列,JOIN 就是按编号把两边对齐。

写法 含义 通俗说法 什么时候用
INNER JOIN 只保留两边都能对上的 两本都有的人才留下 最常用 。要找「有人有号码的完整记录」
LEFT JOIN 保留左表全部,右表没有就填 NULL 左表是主角,右表是补充 要找「左表全部记录,顺便看看右表有没有」
RIGHT JOIN 保留右表全部,左表没有就填 NULL 反过来 2025I-Q58 那段 SQL 用的就是这个
CROSS JOIN 两边全组合 笛卡尔积,结果会爆炸 几乎不用。忘了写 ON 条件就会退化成它

! 最常见的翻车:忘了 ON

写成 FROM A JOIN B 而不写 ON A.x = B.y,SQLite 不会报错,而是给你两表行数相乘的结果。1000 行 × 5000 行 = 500 万行,查询卡死,你还以为是自己写错了条件。看到查询迟迟不返回,先检查 ON 有没有写。

7.4 四种真题联表范式

范式一:顺着外键链一路穿(2023G-Q82,五张表)

这是本文最长的一条链,也是安卓 WhatsApp 的经典结构。题解把起点、过滤器、终点列得很清楚:

顺序 表 接入条件 作用
① message 起点 筛出目标会话的 8 条消息
② message_edit_info message_row_id = message._id 筛出 4 条被编辑过的
③ chat _id = message.chat_row_id 确认所属会话
④ jid _id = chat.jid_row_id 确认发送者是谁
⑤ message_ftsv2_content docid = message._id 取编辑前的原文 ,答案是「再換busd」

这条链的价值在于它示范了「一路 JOIN 到底」的写法——从一个 _id 出发,每经过一张表就顺手取走一个信息,最后拼出完整答案。写的时候不要一次想全,一段一段加,每加一段就跑一次看结果。

范式二:JOIN 到附属表取详情(2025I-Q58)

前面 4.3 节讲过那条 SQL,用的是 RIGHT JOIN:ZWAMESSAGE.ZMESSAGEINFO = ZWAMESSAGEINFO.Z_PK,目的是把 Protobuf 格式的 ZRECEIPTINFO 取出来。范式特征是「主表筛、附表取」——筛选条件写在主表字段上,输出列却来自附表。

范式三:题目直接考 SQL 本身(2023I-Q98)

这道题很特别——它不给数据,只给你两个库的结构和四个 SQL 选项,问哪一个能正确「找出谁前往莫斯科」,并输出转换后的本地时间。题解逐条分析了每个选项,四个错误点全都不一样:

选项 问题 错在哪类知识
A 语法本身能跑,但缺了 IS NOT NULL 之类的限定 题解认为 A 与 D 都符合题意,属题目不严密
B ON customer_id = date.id —— 两表连接时字段名没带表前缀,应是 cus.customer_id 联表时字段名歧义
C 没有做时间戳转换 漏了 datetime(..., 'unixepoch', 'localtime')
D 与 A 相比多了 IS NOT NULL,把空值排掉 正确选项(题解认可)

这道题把第七章要讲的三个坑一次性考全了:字段名要带表前缀、时间要转换、空值要过滤。注意正确答案里 datetime(date.arrival_timestamp_HK, 'unixepoch', 'localtime') AS arrival_time_hk 这一句——它同时做了三件事:指定源字段、指定纪元、指定时区,最后还给结果改了列名。

范式四:跨库接力(2024I-Q2)

这类题目不在一张库内部 JOIN,而是手工接力:先在通讯录库查出号码,再拿号码去通话记录库做条件。因为 SQLite 默认不能在两条 SQL 里跨文件 JOIN(除非用 ATTACH),所以考场上的常规做法就是分两次查、人脑接。

✓ 也可以让 SQLite 帮你接

先进命令行执行 ATTACH DATABASE 'AddressBook.sqlitedb' AS ab;,之后就能在一条 SQL 里 JOIN ab.ZABCDRECORD 了。不过实践中手工接力更快也更不容易错——结果集小的时候,两次查询 + 复制粘贴比写跨库 SQL 稳。

7.5 聚合:怎么回答「多少次」「多少个」

「多少次电话」「多少张图」「多少个群」这类问题,靠的是聚合函数:

函数 作用 典型题目
COUNT(\*) 数行数 「打了多少次电话」——过滤完直接 COUNT
COUNT(DISTINCT 字段) 数去重后的个数 「涉及多少个人」——同一人发多条只算一个
GROUP BY 按某字段分组 「每个人各发了多少条」
SUM /MAX/MIN 求和/最大/最小 「最后一通电话是什么时候」(MAX 时间)

一个组合技,专治「有多少个不同的 X」:

SELECT COUNT(DISTINCT ZTOJID) AS 联系过的人数 FROM ZWAMESSAGE WHERE ZISFROMME = 1;

! COUNT 的两个常见误用

① COUNT(字段)不数 NULL,COUNT(*) 才数所有行——想数「全部尝试次数」要用后者;② 忘记 DISTINCT 会重复计数——题目问「多少个人」你却返回「多少条消息」,这是最常见的失分点。

7.6 联表五个坑,逐个拆

坑 症状 解法
忘了 ON 结果行数暴增、查询卡死 检查每个 JOIN 后面都有 ON
字段名歧义 报 ambiguous column name 所有字段都加表前缀 :cus.customer_id 而不是 customer_id
空值参与比较 条件筛掉/漏掉记录 IS NOT NULL ;空值不能用 = 比较,要用 IS NULL
类型不匹配 数字和字符串比较,结果对不上 JID、号码这类在库里可能存成文本,比较时加引号
以为只有一张表有数据 查不到就下结论「数据不存在」 同一信息可能在多张表里各存一份 (如 ZASSET 与 ZEXTATTR 的经纬度)

八、SQL 速成:够用就好的八个句式

你不需要成为 SQL 工程师。看懂 + 改写上面这些真题 SQL,需要掌握的就只有八个句式。这一章按「从最常用到最不常用」排。

8.1 八个句式

句式 样子 干什么 真题里长啥样
SELECT SELECT 字段1, 字段2 FROM 表 选列 SELECT Z_PK, ZFILENAME FROM ZASSET
WHERE WHERE 条件 AND 条件 筛行 WHERE ZADDRESS = 63791704 AND ZDATE >= 746690400
LIKE WHERE 字段 LIKE '%.HEIC' 模糊匹配。% = 任意多个字符,_ = 一个字符 WHERE ZFILENAME LIKE '%.HEIC'
ORDER BY ORDER BY 字段 DESC 排序(DESC 倒序) 按时间倒序找「最后一条」
LIMIT LIMIT 10 只看前 N 行 先看看数据长什么样
GROUP BY GROUP BY 字段 分组统计 GROUP BY message_type 反查枚举含义
JOIN ... ON JOIN 表2 ON 表1.x = 表2.y 联表 见第七章
IN / BETWEEN WHERE 字段 IN (a, b) 多值匹配 / 区间 筛多个号码、某个时间段

8.2 三个最实用的现成模板

下面三段可以直接背下来改字段名用。

模板一:查「某时刻发生了什么事」

SELECT \* FROM ZWAMESSAGE WHERE ZMESSAGEDATE BETWEEN 749000000 AND 749100000 ORDER BY ZMESSAGEDATE;

模板二:查「某人物相关的所有记录」

SELECT \* FROM ZCALLRECORD WHERE ZADDRESS = <号码>   AND ZDATE >= <起始时间戳> ORDER BY ZDATE;

模板三:自查某字段有哪些取值(万能起手式)

SELECT <可疑字段>, COUNT(\*) AS n FROM <表名> GROUP BY <可疑字段> ORDER BY n DESC LIMIT 30;

第三个模板是本文最有用的「万能开局」。任何陌生的枚举字段(消息类型、状态码、方向、来源),先用它把取值分布拉出来,数量多的那几类通常就是「普通消息」,稀有的那几类就是「考点」。

8.3 真题剖析:一道考 SQL 语法的题(2023I-Q46)

这道题考得很特别——题干说「一个名为 Account 的表拥有 5 个列」,然后问「以下哪一个指令会产生错误讯息」:

选项 语句 会不会报错 原因
A SELECT * from Account WHERE name='Alex' OR '1'=1 不报错 '1'=1 恒真,是全表返回——这是经典的 SQL 注入写法,语法完全合法
B ... UNION SELECT NULL, NULL, NULL, NULL 会报错 左边 5 列、右边 4 列,列数不一致。报错信息是 The used SELECT statements have a different number of columns
C SELECT * from Account WHERE name='Candy' ORDER BY 6 会报错 (本题答案) 表只有 5 列,ORDER BY 6 超出上限
D SELECT name FROM sys.tables 会报错 sys.tables 是 SQL Server 的系统视图,SQLite 里不存在这张表

题解的判断是:「五个列,ORDER BY 6 显然超出上限」,选 C。它还老老实实补了一句——「B 也会报错,但是和题意不符」。

i 这道题真正在考什么

考的是「你对 SQL 的边界有多熟」。四个选项分别踩在四种边界上:恒真条件、列数必须一致、排序列号不能越界、系统表不是通用的。这类题不需要你有检材,纯语法知识就能拿分,是性价比最高的分——考前花半小时把这几条边界过一遍就够。

8.4 用什么工具写 SQL

工具 适合什么 备注
DB Browser for SQLite(DB4S) ★ 首选。图形界面,能直接点开表看数据、写 SQL、导出 CSV 五届题解里出现频率最高的数据库工具之一,免费
Navicat Premium 商业工具,界面更顺手,导出 CSV 方便 2025G-Q164 那道题就是「把 Navicat 的查询结果导出为 CSV 再筛」
命令行 sqlite3 脚本化、批量处理、.headers on 看列名 Linux 自带,适合配合 PRAGMA 用
Python + sqlite3 批量导出表结构、自动化处理(见 2.5 节那段脚本) 适合需要反复跑的活儿

✓ 导出 CSV 这一招别忘

很多题目的答案需要排序、筛选、比大小,在 SQL 界面里滚动看很痛苦。导出成 CSV 用 Excel 打开,筛选排序一秒搞定。2025 年团体赛题解就是这么处理相机型号那一列的。

九、近五年真题逐题还原(2021—2025)

前面八章讲的是「库、表、字段、怎么查」。这一章换个方向:把五届真题里真正考到数据库的题,按届一道一道摊开——题干和选项照抄题解原文,下面再分四段写解题思路——答案/用到的工具/知识点/解析,能有多条路的题在「解析」里给出「另解」。看完这一章,你会对「考试到底怎么考」有具体印象,而不是停在概念上。

i 读法:先看「原题怎么问」,再看四段解题思路

每一道题一张卡片,结构固定:题干与选项(照抄题解原文,选择题全部列出)+ 四段解题思路:
① 答案——以题解记录的为准,题解标了「存疑」或「官方答案有误」的照实标注;
② 用到的工具——这一步用什么开的库、拿什么算的哈希、跑的是哪个脚本;
③ 知识点——这道题真正在考的那条规则(库结构、字段语义、时间戳换算、联表方式);
④ 解析——解题过程分步写,能有多条路的地方写「另解」:题解的路子往往不是唯一解,考场上有更快的走法。
题号写法是「届次+赛道+题号」——2023G-Q82 里的 G 是团体赛,I 是个人赛;题干与选项按题解原文照录,含原文的繁体用字、半角标点与大小写,不作改写。

9.1 收录标准:什么样的题算「数据库题」

两年下来我一共挑出 87 道。挑的标准只有一条——答案的落点必须是某个库的某张表的某个字段,具体分三种情况:

  • 问的就是数据库结构本身

:比如「哪个栏目标题可以显示接收方式」(2022I-Q34)、「哪份表格显示了通话记录」(2023I-Q64)——这类题不懂表名字段名就是零分。
* 必须用 SQL 才能算出来

:计数、求和、按条件筛、联表比对。火眼的界面给不了这种答案,只能自己写语句。
* 火眼解析不出来的库

:第三方 App 自建的库、被压缩或编码过的字段、以及加密的陈年格式。这类题只能手动开库。

! 一个容易误解的地方

「聊天记录在哪」不等于「这题要读数据库」。
像「王晓琳发出这个 PDF 的原因」「两人的对话显示了什么关系」这类题,答案虽然也躺在 WhatsApp 的库里,但火眼的聊天记录分析已经能直接给出来,不需要你写 SQL——所以没有计进这 87 道。
本章收的是「必须动数据库才能拿到答案」的那一批,这也是最难、最容易丢分的一批。

9.2 2021 年:数据库题刚冒头(6 题)

这一年数据库题很少,而且集中在两类:安卓 WhatsApp 的通讯录库和iOS 的蓝牙、相册数据库。考法也简单——知道去哪张表里翻就行。

9.3%202022%20年:个人赛独撑(10%20题)

2022%20年团体赛那道「WordPress%20比特币标题题」考的是服务器侧的%20MySQL,不属于手机数据库,本章不列。手机数据库题全部来自个人赛,而且出现了两个此前没考过、后来反复考的库:Photos.sqlite 与 NoteStore.sqlite。

✓%20这一年最值钱的一条经验

2022I-Q38 说明了一件事:现成工具解不出来的题,才是拉分题。
题解没有换工具,而是打开脚本源码、改掉取字段的那两行——因为「我们只需要标题和内容两个字段」,其他字段全都可以不管。
读懂脚本在取哪个字段,比换一个更贵的工具有用得多。

9.4%202023%20年:从「在哪张表」升级到「怎么把表接起来」(18%20题)

这一年题量翻倍,考法也变了:开始考联表。最有代表性的是团体赛 Q82——一道题串起%20WhatsApp%20安卓库的四张表;个人赛 Q98 干脆让你自己写一段%20SQL。

团体赛(9%20题)

个人赛(9%20题)

✓%20这一届给出的三张「答案地图」

① 系统表当排除项:Z_METADATA/Z_MODELCACHE/Z_PRIMARYKEY 是%20Core%20Data%20的固定配件,问「哪张表存业务数据」时先排除它们。
② 数字类答案多半要计数:45、7%20这两个答案,都是「按某个后缀或条件筛完再数」。
③ 跨库比对才会给对:Q58%20的%2010%20与%207%20就是一次典型陷阱。

9.5%202024%20年:成为主力题型(19%20题)

两届加起来%2019%20题,而且开始出现「同一批检材跨库关联」的考法:微信的聊天记录%20→%20关联相册库拿经纬度、档案名在相册库与微信库之间交叉验证。这一年也是实况照片(Live%20Photo)判定第一次成体系地出现。

团体赛(9%20题)

个人赛(10%20题)

✓%20这一年留下的三条可复用套路

① 「用时间换记录」:先把时间换算成时间戳,再去库里筛那一条(2024G-Q11、2024I-Q2 都是这么做的)。
② 「一个值串两个库」:UUID/GUID%20是跨库的桥(2024I-Q19)。
③ 「工具没显示,不代表库里没有」:UUID、后置镜头这类字段,火眼的界面不展示,但库里有(2024I-Q8)。

9.6%202025%20年:绝对主力(34%20题)

这一年两届一共%2034%20道,是全五届最多的一年,也是考法最成熟的一年:相册库连着%209%20道题、同一个字段的两组值要判断该信哪一个、还要从字段格式反推时间、从群组%20ID%20反推创建者手机号。

团体赛(17%20题)

个人赛(17%20题)

!%202025%20年这批题里,四处「答案或题干本身有问题」

这一届题解的复盘质量很高,把出题瑕疵都标了出来,值得单独记住:
① 检材标错:160—168%20题说用冯子超的%20iPhone,答案却取自陈民浩的%20iPhone;169—177%20题同理(2025G)。
② 字段用错:官方题解用 ZDATECREATED 排序,但「写进数据库的时间」应该是 ZADDEDDATE。
③ 题干与选项不符:Q164%20要求%20heic%20文件,实际答案却是%20JPG;Q166/Q167%20直接标「此题无解」。
④ 库内两值打架:同一文件的经纬度在两张表里不一致(2025I-Q40)。
考场上遇到这种题,把依据写清楚比猜一个答案更划算。

9.7%20回头看第三到第五章:库的出现频次

把上面%2087%20道题按「库」重新归一次类,就得到一张很实用的表——哪些库是必考的、哪些是一届一现的:

库 出现届次 代表题号 一句话考点
Photos.sqlite 五届全勤%20(2021—2025) 2021I-Q37;2022I-Q33/Q34/Q35;2023I-Q58/Q59;2024I-Q22/Q23;2025I-Q30/Q40/Q64;2025G-Q160—Q168 字段最多、坑最多。字段名(ZIMPORTEDBY…)、来源%20App、两组经纬度取舍、Live%20Photo%20判定、ZADDEDDATE vs ZDATECREATED
ChatStorage.sqlite%20(iOS%20WhatsApp) 四届:2021/2023/2024/2025 2021I-Q8;2023I-Q55/Q56/Q62;2024G-Q18;2025G-Q183/Q187/Q189;2025I-Q50 锁定/存档(ZWACHATSESSION)、ZWAMESSAGE 投票(type%2046)、群组%20ID%20拆手机号、头像文件名里藏时间戳
msgstore.db%20(安卓%20WhatsApp) 三届:2021/2023/2024 2021G-Q30(wa.db);2023G-Q82;2024G-Q11 四表串链(message/message_edit_info/chat/jid)、message_type 取值
NoteStore.sqlite 2022 2022I-Q37/Q38 加密备忘录要看 ZICCLOUDSYNCINGOBJECT,解密要改脚本取字段位置
CallHistory.storedata 两届:2023/2024 2023I-Q64;2024I-Q2 表名 ZCALLRECORD;和 AddressBook.sqlitedb 接号码后按时间计数
sms.db 2023 2023I-Q60 按%20GUID%20定位验证码短信
AddressBook.sqlitedb 2024 2024I-Q2 查号码,作为通话记录计的输入
MobileBluetooth.ledevices.other.db 两届:2021/2024 2021I-Q9/Q32/Q33;2024I-Q8 UUID%20与%20MAC%20两个字段;火眼默认只显示%20MAC
DeviceAgents.sqlite 2025 2025G-Q158 ZWASMBDEVICEAGENT%20表数记录%20=%20已登录设备数
finder_main.db%20(微信) 2025 2025I-Q48 finderContactTable3%20表,followState=1%20为已关注
message_2.sqlite%20(微信) 2024 2024I-Q1/Q3 消息的%20XML%20原始数据里带经纬度;可与附件文件编号互查
EnMicroMsg.db%20(安卓微信) 2024 2024I-Q41 库名本身即答案
client.db%20(CloudDocs) 2025 2025I-Q23;2025G-Q253 iCloud%20Drive%20同步记录
第三方%20App%20自建库 四届:2022—2025 2022I-Q10/Q11/Q12/Q31;2023G-Q3/Q5/Q7/Q83;2024G-Q125/Q126/Q127;2025I-Q12/Q19/Q43 火眼普遍没有解析%20——iBooks、waze、MTR、Fitbit、Carousell、Foodpanda、hiPrint、Send%20Anywhere、POE,只能手动开库

✓%20从这张表能读出三件事

① 两个库必须练到闭眼能开:Photos.sqlite 与 ChatStorage.sqlite,五届里几乎每届都考,而且都是多题连考。
② 第三方%20App%20的库是「送分题与丢分题的混合区」——它们本身不难,难在火眼不给解析、你也不知道该去哪个目录找。
③ 安卓%20WhatsApp%20与%20iOS%20WhatsApp%20是两套表,别把 msgstore.db 的表名往 ChatStorage.sqlite 上套。

9.8%20同届还有一批「数据库题」,但不在本章范围

为了不让你误会「数据库题就这些」,这里把同届考到、但属于服务器侧数据库的题一并列出来。它们同样要开库、写%20SQL,只是不在手机里,而是落在服务器镜像、虚拟机或备份文件上:

届次 题号 数据库类型 考什么
2022%20团体 Q6、Q9 MySQL(WordPress) wp_comments%20表按 comment_post_ID 关联文章;用户全名要从%20WordPress%20库取
2022%20个人 Q68、Q69 MySQL(Docker%20容器) 哪个库存了大量个人资料、某人的出生日期
2023%20团体 Q43、Q46、Q48 MySQL 库密码(从 .bash_history 拿)、被清空的 creditcard 表如何从 dump.sql 恢复并计数
2023%20团体 Q124、Q125 SQL%20dump%20文件 从备份%20SQL%20里列出所有表名、判断备份日期
2024%20团体 Q76 WAF%20流量日志里的%20SQL%20注入 从日志判断攻击类型
2025%20团体 Q86、Q90、Q95 网站系统自建库 广告机系统的 action_log/player_attribute/user 表
2025%20团体 Q136—Q152 SQLite%20+%20PostgreSQL(n8n) 工作流平台的两套库、n8n_chat_histories 表、按 session_id 数问答
2025%20团体 Q110、Q117—Q128 MySQL 邮件服务器库版本、网站库用户名密码、按 userID 统计交易次数与金额

为什么分开列?因为解法差别很大:手机库考「认得库和字段」,服务器库考「怎么把库恢复出来再查」——后者往往要先从 .bash_history、.env、dump.sql 或者%20Docker%20配置里把连接信息挖出来。如果这两类混着准备,很容易两边都不熟。

手机数据库这一块的完整地图,就是本章%2087%20道题的落点。下一章把这些落点压成四张速查表,考场上直接查。

十、五年考点地图:15%20个考点,哪些年年考、哪些刚成形

第九章是按届看题,这一章反过来——把%2087%20道题重新打散,按「答案最终落在哪一类知识、哪一个动作上」归成%2015%20个考点,再看每个考点在五年里出现了几届、几道题。同一道题可以挂多个考点(例如%202025%20个人赛的%20WhatsApp%20位置消息题,既属于「消息类型与媒体内容」,也属于「位置坐标」),全部%2087%20道题合计%20135%20个考点标签。

i%20为什么用「覆盖届数」而不是「题数」看重复度

五届收录的题量差得很远:2021%20年%206%20题、2022%20年%2010%20题、2023%20年%2018%20题、2024%20年%2019%20题、2025%20年%2034%20题。比题数会把%202025%20年的小考点抬成「重点」,比届数才能看出它是不是每年都在考。所以下文一律用「覆盖%20N%20届」当重复度的尺子,题数只作参考。

10.1%20地图是怎么画出来的
  • 切分依据是「答案落在哪」

,不是按库名、也不是按届次。问「这张照片怎么来的」和问「这个文件谁拍的」,题干完全不同,但答案都落在同一族来源字段上,就该归同一个考点。
*%20一个考点里可以有多个库

:K14「系统库」同时装了蓝牙库、通话记录、短信、iCloud%20同步清单;一个库里也可以有多个考点:相册库一个库就撑起了%20K03%20至%20K07%20五个考点。
*%2015%20个考点没有一个只考过一届

——最少的也覆盖了%202%20届。这一点本身就是结论:五年真题里没有「偶然考点」,凡是出现过的知识点,都值得按「还会再考」来准备。

10.2%20考点总览:15%20个考点按重复度排序
编号 考点 维度 覆盖届数 涉及题数 出现在哪几届
K04 相册库:来源与生成方式 相册库 5%20届 12 2021、2022、2023、2024、2025
K06 相册库:属性与文件类型 相册库 5%20届 10 2021、2022、2023、2024、2025
K10 消息类型与媒体内容 聊天库 5%20届 10 2021、2022、2023、2024、2025
K15 第三方%20App%20业务库 系统与业务库 4%20届 24 2022、2023、2024、2025
K14 系统库 系统与业务库 4%20届 12 2021、2023、2024、2025
K07 位置坐标:库内字段与%20EXIF%20交叉 跨库技法 4%20届 10 2021、2023、2024、2025
K01 找库:数据目录与包名 定位与格式 4%20届 7 2022、2023、2024、2025
K11 时间戳换算 跨库技法 4%20届 6 2022、2023、2024、2025
K08 聊天库:库结构与消息定位 聊天库 3%20届 9 2021、2023、2025
K03 相册库:主表与文件身份 相册库 3%20届 7 2022、2023、2025
K09 聊天库:联系人与群组 聊天库 3%20届 6 2023、2024、2025
K05 相册库:入库时间%20vs%20拍摄时间 相册库 3%20届 3 2021、2023、2025
K12 联表查询与%20SQL%20语法 跨库技法 2%20届 8 2023、2024
K02 辨形:非%20SQLite%20库与加密库 定位与格式 2%20届 6 2022、2025
K13 文件本体:哈希与编码 跨库技法 2%20届 5 2024、2025

维度是更大的归类:相册库(K03—K06)、聊天库(K07—K09)、定位与格式(K01、K02,找库与辨明库的形态)、跨库技法(K10—K13,时间、位置、SQL、文件本体)、系统与业务库(K14、K15)。

排在最上面的三个(K04%20相册库来源、K06%20相册库属性、K10%20消息类型与媒体)五届一届没落;再往下五个覆盖%204%20届、四个覆盖%203%20届、三个覆盖%202%20届。把这%2015%20行当成复习清单,从上往下练即可。

10.3%20重复考点地图:考点%20×%20届次

下面这张矩阵是本章的核心。横向看一行——格子越满,说明这个考点越「年年考」;纵向看一列——格子越多,说明那一届的考核面越宽。格子里的数字是该届挂在此考点的题数,— 表示该届没有考。行底色按重复度分档:深蓝=5%20届,浅蓝=4%20届,淡蓝=3%20届,白=2%20届。

考点 2021 2022 2023 2024 2025 届数/题数
K04%20相册库:来源与生成方式 1 2 1 2 6 5/12
K06%20相册库:属性与文件类型 1 1 2 2 4 5/10
K10%20消息类型与媒体内容 1 1 2 4 2 5/10
K15%20第三方%20App%20业务库 — 6 6 5 7 4/24
K14%20系统库 3 — 2 3 4 4/12
K07%20位置坐标:库内字段与%20EXIF%20交叉 2 — 2 5 1 4/10
K01%20找库:数据目录与包名 — 2 1 3 1 4/7
K11%20时间戳换算 — 1 1 1 3 4/6
K08%20聊天库:库结构与消息定位 2 — 2 — 5 3/9
K03%20相册库:主表与文件身份 — 1 1 — 5 3/7
K09%20聊天库:联系人与群组 — — 1 3 2 3/6
K05%20相册库:入库时间%20vs%20拍摄时间 1 — 1 — 1 3/3
K12%20联表查询与%20SQL%20语法 — — 6 2 — 2/8
K02%20辨形:非%20SQLite%20库与加密库 — 2 — — 4 2/6
K13%20文件本体:哈希与编码 — — — 2 3 2/5

三个观察直接给出来:① 相册库占了最上面的两行,它是五年里最稳定的出题池;② 2025%20年那一列几乎每行都有数字(15%20个考点里覆盖%2014%20个),出题面在这一届达到最宽;③ 2022%20那一列格子最少,但%202022%20只有%2010%20道题入库,属于题量小而不是考得浅。

10.4%20年年考的三个考点(覆盖%205%20届) K04 相册库:来源与生成方式(12%20题,五届全勤)

这是五年重复度最高的单一考点(2021、2022、2024、2025%20各届都考)。题干从「提供了什么取证信息」到「通过哪种方式生成」再到「由哪一个%20App%20拍摄」,问法一直在换,但答案永远落在同一个字段族:ZIMPORTEDBYBUNDLEIDENTIFIER/ZIMPORTEDFROMSOURCEIDENTIFIER 一类。真正的考点是把%20BundleID%20翻译成人话:com.apple.sharingd 是隔空投送、SpringBoard 是截图、同步下来的看云端与本地时间先后。

该背什么:来源字段的值不是中文描述,而是%20BundleID%20或系统组件名:com.apple.sharingd =%20隔空投送、SpringBoard =%20截图、Safari =%20网页下载。问「怎么来的」先想这个字段。

代表题:2021I-Q37、2022I-Q34、2024G-Q19、2025G-Q166、2025I-Q35(完整题干与解法见第九章对应卡片)

K06 相册库:属性与文件类型(10%20题,五届全勤)

相册库里「东西最多」的一个考点,出题方式是给四条描述判断哪几条对/错,每条描述对应一个字段。2023%20个人赛考「哪项描述是错的」,2024%20个人赛考后置镜头张数,2025%20年连考隐藏相册与缩时摄影(个人赛)、机型比对(团体赛);安卓侧还多一层——库里存着%20AI%20打标的主体标签(2023%20团体赛的拉面题)。这一类题不难,但要求手快:先 PRAGMA%20table_info 认字段,再逐条对。

该背什么:这一类题的标准动作是先 PRAGMA%20table_info 认字段,再逐条核对描述;「由哪个%20App%20拍摄」是来源字段,「是哪一类文件」是类型标记,两者别混。

代表题:2023I-Q59、2024I-Q22、2024I-Q23、2025I-Q39(完整题干与解法见第九章对应卡片)

K10 消息类型与媒体内容(10%20题,五届全勤)

把聊天库里「非纯文本」的那部分单独归一类。2023%20至%202025%20连续三届出现,且题型越来越细:统计语音对话段数(按 .opus 后缀计数)、判一条消息是发出还是接收(ZISFROMME)、读位置消息的经纬度、数投票活动的次数、认出表情包对应的枚举值(20)。共同动作是:先确定类型字段的取值含义,再统计或取值——枚举表题解不给,要从实际数据反推。

该背什么:类型字段是枚举值,题解不给表,只能从实际数据反推(20 =%20表情包、46 =%20投票);收发判定看 ZISFROMME(1%20为发出、0%20为接收);位置消息的经纬度不在消息表,在媒体表里。

代表题:2023I-Q56、2024G-Q11、2024G-Q18、2025I-Q58、2025I-Q74(完整题干与解法见第九章对应卡片)

10.5%20常客:五个覆盖%204%20届的考点

这五个考点不是每届都出现,但隔一年就会回来一次,属于「必须会」的第二梯队。

K15 第三方%20App%20业务库(24%20题,出现于%202022、2023、2024、2025)

五年里变化最大、也最能体现「读库」价值的一类:库里存的都是工具没解析的业务数据。2022%20年的电子书与备忘录、2023%20年的运动与电商、2024%20年的外卖与邮件、2025%20年的%20AI%20聊天与智能家居,几乎没有重复的%20App,但动作完全一样:先按包名定位目录、罗列全部表名、按业务关键词猜字段、再用时间戳筛那一条记录。题解反复提示的一句话是「自动取证工具读不完这些」,这就是所谓剩下%2020%%20的分。

该背什么:标准四步:按包名定位目录%20→%20罗列全部表名%20→%20按业务关键词猜字段%20→%20用时间戳筛那一条记录。库很小也不代表没证据(外卖两个库各%201%20条记录,就是答案)。

代表题:2022I-Q10、2024G-Q90、2024G-Q125、2025G-Q175

K14 系统库(12%20题,出现于%202021、2023、2024、2025)

贯穿五届中四届的「基础分仓库」。2021%20年靠蓝牙库(UUID%20与%20MAC%20辨析)开场,2023%20年出现在通话与短信题里(「哪张表存通话记录」、短信%20GUID%20定位),2025%20年转向%20iCloud%20同步清单、空投痕迹与安卓媒体总库。有两个必须记住的点:火眼只给%20MAC,要%20UUID%20得自己开蓝牙库;Core%20Data%20库里%20Z\_METADATA/Z\_MODELCACHE/Z\_PRIMARYKEY%20三张表天然是「哪张表存业务数据」题的干扰项。

该背什么:两个高频细节:火眼的蓝牙信息只给%20MAC,要%20UUID%20必须自己开蓝牙库;Core%20Data%20库里 Z_METADATA/Z_MODELCACHE/Z_PRIMARYKEY 三张系统表,天然是「哪张表存业务数据」题的干扰项。

代表题:2021I-Q9、2023I-Q64、2024I-Q8、2025I-Q23

K07 位置坐标:库内字段与%20EXIF%20交叉(10%20题,出现于%202021、2023、2024、2025)

2023%20至%202025%20三届连考。考法有两面:同一张照片库里两组经纬度不同,该信哪一个(2025%20个人赛,ZASSET 与 ZEXTATTR 各一组,要靠同地点其他照片交叉比对);原文件%20EXIF%20里根本没有%20GPS,只能回库读(2025%20个人赛另一题)——这两题刚好互为反面,说明「EXIF%20与库谁更可信」没有固定答案。运动%20App%20的轨迹表(2023%20团体赛跑步起点)与聊天库的位置消息(2024%20个人赛微信%20XML、2025%20个人赛%20WhatsApp%20位置消息)也归这一考点的动作:先找到坐标寄存在哪张表。

该背什么:同一份坐标可能有两份(ZASSET 一份、ZEXTATTR 或%20EXIF%20一份),没有哪一份天然更可信,要靠同地点的其他照片交叉比对;EXIF%20里没有%20GPS%20时就回库读,别以为没有。

代表题:2023G-Q7、2025I-Q40、2025I-Q64、2024I-Q1

K01 找库:数据目录与包名(7%20题,出现于%202022、2023、2024、2025)

五年里每一届都至少有一题只问「数据存在哪个库/这个%20App%20的包名是什么」。考法一直在换外衣:2022%20问电子书的书库在哪、2024%20问照片数据在哪个库、2025%20问小程序式的包名(智能家居、AI%20聊天),但动作始终是同一步——先定位目录,再开库。这类题分值好拿,前提是认得包名规律:安卓按包名切目录、iOS%20分私有域与%20AppDomainGroup%20共享域。

该背什么:安卓统一在 /data/<包名>/databases/;iOS%20分私有域与 AppDomainGroup 共享域;认得开发者就能猜出包名(Quora%20→ com.quora.app.Experts,小米%20→ com.xiaomi.smarthome)。

代表题:2022I-Q10、2023G-Q3、2024G-Q12、2025G-Q169

K11 时间戳换算(6%20题,出现于%202022、2023、2024、2025)

五年里最「稳定送分又稳定送命」的考点,2021、2022、2023、2024、2025%20各届都有。坑一共四个:①格式——Cocoa%20以%202001%20年为%200%20点,忘加%20978307200%20就错到离谱;②时区——题干写%20UTC+8%20而工具默认输出%20UTC,少加%208%20小时(2023%20个人赛的「I%20am%20already%20home」就是这题);③反向坑——库里存的已经是本地时间,再%20+8%20反而多%208%20小时(2023%20团体赛跑步时间);④单位——安卓常见毫秒级,先除%201000。每一届都要重踩一遍,说明它必须练到条件反射。

该背什么:四条一起背:Cocoa%20加%20978307200、UTC+8%20再加%208%20小时、库里已是本地时间就别再加、安卓毫秒先除%201000。每次作答前先回题干确认它要的是%20UTC+8%20还是%20UTC+0。

代表题:2021I-Q33、2023G-Q6、2023I-Q62、2024I-Q2、2024I-Q29

10.6%20正在成形:三届与两届的考点

三届的四个考点已经算「稳定」,两届的三个考点则要留意——它们往往是出题人新加的方向,2026%20年大概率会接着考。

覆盖%203%20届(稳定)

K08%20聊天库:库结构与消息定位(9%20题,2021、2023、2025):安卓%20WhatsApp%20双库(wa.db%20联系人+msgstore.db%20消息)、iOS%20单库%20ChatStorage.sqlite;精确定位靠%20GUID%20或关键字
该背什么:三个库名背死:iOS%20WhatsApp%20只有 ChatStorage.sqlite;安卓是 wa.db(联系人)+ msgstore.db(消息);微信是 EnMicroMsg.db(通常加密)。精确定位靠%20GUID%20或关键字,不靠翻。
代表题:2021G-Q30、2024I-Q42、2024I-Q41、2025I-Q50

K03%20相册库:主表与文件身份(7%20题,2022、2023、2025):ZASSET%20主表、Z\_PK%20自增主键、ZFILENAME、本地名与原文件名、修改后另存
该背什么:Z_PK 是%20Core%20Data%20的自增主键,写入顺序=主键顺序;库里同时存本地文件名与原始(云端)文件名,「原名」问的是后者。
代表题:2025G-Q160、2025G-Q162、2025I-Q38、2025I-Q42

K09%20聊天库:联系人与群组(6%20题,2023、2024、2025):群组两张表(群信息+会话)、群%20ID%20里含建群者手机号与建群时间戳、封存/锁定/多设备登录
该背什么:群组这组题的值都藏在「名字」里:群%20ID%20形如 <建群者手机号>-<建群时间戳>@g.us,群头像文件名 85263834763-1563607573-1732782278.jpg 第三段就是更改时间。文件名与 ID 本身就是证据。
代表题:2023G-Q9、2025G-Q183、2025G-Q187、2025G-Q189

K05 相册库:入库时间 vs 拍摄时间(3 题,2021、2023、2025):ZADDEDDATE=写进数据库的时间,ZDATECREATED=文件元数据里的创建时间,题干问哪个就用哪个
该背什么:两个日期字段分得很清:写进数据库/储存到相册看 ZADDEDDATE,拍摄时间看 ZDATECREATED。
代表题:2021I-Q37、2023I-Q59、2025G-Q160

覆盖 2 届(新方向)

K12 联表查询与 SQL 语法(8 题,2023、2024):两表靠共同字段接起来、表别名用了就必须全程带、自连接解「原名→现名」、COUNT 前先定筛选字段
该背什么:联表的连接键要从题干和两表的共同字段推,不能想当然;表别名一旦用了(FROM cus c),后续每一列都得带别名;「多少条」之前先定筛选字段,再 COUNT。
代表题:2023G-Q4、2023I-Q98、2023G-Q82、2024I-Q2、2024I-Q23

K02 辨形:非 SQLite 库与加密库(6 题,2022、2025):Realm、MMKV、plist、加密库、扩展名伪装——先辨明是什么格式,再决定怎么开
该背什么:打不开先别怀疑工具,先看它是什么:.realm 是 Realm 库、无扩展名的可能是 MMKV、加密库要么找密钥(微信按 uin + IMEI 生成)要么上字典。
代表题:2022I-Q38、2025I-Q12、2025G-Q175、2025I-Q43

K13 文件本体:哈希与编码(5 题,2024、2025):哈希算的是文件本体不是数据库记录;源文件与库互证;同一记录可能被 GBK/UTF8 两套编码搜出两次
该背什么:哈希是对文件本体算的,不是对数据库记录算的——先把库里的路径还原成磁盘文件;同名不同源、同图两名,一律用哈希说话;全局搜索的结果要按编码去重。
代表题:2024G-Q10、2024I-Q19、2025G-Q165、2025I-Q31

! 最该警惕的三个「两届考点」

K02 非 SQLite 库与加密库(2022、2025)、K13 文件本体哈希与编码(2024、2025)、K12 联表查询与 SQL 语法(2023、2024)——前两个是纯技术新增项,2025 年一次性出现了 4 道,说明出题人正在加码;K12 是唯一一个「间隔年」出现的考点,2025 年虽然没单独设题,但解法已经融进了相册与聊天的题里。

10.7 五年趋势:考核面在逐年扩大

届次 收录题数 当届涉及考点 具体考点 首次出现的考点
2021 6 7 K04、K05、K06、K07、K08、K10、K14 K04、K06、K10、K14、K07、K08、K05
2022 10 8 K01、K02、K03、K04、K06、K10、K11、K15 K15、K01、K11、K03、K02
2023 18 13 K01、K03、K04、K05、K06、K07、K08、K09、K10、K11、K12、K14、K15 K09、K12
2024 19 11 K01、K04、K06、K07、K09、K10、K11、K12、K13、K14、K15 K13
2025 34 14 K01、K02、K03、K04、K05、K06、K07、K08、K09、K10、K11、K13、K14、K15 —
  • 考核面从 7 个考点扩到 14 个

(2021 → 2025),2023 年是一次跃迁(业务 App 类考点一次铺开),2024 年略微收窄,2025 年达到最宽。
* 「读库」的比重在上升。

K15 第三方 App 业务库覆盖 4 届、涉及 24 题,是全部 15 个考点里题数最多的一个——数据库题的答案越来越多地藏在业务库里,而不是在通信软件这类「常规考点」里。
* 物理层与格式层开始入场。

K13(哈希与编码)、K02(非 SQLite 库与加密库)都是后两年才出现的——以前只需要「打开库读字段」,现在还要处理文件本身。
* 相册库从未离场。

K03 至 K07 五个考点覆盖 3 到 5 届不等,合计 42 题。哪怕 2025 年加了再多新方向,相册库仍是出题密度最高的地方。

10.8 同一个考点的多种问法(三张对照表)

「重复考点」不是「原题重现」。出题人的手法是同一个知识点,换一个入口问。下面三张表把这种问法变化摊开——左边是题干原句,右边是它真正要读的字段或要做的动作。

① 相册库「来源」(K04,五届全勤)

届次·题号 题干原句(节选) 实际要读的字段/动作
2021I-Q37 相片檔 IMG\_0056.HEIC 提供了什么电子数据取证的信息? 一次问三项:来源 + 机型 + 拍摄时间
2022I-Q34 哪一个栏目标题可以显示这张照片的接收方式 ZIMPORTED* 与 ZRECEIVED* 的命名区别
2022I-Q35 承上题,这张照片通过什么方式接收 把 BundleID 翻成人话(sharingd = 隔空投送)
2024G-Q19 IMG\_0011.PNG 是通过哪种方式生成的? 值是系统组件名(SpringBoard = 截图)
2025G-Q161 这个图片文件是通过什么方法在此手机生成 iCloud 同步——比云端与本地时间的先后
2025G-Q166 此图片文件是如何在此手机生成的 网页下载——来源是浏览器
2025I-Q30 请指出由哪一个软件拍摄 来源 App(GIF 由 Infltr 拍摄)
2025I-Q35 图片文件 IMG\_0079.JPG 是由哪一个 APP 拍摄 按文件名定位 asset 再读来源字段

② 时间戳换算(K11)的四种坑

坑 长什么样 代表题
格式:Cocoa Core Time 库里是 2001-01-01 起算的秒数,忘加 978307200 差 31 年 2023I-Q62、2024I-Q2
时区:题干要 UTC+8 工具默认输出 UTC,少加 8 小时 2023I-Q62(答案 2023-04-01 11:21:51)
反向坑:库里已是本地时间 再加 8 小时反而错 8 小时 2023G-Q6(跑步开始时间)
单位:毫秒 安卓字段常见 13 位,先除 1000 2024I-Q29(Gmail 首封邮件日期)
题干要 UTC+0 这次不要加 8 小时 2025G-Q189(群头像更改时间)

③ 聊天库三个考点的问法迁移(K07/K08/K09/K10)

届次 在聊天库里问了什么 归属考点
2021 对方名下的 WhatsApp 账号有哪些、黑名单有几条 K07 库结构、K08 联系人与状态
2023 哪些对话被锁定、有多少段录音、被修改前的内容是什么、群组名称 K07/K08/K09
2024 哪个库存 WhatsApp 消息、表情包对应哪个枚举、一条消息是发还是收 K07/K09/K10
2025 封存了哪个群、群建立者手机号、群头像的更改时间、投了几次票、位置消息坐标 K08/K09/K10

从 2021 到 2025,聊天库的题从「读一个字段」走到「一条链上取三个值」——这就是重复考点的演化方式:不是重复题,是重复难度加码。

10.9 按重复度排出的复习优先级

  • 第一优先(覆盖 5 届,共 32 题):

K04 相册库来源、K06 相册库属性、K10 消息类型与媒体。这三个必须在不查资料的情况下能说出「读哪个字段」。
* 第二优先(覆盖 4 届,共 59 题):

K15 业务库、K14 系统库、K07 位置坐标、K01 找库与包名、K11 时间戳。这五个是补分的主战场,练法见第十三章的五周路线。
* 第三优先(覆盖 3 届,共 25 题):

K08 库结构与消息定位、K03 相册库主表、K09 联系人与群组、K05 时间双轨。这四个是「会了就有、不会就丢」的稳定分。
* 第四优先(覆盖 2 届,共 19 题):

K12 联表与 SQL、K02 非 SQLite 库与加密库、K13 文件本体哈希与编码。题数少但都是新方向,建议至少各做一道原题。

10.10 考点自查表

最后给自己打一次分。逐行问自己:这个考点,我能不能不看笔记说出「去哪个库、读哪个字段、要注意什么」?说不出来的,把编号记下来,回第九章找代表题重做一遍。

编号 考点 重复度 做完这几题就算过关 自评
K04 相册库:来源与生成方式 5 届 2021I-Q37、2022I-Q34、2024G-Q19 □
K06 相册库:属性与文件类型 5 届 2023I-Q59、2024I-Q22、2024I-Q23 □
K10 消息类型与媒体内容 5 届 2023I-Q56、2024G-Q11、2024G-Q18 □
K15 第三方 App 业务库 4 届 2022I-Q10、2024G-Q90、2024G-Q125 □
K14 系统库 4 届 2021I-Q9、2023I-Q64、2024I-Q8 □
K07 位置坐标:库内字段与 EXIF 交叉 4 届 2023G-Q7、2025I-Q40、2025I-Q64 □
K01 找库:数据目录与包名 4 届 2022I-Q10、2023G-Q3、2024G-Q12 □
K11 时间戳换算 4 届 2021I-Q33、2023G-Q6、2023I-Q62 □
K08 聊天库:库结构与消息定位 3 届 2021G-Q30、2024I-Q42、2024I-Q41 □
K03 相册库:主表与文件身份 3 届 2025G-Q160、2025G-Q162、2025I-Q38 □
K09 聊天库:联系人与群组 3 届 2023G-Q9、2025G-Q183、2025G-Q187 □
K05 相册库:入库时间 vs 拍摄时间 3 届 2021I-Q37、2023I-Q59、2025G-Q160 □
K12 联表查询与 SQL 语法 2 届 2023G-Q4、2023I-Q98、2023G-Q82 □
K02 辨形:非 SQLite 库与加密库 2 届 2022I-Q38、2025I-Q12、2025G-Q175 □
K13 文件本体:哈希与编码 2 届 2024G-Q10、2024I-Q19、2025G-Q165 □

✓ 这一章的用法

别把它当知识点汇总来读,当进度表用:15 行全部能说出「怎么查」,手机数据库这类题就不会再丢分了。第九章提供逐题拆解,这一章提供重复度依据,两张表合起来看,就能判断哪些投入是值得的。

十一、速查表:考场上的四张表

这一章是全文的落点。前面八章都在讲「为什么」,这一章只有「去哪查」。

i 这四张表怎么用

表一、表二:按平台列出每个库的路径与核心字段,遇到陌生检材时先对一遍;表三:按题目的问法索引——这是最该打印出来的一张,题目怎么问,你顺着它找到「去哪个库、看哪个字段」;表四:反查表,看到题干里冒出一个字段名,回来查它是哪个库的。

10.1 速查表一:iOS 常考库

库文件 路径关键段 核心表 必记字段
Photos.sqlite /var/mobile/Media/PhotoData/ ZASSET 、ZEXTENDEDATTRIBUTES、ZADDITIONALASSETATTRIBUTES、ZGENERICALBUM、ZCLOUDMASTER ZUUID 、ZFILENAME、ZUNIFORMTYPEIDENTIFIER、ZDATECREATED、ZADDEDDATE、ZLATITUDE/ZLONGITUDE、ZVIDEOCPDURATIONVALUE、ZEXTENDEDATTRIBUTES
ChatStorage.sqlite /var/mobile/Applications/group.net.whatsapp.WhatsApp.shared/ ZWAMESSAGE 、ZWAMESSAGEINFO、ZWACHATSESSION、ZWAMEDIAITEM、ZWAGROUPINFO ZTEXT 、ZFROMJID/ZTOJID、ZMESSAGETYPE、ZMESSAGEINFO、ZMEDIAITEM、ZISFROMME、ZCREATORJID
DeviceAgents.sqlite 同 WhatsApp 目录 ZWASMBDEVICEAGENT 登录设备记录(几条记录 = 几台设备)
NoteStore.sqlite /AppDomainGroup-group.com.apple.notes/ ZICCLOUDSYNCINGOBJECT 笔记加密标志、标题、内容
CallHistory.storedata /var/mobile/Library/CallHistoryDB/ ZCALLRECORD (另有 ZCALLBPROPERTIES) ZADDRESS (号码)、ZDATE(Cocoa 时间)
AddressBook.sqlitedb /var/mobile/Library/AddressBook/ ZABCDRECORD 等 号码 ↔ 姓名
sms.db /var/mobile/Library/SMS/ message 、chat 短信正文、收发方、时间
Manifest.db iOS 备份根目录 /var/ Files fileID 、domain、relativePath
message\_N.sqlite com.tencent.xin/Documents/<32位哈希>/ 消息表 图片消息的 XML:aeskey、filekey、m_assetUrlForSystem(GUID)
finder\_main.db .../finder/db/ finderContactTable3 followState (1 = 已关注)

10.2 速查表二:Android 常考库

库文件 路径 核心表 必记字段
msgstore.db /data/data/com.whatsapp/databases/ message 、chat、jid、message_edit_info、message_ftsv2_content、media _id 、chat_row_id、jid_row_id、message_row_id、docid、message_type、text_data
wa.db /data/data/com.whatsapp/databases/ wa_contacts (题解原文写作 wa_contects,应为笔误) 联系人的 WhatsApp 账号
contacts2.db /data/data/com.android.providers.contacts/databases/ contacts 、raw_contacts、data、mimetypes 要联 mimetypes 才知道某行是电话、邮箱还是姓名
mmssms.db /data/data/com.android.providers.telephony/databases/ sms 、threads 单条短信与会话
calllog.db /data/data/com.android.providers.contacts/databases/ calls type 区分呼入/呼出/未接
EnMicroMsg.db /data/data/com.tencent.mm/MicroMsg/<哈希>/ 消息表(需解密) 微信安卓版聊天库
com.tencent.mm\_preferences.xml /data/data/com.tencent.mm/shared_prefs/ —(XML 配置,非数据库) 最后登录的微信 ID

10.3 速查表三:按题目问法索引(最常用的一张)

做题时从这里开始查。左边是题目里出现的话,右边是你的动作。

题目这么问 去哪个库 · 哪张表 看哪些字段/怎么做
某时刻谁发了什么消息 ChatStorage ZWAMESSAGE 按时间过滤,取 ZTEXT、ZFROMJID、ZISFROMME
某条消息是谁发的(安卓) msgstore.db message→chat→jid chat_row_id → jid_row_id → jid.user,三级联表
某时刻发送的位置坐标 ChatStorage ZWAMESSAGE→ZWAMEDIAITEM 取 ZMEDIAITEM 的值,去 ZWAMEDIAITEM 按 Z_PK 过滤
这张照片在哪拍的 Photos.sqlite ZASSET + ZEXTATTR 两处经纬度都要看,冲突时用邻近照片轨迹判定 ,再用 EXIF 印证
这张照片是否本机拍摄 Photos.sqlite ZEXTENDEDATTRIBUTES ZCAMERAMAKE /ZCAMERAMODEL
这张照片是怎么来的 Photos.sqlite ZADDITIONALASSETATTRIBUTES ZIMPORTEDBYBUNDLEIDENTIFIER 的值(BundleID),翻译成 App 名
是不是实况照片 Photos.sqlite ZASSET ZVIDEOCPDURATIONVALUE != 0
照片删了没有/何时删的 Photos.sqlite ZASSET ZTRASHEDSTATE 、ZTRASHEDDATE、ZHIDDEN
群主/建群者是谁 ZWAGROUPINFO.ZCREATORJID ; 或解析群 ID 老格式 <手机号>-<时间戳>@g.us ,前半段就是建群者号码
群是什么时候建的 群 ID(老格式)/ChatStorage 记录 解析群 ID 里的 UNIX 时间戳,再与库里时间交叉验证
哪个群被存档了 ChatStorage ZWACHATSESSION 存档标志字段(值为 1)
群头像叫什么文件 ChatStorage Media/Profile/ 库里有路径,磁盘上有文件,两边对上
登录了几台设备 DeviceAgents.sqlite ZWASMBDEVICEAGENT 表的记录数
打了多少次电话 CallHistory.storedata ZCALLRECORD ZADDRESS + ZDATE 过滤后 COUNT(*)
这个号码是谁 AddressBook.sqlitedb ; 或 JID 的 @ 前半段 号码 ↔ 姓名接力
消息被编辑前是什么 msgstore.db message_edit_info + message_ftsv2_content message_row_id → message._id ← docid
某个类型值的含义 任意库对应表 GROUP BY 该字段 + 抓样本内容反推
某个文件存在哪 ChatStorage ZWAMEDIAITEM.ZMEDIALOCALPATH; 备份里查 Manifest.db 库里的路径 + 磁盘上的文件互校
微信图片的原图 message\_N.sqlite 消息 XML filekey (编号对应磁盘文件名)、aeskey(解密)、md5(校验)
微信图片的地理位置 message\_N.sqlite → Photos.sqlite XML 里的 m_assetUrlForSystem GUID = 相册库的 ZUUID
关注了几个视频号 finder\_main.db finderContactTable3 followState = 1 计数
这个库有哪些表 任意库 SELECT name FROM sqlite_master WHERE type='table';
某个字段名存不存在 任意库 PRAGMA table_info(表名); 或导出全库字段清单
某张表里有哪些取值 任意库 GROUP BY 字段 + COUNT(*)

10.4 速查表四:看到字段名,反查它属于哪个库

题干或选项里直接给你一串字段名时,这张表能帮你秒判方向。

字段名(或片段) 属于 含义
ZASSET /ZEXTATTR/ZADDASSETATTR Photos.sqlite 相册主表/EXIF/附加属性
ZUUID Photos.sqlite 资产唯一标识,跨库关联用
ZMESSAGETYPE /ZMESSAGEINFO ChatStorage.sqlite 消息类型/详情指针
ZFROMJID /ZTOJID ChatStorage.sqlite 收发方
ZMEDIAITEM ChatStorage.sqlite 媒体/位置指针
ZRECEIPTINFO ChatStorage.sqlite · ZWAMESSAGEINFO Protobuf 格式的消息详情
ZCREATORJID ChatStorage.sqlite · ZWAGROUPINFO 群创建者
ZICCLOUDSYNCINGOBJECT NoteStore.sqlite 备忘录对象
ZCALLRECORD /ZADDRESS/ZDATE CallHistory.storedata 通话记录/对方号码/时间
chat_row_id /jid_row_id/message_row_id msgstore.db(安卓) 三种外键
message_ftsv2_content /docid msgstore.db(安卓) 编辑前的原始文本
text_data /message_type msgstore.db(安卓) 正文/消息类型
followState /finderContactTable3 finder\_main.db(微信) 视频号关注状态
m_assetUrlForSystem /aeskey/filekey 微信 message_N.sqlite 消息 XML 中的图片元数据
fileID /domain/relativePath Manifest.db(iOS 备份) 备份文件清单
Z_PRIMARYKEY /Z_METADATA/Z_MODELCACHE 任何 Core Data 库 通用表,八成是干扰项

10.5 一页纸的做题流程

把前面所有内容压成一条流程,考场上照着走:

  • 第 1 步 · 判平台

:看路径。有 /data/data/ 是安卓,有 /var/mobile/ 或 Applications/ 是 iOS。如果是备份包,先处理 Manifest 四件套。
* 第 2 步 · 找库

:搜 /databases/ 目录,或按文件头 SQLite format 3 扫。别只按后缀筛,会漏掉 .storedata。
* 第 3 步 · 认表

:sqlite_master 列表名 → 对照 10.1/10.2 两张表,看是哪个 App 的库。
* 第 4 步 · 认字段

:PRAGMA table_info(表),或直接跑一遍 2.5 节那段导字段脚本。找不到就搜,别猜。
* 第 5 步 · 定位答案

:照 10.3 表按问法找到字段,注意时间是 Cocoa 还是 UNIX、要不要联表。
* 第 6 步 · 交叉验证

:同一信息若有两个来源(工具 vs 库、主表 vs 附表),都要看一遍,答案以原始记录为准并说明依据。
* 第 7 步 · 记下依据

:答案带上届次题号式的出处,例如「来自 ZASSET 表 ZFILENAME=IMG_0027.HEIC 的记录」。

十二、五年踩过的坑:15 条易错点

# 易错点 正确做法
1 用文件后缀筛数据库,漏掉 .storedata 这类 同时按文件头判:SQLite format 3 就是库
2 只读主库文件,忽略 -wal/-shm 三个文件放同一目录再打开 ,否则拿不到最新数据
3 把 Cocoa 时间戳当 UNIX 用 Cocoa + 978307200 = UNIX ,iOS 库几乎都是 Cocoa
4 直接抄工具显示的时间 工具可能显示 UTC。东八区要 +8 小时,答案里写明时区
5 在 ZASSET 里找相机型号 设备信息在 ZEXTENDEDATTRIBUTES,顺着外键跳过去
6 发现两份经纬度不一致就随便选一个 对比邻近记录 + EXIF 印证 ,三方一致才落笔
7 以为工具解析不出来 = 数据不存在 工具只翻译常用字段。自己开库看原始表
8 忘记 JOIN 的 ON 条件 结果会变成笛卡尔积,行数暴增、查询卡死
9 联表时字段名不加表前缀 报 ambiguous column name。一律写 cus.customer_id 这种全名
10 只在一张表里找答案 同一信息可能分散在多张表(主表存记录、附表存详情)
11 看到「封存/存档」找不到字段就放弃 港台用词,英文是 Archive;大陆叫「存档」
12 被字段简写绕晕(ZEXTATTR 到底是什么) 去 sqlite_master 对全称,或用导字段脚本搜关键词
13 用 COUNT(字段) 数总数 它不数 NULL。数全部用 COUNT(*),数「多少个人」要 COUNT(DISTINCT 字段)
14 直接背消息类型枚举表 用 GROUP BY 字段 + 抓样本内容现场反推,零记忆且不会错
15 在原检材上直接写 SQL、做实验 先复制一份工作副本,所有操作在副本上做

十三、要掌握到什么程度:四级能力清单

把「会做手机数据库题」拆成四级。可以拿它给自己打分,看看卡在哪一级,再去看对应章节。

级别 名称 要会什么 对应章节
L1 认得出 看到一个检材,知道去哪个目录找库;能打开库、能用 sqlite_master 列出表名;能说出这个库属于哪个 App。 第 2 章
L2 找得到 题目问某个信息,能判断它在哪张表;能列出该表字段、认出外键;会写单表 SELECT ... WHERE ... 把记录捞出来。 第 3/4/5 章
L3 接得起 会写联表:能顺着 Z_PK/xxx_row_id 串两三张表;会把题干的时刻换算成时间戳当筛选条件;会 GROUP BY 反查枚举值;会在两个库之间做接力。 第 6/7 章
L4 辨得清 遇到同一信息有两个来源时,能交叉验证并说明取舍依据;工具与库冲突时,知道回原始记录;库结构变了、工具不支持时,能改脚本、手动硬看,把答案挖出来。 第 3.5/4.3 节 + 第 5.1 节

十四、五周练习路线

不用买课,全程只用公开资源 + 你手上的这几篇题解。

周 目标 具体动作
第 1 周 把「认库认表」练成条件反射 ① 拿任意一份 iOS 检材,对着 10.1 表把每个库打开一遍;② 每个库跑一次 sqlite_master,把表名抄一遍;③ 用 2.5 节的脚本导出全库字段清单,存成自己的参考文件
第 2 周 吃透 Photos.sqlite ① 逐条复现第 3.9 节的 8 道真题;② 重点练 3.5 节的「两份经纬度」判定;③ 把 ZASSET 和 ZEXTENDEDATTRIBUTES 的字段对着库抄一遍
第 3 周 吃透 WhatsApp 双平台 ① 复现第 4.7 节的 14 道题;② iOS 侧练 ZWAMESSAGE → ZWAMESSAGEINFO → ZWAMEDIAITEM 三段链;③ 安卓侧练 4.6.1 节的五表链,把「编辑前原文」亲手查出来
第 4 周 时间与联表专项 ① 把第 6 章的验算自己动手算一遍(不要只看);② 写一句 strftime 把任意给定时刻换成 Cocoa 秒数;③ 复现第 7.4 节四个范式,每个至少独立写一遍,不看答案
第 5 周 综合演练 + 查漏 ① 拿一份完整检材,从找库到给答案走完 10.5 的七步;② 把 10.3 速查表打印出来,盖住右列自测;③ 过一遍第十二章 15 条易错点,把踩过的标出来

结语

写这一篇的起因,是发现近五年美亚杯的手机题有个很集中的落点:出题人越来越喜欢把答案埋在一个具体字段里——一个 ZVIDEOCPDURATIONVALUE、一个 ZCREATORJID、一个 followState、一个 ZRECEIPTINFO。自动取证工具能帮你走到门口,但最后那一脚得你自己迈。

而这条路其实比想象中窄——常用的库就那十来个,核心的表就那二三十张,真正被反复考的字段不到六十个。本文把它们全部收在了第十一章的四张表里。

所以别再觉得「数据库题要背很多」。你要记的不是几十张表的几百个字段,而是七个动作:判平台、找库、列表名、查字段、定条件、接外键、交叉验证。把这七个动作变成肌肉记忆,剩下的都是体力活。

✓ 最后一句提醒

手机取证里的「答案」,永远以原始记录为准。工具给你的是它算出来的结果,而库给你的是当时真实写下的那串数字。这也是为什么——五年了,这个考点一次都没落过。

敬请各位大佬关注:小谢取证

扫取二维码获取

更多精彩

小谢取证


适配Android17提权,微信多媒体删除恢复再突破,数据管控再升级" 网络安全文章

适配Android17提权,微信多媒体删除恢复再突破,数据管控再升级"

盘古石手机取证R8.8.0发布,围绕提取、解析、安全管控三大方向升级。提取方面适配Android17及三星小米Android16提权,新增智能截屏辅证;解析方面突破微信多媒体删除恢复技术,新增鸿蒙平台豆包、千问等应用解析;安全管控新增用户管理、操作审计、自定义水印及数据自动清理功能,强化执法数据安全防线。
【盘古石取证】国庆假期值班安排" 网络安全文章

【盘古石取证】国庆假期值班安排"

盘古石取证团队发布国庆假期值班安排通知,放假时间为10月1日至10月7日,期间技术服务不间断响应,提供产品技术支持与紧急案件协助。团队隶属于奇安信集团,专注电子数据取证领域,产品覆盖计算机取证、移动终端取证等全领域解决方案,服务公安执法、司法机关等客户,并附有联系方式。
评论:0   参与:  0