forensicnomicon 0.3.1

The ForensicNomicon — comprehensive DFIR artifact catalog: UserAssist, Shimcache, Amcache, Prefetch, $MFT, ShellBags, EVTX, NTDS.dit, SAM, SRUM, LNK, Jump Lists + KAPE/Velociraptor/Sigma/MITRE. Zero deps.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
//! Vehicle infotainment forensic artifact descriptors.
//!
//! Honda Accord (2016, USA) — Clarion-manufactured Android 4.2.2-based head unit
//! with Garmin navigation. Four SQLite databases on Partition4 (/data) contain
//! navigation history, trip telemetry, Bluetooth call/contact sync, and paired
//! device records.
//!
//! Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
//! Scripts: https://github.com/cheeky4n6monkey/Honda_Accord_2016_scripts

use super::super::types::{
    ArtifactDescriptor, ArtifactType, DataScope, Decoder, FieldSchema, OsScope, TriagePriority,
    ValueType,
};

// ── Honda Accord RecentStops (Garmin navigation history) ─────────────────────

/// Field schema for the `history` table in RecentStops.db.
/// SQL: SELECT time, lat, lon, name FROM history ORDER BY time ASC;
/// Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
pub(crate) static HONDA_ACCORD_RECENTSTOPS_FIELDS: &[FieldSchema] = &[
    FieldSchema {
        name: "time",
        value_type: ValueType::Timestamp,
        description: "Timestamp of the navigation stop entry; format not confirmed but \
            appears to be a numeric epoch value. Useful for establishing a timeline of \
            vehicle locations",
        is_uid_component: true,
    },
    FieldSchema {
        name: "lat",
        value_type: ValueType::Text,
        description: "Latitude coordinate of the stop location in decimal degrees",
        is_uid_component: false,
    },
    FieldSchema {
        name: "lon",
        value_type: ValueType::Text,
        description: "Longitude coordinate of the stop location in decimal degrees",
        is_uid_component: false,
    },
    FieldSchema {
        name: "name",
        value_type: ValueType::Text,
        description: "Name or label associated with the stop (e.g. address or POI name)",
        is_uid_component: false,
    },
];

pub(crate) static HONDA_ACCORD_RECENTSTOPS: ArtifactDescriptor = ArtifactDescriptor {
    id: "honda_accord_recentstops",
    name: "Honda Accord Garmin RecentStops (Navigation History)",
    artifact_type: ArtifactType::DatabaseEntry,
    hive: None,
    key_path: "",
    value_name: None,
    // Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
    file_path: Some("/data/com.honda.displayaudio.navi/Garmin/sqlite/RecentStops.db"),
    scope: DataScope::System,
    os_scope: OsScope::Android,
    decoder: Decoder::Identity,
    retention: None,
    meaning: "Garmin navigation 'history' table in RecentStops.db on Honda Accord (2016) \
        Clarion Android-based infotainment. Contains timestamped latitude/longitude coordinates \
        documenting vehicle stops or navigation waypoints. Trigger for entry creation is not \
        confirmed but entries correlate with driven routes. High forensic value for placing a \
        vehicle at specific locations and times. The infotainment runs Android 4.2.2 on a \
        Clarion platform (ro.product.manufacturer=Clarion, ro.board.platform=r8a7791). \
        A companion quick_search_list.db exists at the same path but was found empty.",
    mitre_techniques: &[],
    fields: HONDA_ACCORD_RECENTSTOPS_FIELDS,
    triage_priority: TriagePriority::High,
    sources: &[
        "https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html",
        "https://github.com/cheeky4n6monkey/Honda_Accord_2016_scripts",
    ],
    related_artifacts: &[
        "honda_accord_crm_eco_logs",
        "honda_accord_phonedb",
        "honda_accord_bluetooth",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Trigger for entry creation not confirmed — entries correlate with driven routes but interpretation requires care",
        "Limited to specific Honda Accord 2016 Clarion infotainment",
    ],
    volatility: Some(crate::volatility::VolatilityClass::ActivityDriven),
    volatility_rationale: "Database updated per navigation event; bounded by app retention",
};

