Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions scripts/artifacts/FacebookMessenger.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,23 @@
"description": "Facebook/Messenger chat messages (msys_database)",
"author": "Kevin Pagano",
"creation_date": "2021-03-03",
"last_update_date": "2021-03-03",
"last_update_date": "2026-07-03",
"requirements": "none",
"category": "Facebook Messenger",
"notes": "",
"paths": ('*/msys_database*',),
"output_types": "standard",
"artifact_icon": "message-square",
"data_views": {
"conversation": {
"conversationDiscriminatorColumn": "Thread Key",
"textColumn": "Message",
"directionColumn": "Direction",
"directionSentValue": "Outgoing",
"timeColumn": "Message Timestamp",
"senderColumn": "Sender"
}
},
},
"get_fb_msys_calls": {
"name": "Facebook Messenger - Calls (msys_database)",
Expand Down Expand Up @@ -164,6 +174,16 @@ def get_fb_msys_chats(files_found, report_folder, seeker, wrap_text):
if 'msys_database_' not in file_found:
continue
source = source or file_found
# local account uid from the threads_db2-uid file (fetched via paths)
fb_uid = ''
for uid_file in files_found:
if str(uid_file).endswith('threads_db2-uid'):
try:
with open(str(uid_file), 'r', encoding='utf-8', errors='replace') as dat:
fb_uid = next((line.strip() for line in dat if line.strip()), '')
except OSError:
fb_uid = ''
break
rel = _src(file_found, seeker)
db = open_sqlite_db_readonly(file_found)
cursor = db.cursor()
Expand Down Expand Up @@ -196,16 +216,20 @@ def get_fb_msys_chats(files_found, report_folder, seeker, wrap_text):
ORDER BY messages.timestamp_ms ASC
''')
for row in rows:
if fb_uid and row[2] is not None:
direction = 'Outgoing' if str(row[2]) == fb_uid else 'Incoming'
else:
direction = ''
data_list.append((_str_to_utc(row[0]), row[1], row[2], row[3], row[4], row[5], row[6],
row[7], row[8], row[9], row[10], row[11], _str_to_utc(row[12]), row[13],
row[14], rel))
row[14], rel, direction))
db.close()

data_headers = (('Message Timestamp', 'datetime'), 'Sender', 'Sender ID', 'Thread Key', 'Message',
'Snippet', 'Call/Location Information', 'Attachment Name', 'Attachment Type',
'Attachment URL', 'Location Lat/Long', 'Reaction',
('Reaction Timestamp', 'datetime'), 'Is Admin Message', 'Message ID',
'Source File')
'Source File', 'Direction')
return data_headers, data_list, source


Expand Down
27 changes: 25 additions & 2 deletions scripts/artifacts/WhatsApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"description": "WhatsApp 1:1 messages (modern msgstore.db schema)",
"author": "",
"creation_date": "2021-03-11",
"last_update_date": "2021-03-11",
"last_update_date": "2026-07-03",
"requirements": "none",
"category": "WhatsApp",
"notes": "",
Expand All @@ -53,13 +53,25 @@
'*/Android/media/com.whatsapp/WhatsApp/Media/*'),
"output_types": "standard",
"artifact_icon": "message-square",
"data_views": {
"conversation": {
"conversationDiscriminatorColumn": "Other Participant WA User Name",
"textColumn": "Message",
"directionColumn": "Message Direction",
"directionSentValue": "Outgoing",
"timeColumn": "Message Timestamp",
"senderColumn": "Other Participant WA User Name",
"sentMessageStaticLabel": "Local User",
"mediaColumn": "Media"
}
},
},
"get_whatsapp_group_messages": {
"name": "WhatsApp - Group Messages",
"description": "WhatsApp group messages (modern msgstore.db schema)",
"author": "",
"creation_date": "2021-03-11",
"last_update_date": "2021-03-11",
"last_update_date": "2026-07-03",
"requirements": "none",
"category": "WhatsApp",
"notes": "",
Expand All @@ -68,6 +80,17 @@
'*/Android/media/com.whatsapp/WhatsApp/Media/*'),
"output_types": "standard",
"artifact_icon": "message-square",
"data_views": {
"conversation": {
"conversationDiscriminatorColumn": "Conversation Name",
"textColumn": "Message",
"directionColumn": "Message Direction",
"directionSentValue": "Outgoing",
"timeColumn": "Message Timestamp",
"senderColumn": "Sending Party",
"mediaColumn": "Media"
}
},
},
"get_whatsapp_group_details": {
"name": "WhatsApp - Group Details",
Expand Down
13 changes: 12 additions & 1 deletion scripts/artifacts/googleVoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,24 @@
"description": "Parses Google Voice Messages",
"author": "William Campbell (@campwill), Eli Ehresmann (@H-Seek), Reina Girouard (@rgrd59), Paula Rokusek (@paula-rokusek)",
"creation_date": "2025-10-22",
"last_update_date": "2025-11-5",
"last_update_date": "2026-07-03",
"requirements": "blackboxprotobuf",
"category": "Google Voice",
"notes": "Tested on version 2025.07.20.788599304 (October 29th, 2025). Tested on Samsung and Motorola devices.",
"paths": ('*/data/com.google.android.apps.googlevoice/files/accounts/*/LegacyMsgDbInstance.db*', '*/data/com.google.android.apps.googlevoice/cache/Photo MMS images/*', '*/data/com.samsung.android.providers.contacts/databases/contact*'),
"output_types": ["html", "tsv", "lava"],
"artifact_icon": "user",
"data_views": {
"conversation": {
"conversationDiscriminatorColumn": "Conversation ID",
"textColumn": "Message",
"directionColumn": "Direction",
"directionSentValue": "Outgoing",
"timeColumn": "Timestamp",
"senderColumn": "Sender",
"mediaColumn": "Image"
}
},
}
}

Expand Down
16 changes: 14 additions & 2 deletions scripts/artifacts/imo.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,24 @@
"description": "",
"author": "",
"creation_date": "2021-03-11",
"last_update_date": "2021-03-11",
"last_update_date": "2026-07-03",
"requirements": "none",
"category": "IMO",
"notes": "",
"paths": ('*/com.imo.android.imous/databases/imofriends.db*',),
"output_types": "standard",
"artifact_icon": "message-square",
"data_views": {
"conversation": {
"conversationDiscriminatorColumn": "Chat Partner",
"textColumn": "Last Message",
"directionColumn": "Direction",
"directionSentValue": "Outgoing",
"timeColumn": "Timestamp",
"senderColumn": "Chat Partner",
"sentMessageStaticLabel": "Local User"
}
},
}
}

Expand Down Expand Up @@ -101,7 +112,7 @@ def get_imo_messages(files_found, report_folder, seeker, wrap_text):
attachmentPath = attachmentLocalPath

timestamp = datetime.datetime.fromtimestamp(int(row[3]), datetime.timezone.utc)
data_list.append((timestamp, from_id, to_id, row[2], row[4], row[5], attachmentPath))
data_list.append((timestamp, from_id, to_id, row[2], row[4], row[5], attachmentPath, row[0]))
db.close()

data_headers = (
Expand All @@ -112,5 +123,6 @@ def get_imo_messages(files_found, report_folder, seeker, wrap_text):
'Direction',
'Message Read',
'Attachment',
'Chat Partner',
)
return data_headers, data_list, source_path
31 changes: 27 additions & 4 deletions scripts/artifacts/teleguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@
"description": "Teleguard messenger messages",
"author": "",
"creation_date": "2024-01-09",
"last_update_date": "2024-01-09",
"last_update_date": "2026-07-03",
"requirements": "none",
"category": "Teleguard",
"notes": "",
"paths": ('*/data/ch.swisscows.messenger.teleguardapp/app_flutter/teleguard_database.db*',
'*/data/ch.swisscows.messenger.teleguardapp/cache/**'),
"output_types": "standard",
"artifact_icon": "message-square",
"data_views": {
"conversation": {
"conversationDiscriminatorColumn": "Chat ID",
"textColumn": "Content",
"directionColumn": "Direction",
"directionSentValue": "Outgoing",
"timeColumn": "Timestamp",
"senderColumn": "Sender",
"mediaColumn": "Media"
}
},
},
"get_teleguard_posts": {
"name": "Teleguard - Posts",
Expand Down Expand Up @@ -99,9 +110,16 @@ def get_teleguard(files_found, report_folder, seeker, wrap_text):
source_path = _db(files_found)
rows = _run(source_path, '''
SELECT datetime(createDate/1000,'unixepoch'), datetime(userTime/1000,'unixepoch'),
type, sender, receiver, content, metadata, status, isEdited
type, sender, receiver, content, metadata, status, isEdited, chatId
FROM messages
''')
# local account id lives in the service table ('user' row) of the same db
owner_id = ''
for (svc_data,) in _run(source_path, "SELECT data FROM service WHERE id = 'user'"):
try:
owner_id = (json.loads(svc_data) or {}).get('serverId', '')
except (ValueError, TypeError):
owner_id = ''
data_list = []
for row in rows:
media_refs = []
Expand Down Expand Up @@ -129,11 +147,16 @@ def get_teleguard(files_found, report_folder, seeker, wrap_text):
media_cell = media_refs
else:
media_cell = ''
if owner_id and row[3]:
direction = 'Outgoing' if row[3] == owner_id else 'Incoming'
else:
direction = ''
data_list.append((_str_to_utc(row[0]), _str_to_utc(row[1]), row[2], row[3], row[4], row[5],
media_cell, row[6], row[7], row[8]))
media_cell, row[6], row[7], row[8], direction, row[9]))

data_headers = (('Timestamp', 'datetime'), ('User Time', 'datetime'), 'Type', 'Sender', 'Receiver',
'Content', ('Media', 'media'), 'Metadata', 'Status', 'Is Edited?')
'Content', ('Media', 'media'), 'Metadata', 'Status', 'Is Edited?', 'Direction',
'Chat ID')
return data_headers, data_list, source_path


Expand Down
Loading