// ── Honda Accord CRM Eco Logs (trip telemetry) ──────────────────────────────

/// Field schema for the `eco_logs` table in crm.db.
/// SQL: SELECT _id, trip_date, trip_id, mileage, start_pos_time, start_pos_odo,
///      finish_pos_time, finish_pos_odo, fuel_used, driving_range
///      FROM eco_logs ORDER BY _id ASC;
/// Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
pub(crate) static HONDA_ACCORD_CRM_ECO_LOGS_FIELDS: &[FieldSchema] = &[
    FieldSchema {
        name: "_id",
        value_type: ValueType::Integer,
        description: "Auto-increment row identifier",
        is_uid_component: true,
    },
    FieldSchema {
        name: "trip_date",
        value_type: ValueType::Text,
        description: "Date of the trip leg",
        is_uid_component: false,
    },
    FieldSchema {
        name: "trip_id",
        value_type: ValueType::Integer,
        description: "Trip identifier grouping related journey legs",
        is_uid_component: false,
    },
    FieldSchema {
        name: "mileage",
        value_type: ValueType::Text,
        description: "Mileage for this trip leg (units not confirmed but usable for trending)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "start_pos_time",
        value_type: ValueType::Timestamp,
        description: "Timestamp when the trip leg started",
        is_uid_component: false,
    },
    FieldSchema {
        name: "start_pos_odo",
        value_type: ValueType::Text,
        description: "Odometer reading at trip start (units not confirmed)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "finish_pos_time",
        value_type: ValueType::Timestamp,
        description: "Timestamp when the trip leg ended",
        is_uid_component: false,
    },
    FieldSchema {
        name: "finish_pos_odo",
        value_type: ValueType::Text,
        description: "Odometer reading at trip end (units not confirmed)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "fuel_used",
        value_type: ValueType::Text,
        description: "Fuel consumed during the trip leg (units not confirmed)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "driving_range",
        value_type: ValueType::Text,
        description: "Driving range for the trip leg (units not confirmed but usable for trending)",
        is_uid_component: false,
    },
];

pub(crate) static HONDA_ACCORD_CRM_ECO_LOGS: ArtifactDescriptor = ArtifactDescriptor {
    id: "honda_accord_crm_eco_logs",
    name: "Honda Accord CRM Eco Logs (Trip Telemetry)",
    artifact_type: ArtifactType::DatabaseEntry,
    hive: None,
    key_path: "",
    value_name: None,
    // Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
    file_path: Some("/data/com.honda.telematics.core/databases/crm.db"),
    scope: DataScope::System,
    os_scope: OsScope::Android,
    decoder: Decoder::Identity,
    retention: None,
    meaning: "Honda telematics 'eco_logs' table in crm.db on Honda Accord (2016) Clarion \
        Android-based infotainment. Logs timestamped journey legs with start/finish odometer \
        readings, mileage, fuel consumption, and driving range. Trip legs are grouped by \
        trip_id. Useful for establishing vehicle usage patterns and correlating trip times \
        with other evidence. Units for mileage, odometer, fuel, and range are not confirmed \
        but values are internally consistent and usable for trending analysis.",
    mitre_techniques: &[],
    fields: HONDA_ACCORD_CRM_ECO_LOGS_FIELDS,
    triage_priority: TriagePriority::Medium,
    sources: &[
        "https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html",
        "https://github.com/cheeky4n6monkey/Honda_Accord_2016_scripts",
    ],
    related_artifacts: &[
        "honda_accord_recentstops",
        "honda_accord_phonedb",
        "honda_accord_bluetooth",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Units for mileage/odometer/fuel/range not confirmed",
        "Limited to specific Honda Accord 2016 Clarion infotainment",
    ],
    volatility: Some(crate::volatility::VolatilityClass::ActivityDriven),
    volatility_rationale: "Telemetry log updated per trip leg; bounded by app retention",
};

// ── Honda Accord Phone DB (Bluetooth call history & contacts) ───────────────

/// Field schema for the `call_history` and `contact`/`contactnumber` tables in phonedb.db.
/// Call History SQL: SELECT _id, address, phonenum, calldate, calltype
///                   FROM call_history ORDER BY calldate ASC;
/// Contacts SQL: SELECT contact._id, contact.address, contact.firstName,
///               contact.lastName, contact.phonename, contactnumber.number,
///               contactnumber.numbertype
///               FROM contact JOIN contactnumber
///               ON contactnumber.contact_id = contact._id
///               ORDER BY contact._id ASC;
/// Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
pub(crate) static HONDA_ACCORD_PHONEDB_FIELDS: &[FieldSchema] = &[
    FieldSchema {
        name: "_id",
        value_type: ValueType::Integer,
        description: "Auto-increment row identifier",
        is_uid_component: true,
    },
    FieldSchema {
        name: "address",
        value_type: ValueType::Text,
        description: "MAC address of the Bluetooth device that synced this record",
        is_uid_component: false,
    },
    FieldSchema {
        name: "phonenum",
        value_type: ValueType::Text,
        description: "Phone number associated with the call (call_history table)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "calldate",
        value_type: ValueType::Timestamp,
        // Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
        description: "Call timestamp as milliseconds since 1 Jan 1970 (UTC). Displayed as \
            ISO-formatted string when parsed",
        is_uid_component: false,
    },
    FieldSchema {
        name: "calltype",
        value_type: ValueType::Integer,
        description: "Call type indicator (observed values: 1, 2, 3). Likely maps to \
            incoming/outgoing/missed but exact mapping requires confirmation via call \
            charge records or device comparison",
        is_uid_component: false,
    },
    FieldSchema {
        name: "firstName",
        value_type: ValueType::Text,
        description: "Contact first name (from contact table JOIN)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "lastName",
        value_type: ValueType::Text,
        description: "Contact last name (from contact table JOIN)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "phonename",
        value_type: ValueType::Text,
        description: "Name of the phone that synced the contact (from contact table)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "contactnumber",
        value_type: ValueType::Text,
        description: "Contact phone number (from contactnumber table JOIN)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "contacttype",
        value_type: ValueType::Integer,
        description: "Contact number type; observed consistently as 3 in test data. \
            Likely maps to standard vCard TEL types",
        is_uid_component: false,
    },
];

pub(crate) static HONDA_ACCORD_PHONEDB: ArtifactDescriptor = ArtifactDescriptor {
    id: "honda_accord_phonedb",
    name: "Honda Accord Phone DB (Bluetooth Call History & Contacts)",
    artifact_type: ArtifactType::DatabaseEntry,
    hive: None,
    key_path: "",
    value_name: None,
    // Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
    file_path: Some("/data/com.clarion.bluetooth/databases/phonedb.db"),
    scope: DataScope::User,
    os_scope: OsScope::Android,
    decoder: Decoder::Identity,
    retention: None,
    meaning: "Clarion Bluetooth 'call_history', 'contact', and 'contactnumber' tables in \
        phonedb.db on Honda Accord (2016) infotainment. Records call history and contacts \
        synced from paired phones via Bluetooth. Call timestamps are UNIX milliseconds (UTC). \
        The 'address' field contains the Bluetooth MAC of the syncing device. A Write-Ahead-Log \
        (phonedb.db-wal) may contain additional uncommitted records — parse both with and \
        without the WAL for completeness. High forensic value for communications evidence \
        and device attribution.",
    mitre_techniques: &[],
    fields: HONDA_ACCORD_PHONEDB_FIELDS,
    triage_priority: TriagePriority::High,
    sources: &[
        "https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html",
        "https://github.com/cheeky4n6monkey/Honda_Accord_2016_scripts",
    ],
    related_artifacts: &[
        "honda_accord_bluetooth",
        "honda_accord_recentstops",
        "honda_accord_crm_eco_logs",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Reflects only data synced from paired phones, not vehicle-originated calls",
        "WAL file may contain additional uncommitted records",
    ],
    volatility: Some(crate::volatility::VolatilityClass::ActivityDriven),
    volatility_rationale: "Database updated per Bluetooth sync; bounded by app retention",
};

// ── Honda Accord Bluetooth Settings (paired devices) ────────────────────────

/// Field schema for the `bluetooth_device` table in bluetoothsettings.db.
/// SQL: SELECT device_bank, device_addr, device_name FROM bluetooth_device
///      ORDER BY device_bank ASC;
/// Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
pub(crate) static HONDA_ACCORD_BLUETOOTH_FIELDS: &[FieldSchema] = &[
    FieldSchema {
        name: "device_bank",
        value_type: ValueType::Integer,
        description: "Index/bank number for each paired device entry",
        is_uid_component: true,
    },
    FieldSchema {
        name: "device_addr",
        value_type: ValueType::Text,
        description: "Bluetooth MAC address of the paired device",
        is_uid_component: false,
    },
    FieldSchema {
        name: "device_name",
        value_type: ValueType::Text,
        description: "User-visible name of the paired Bluetooth device (e.g. phone model \
            or user-assigned name)",
        is_uid_component: false,
    },
];

pub(crate) static HONDA_ACCORD_BLUETOOTH: ArtifactDescriptor = ArtifactDescriptor {
    id: "honda_accord_bluetooth",
    name: "Honda Accord Bluetooth Settings (Paired Devices)",
    artifact_type: ArtifactType::DatabaseEntry,
    hive: None,
    key_path: "",
    value_name: None,
    // Source: https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html
    file_path: Some("/data/com.clarion.bluetooth/databases/bluetoothsettings.db"),
    scope: DataScope::System,
    os_scope: OsScope::Android,
    decoder: Decoder::Identity,
    retention: None,
    meaning:
        "Clarion Bluetooth 'bluetooth_device' table in bluetoothsettings.db on Honda \
        Accord (2016) infotainment. Records Bluetooth MAC addresses and device names of all \
        phones/devices that have been paired with the vehicle. A companion 'speed_dial' table \
        exists but was found empty. Data is consistent with the paired_device_list.txt found \
        at /system/alps/evolution/paired_device_list.txt on Partition3. Useful for identifying \
        which phones connected to the vehicle and correlating with phonedb.db call/contact records.",
    mitre_techniques: &[],
    fields: HONDA_ACCORD_BLUETOOTH_FIELDS,
    triage_priority: TriagePriority::Medium,
    sources: &[
        "https://cheeky4n6monkey.blogspot.com/2021/03/monkey-test-drives-honda-accord.html",
        "https://github.com/cheeky4n6monkey/Honda_Accord_2016_scripts",
    ],
    related_artifacts: &[
        "honda_accord_phonedb",
        "honda_accord_recentstops",
        "honda_accord_crm_eco_logs",
    ],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Definitive),
    evidence_caveats: &[
        "Records all paired devices regardless of recent connection — no last-connect timestamp",
    ],
    volatility: Some(crate::volatility::VolatilityClass::Persistent),
    volatility_rationale: "Pairing database persists until user unpairs the device",
};

// ── Garmin nuvi Voice Log (TTS navigation instructions) ─────────────────────

/// Field schema for parsed lines from vpm_log_all.log on Garmin nuvi devices.
/// Each log line follows the format:
///   D[YYYY/MM/DD HH:MM:SS] {hex_id} [source_file:function:line] Message
/// Source: https://cheeky4n6monkey.blogspot.com/2020/05/recovering-and-replaying-garmin-voice.html
pub(crate) static GARMIN_NUVI_VOICE_LOG_FIELDS: &[FieldSchema] = &[
    FieldSchema {
        name: "timestamp",
        value_type: ValueType::Timestamp,
        description: "Log entry timestamp in D[YYYY/MM/DD HH:MM:SS] format. Uses Garmin \
            epoch (seconds since 31 Dec 1989). Add 631065600 to convert to UNIX epoch",
        is_uid_component: true,
    },
    FieldSchema {
        name: "hex_id",
        value_type: ValueType::Text,
        description: "4-byte hex identifier (possibly process or thread ID)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "source_function",
        value_type: ValueType::Text,
        description: "Source code reference indicating which TTS subsystem generated the entry \
            (e.g. vpm_tts_parse.c:vpm_tts_parse:3770 for navigation phrases, \
            vpm_tts_log.c:vpm_tts_log_phonetics:277 for phonetic output)",
        is_uid_component: false,
    },
    FieldSchema {
        name: "voice_string",
        value_type: ValueType::Text,
        description: "The spoken navigation instruction text or phonetic representation. \
            Navigation phrases contain template variables like $USR_TO_NEXT_ROAD. \
            Phonetic entries use IPA-like notation for text-to-speech synthesis. \
            Both types together reconstruct the turn-by-turn directions given to the driver",
        is_uid_component: false,
    },
    FieldSchema {
        name: "mdb_lang",
        value_type: ValueType::Integer,
        description: "Language identifier from the map database (e.g. 23 observed in test data). \
            Indicates which language pack was used for voice synthesis",
        is_uid_component: false,
    },
];

pub(crate) static GARMIN_NUVI_VOICE_LOG: ArtifactDescriptor = ArtifactDescriptor {
    id: "garmin_nuvi_voice_log",
    name: "Garmin nuvi GPS Voice Instruction Log (vpm_log_all)",
    artifact_type: ArtifactType::File,
    hive: None,
    key_path: "",
    value_name: None,
    // Source: https://cheeky4n6monkey.blogspot.com/2020/05/recovering-and-replaying-garmin-voice.html
    file_path: Some("Voice/logs/vpm_log_all.log"),
    scope: DataScope::System,
    os_scope: OsScope::All,
    decoder: Decoder::Identity,
    retention: None,
    meaning: "Garmin nuvi GPS text-to-speech voice instruction log found on the FAT32 partition \
        at Voice/logs/vpm_log_all.log. Contains chronologically ordered, timestamped spoken \
        navigation instructions. Each line records either a navigation phrase (e.g. 'Keep right', \
        'Turn left') with template variables, or the corresponding phonetic representation used \
        for TTS synthesis. Tested on Garmin nuvi 56LM but may apply to other Garmin models. \
        The device typically has two partitions: FAT16 (128 MB) and FAT32 (main storage with \
        GPX tracklogs under Garmin/ and voice logs under Voice/). Timestamps use Garmin epoch \
        (seconds since 31 Dec 1989; add 631065600 for UNIX epoch). High forensic value for \
        reconstructing routes and navigation history from damaged or recovered GPS devices. \
        Voice strings can be converted to audio using espeak-ng for audible playback of the \
        navigation instructions.",
    mitre_techniques: &[],
    fields: GARMIN_NUVI_VOICE_LOG_FIELDS,
    triage_priority: TriagePriority::High,
    sources: &[
        "https://cheeky4n6monkey.blogspot.com/2020/05/recovering-and-replaying-garmin-voice.html",
        "https://github.com/cheeky4n6monkey/4n6-scripts",
    ],
    related_artifacts: &[],
    evidence_strength: Some(crate::evidence::EvidenceStrength::Strong),
    evidence_caveats: &[
        "Tested only on Garmin nuvi 56LM; coverage on other models unconfirmed",
        "Voice phrases use template variables — actual instruction values may need correlation",
    ],
    volatility: Some(crate::volatility::VolatilityClass::RotatingBuffer),
    volatility_rationale: "Append-only log file with bounded size on FAT32 partition",
};