From 19915d278fff8796f136fceeba31c7a5f4584d85 Mon Sep 17 00:00:00 2001 From: charpy4n6 <112824930+charpy4n6@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:35:02 -0500 Subject: [PATCH 1/2] Add files via upload Parses external.db located at com.android.providers.media --- scripts/artifacts/externalDB.py | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 scripts/artifacts/externalDB.py diff --git a/scripts/artifacts/externalDB.py b/scripts/artifacts/externalDB.py new file mode 100644 index 00000000..43045349 --- /dev/null +++ b/scripts/artifacts/externalDB.py @@ -0,0 +1,90 @@ +__artifacts_v2__ = { + "externalDB": { + "name": "External Database", + "description": "Parses External Database", + "author": "Heather Charpentier", + "creation_date": "2025-11-17", + "last_updated_date": "2025-11-17", + "requirements": "none", + "category": "ExternalDB", + "notes": "", + "paths": ('*/data/com.android.providers.media/databases/external.db*'), + "output_types": "standard", + "artifact_icon": "download", + } +} + +from scripts.ilapfuncs import artifact_processor, open_sqlite_db_readonly + +@artifact_processor +def externalDB(files_found, report_folder, seeker, wrap_text): + + data_list = [] + source_path = '' + + candidate_dbs = [] + + for file_found in files_found: + file_str = str(file_found).lower() + + if file_str.endswith('.db') and ( + 'media' in file_str or + 'external' in file_str or + 'internal' in file_str or + 'files' in file_str + ): + candidate_dbs.append(str(file_found)) + + if not candidate_dbs: + return ( + ('Path','Size',('Date Taken','datetime'),('Date Added','datetime'),('Date Modified','datetime'),'Album Name','Display Name','Directory','Duration'), + data_list, + source_path + ) + + for db_path in candidate_dbs: + + try: + db = open_sqlite_db_readonly(db_path) + source_path = db_path + + cursor = db.cursor() + + cursor.execute( + "SELECT name FROM sqlite_master WHERE type='table' AND name='files';" + ) + table_check = cursor.fetchone() + + if not table_check: + db.close() + continue + + cursor.execute(''' + SELECT + datetime(datetaken/1000, 'unixepoch') AS "Date Taken", + datetime(date_added, 'unixepoch') AS "Date Added", + datetime(date_modified, 'unixepoch') AS "Date Modified", + album AS "Album Name", + _display_name AS "Display Name", + _data AS "Path", + duration AS "Duration", + _size AS "Size" + FROM files + ''') + + rows = cursor.fetchall() + + for row in rows: + data_list.append(( + row[0], row[1], row[2], row[3], row[4],row[5], row[6], row[7] + )) + + db.close() + + except Exception as e: + continue + + data_headers = (('Date Taken','datetime'),('Date Added','datetime'),('Date Modified','datetime'),'Album Name','Display Name','Path','Duration','Size') + + return data_headers, data_list, source_path + From b408f0716724b74e3fb54ee44eb07aa41c59ba35 Mon Sep 17 00:00:00 2001 From: charpy4n6 <112824930+charpy4n6@users.noreply.github.com> Date: Thu, 11 Dec 2025 13:23:02 -0500 Subject: [PATCH 2/2] MeWe The application updated and the database related to MeWe messages is now called app_v3.db. It is in the same location and its tables and columns still match the original mewe.py. --- scripts/artifacts/mewe.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/scripts/artifacts/mewe.py b/scripts/artifacts/mewe.py index fc9f9400..866f1721 100644 --- a/scripts/artifacts/mewe.py +++ b/scripts/artifacts/mewe.py @@ -4,8 +4,9 @@ from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly APP_NAME = 'MeWe' -DB_NAME = 'app_database' +DB_NAMES = ('app_database', 'app_v3.db') # Added support for app_v3.db SGSESSION_FILE = 'SGSession.xml' + CHAT_MESSAGES_QUERY = ''' SELECT DATETIME(createdAt, 'unixepoch'), @@ -31,6 +32,7 @@ JOIN CHAT_THREAD ON threadId = CHAT_THREAD.id ''' + def _perform_query(cursor, query): try: cursor.execute(query) @@ -71,11 +73,11 @@ def _parse_xml(xml_file, xml_file_name, report_folder, title, report_name): value = node.attrib['value'] except: value = node.text - + data_list.append((node.attrib['name'], value)) tl_bool = False - + _make_reports(f'{APP_NAME} - {report_name}', data_headers, data_list, report_folder, xml_file_name, tl_bool) @@ -116,12 +118,12 @@ def get_mewe(files_found, report_folder, seeker, wrap_text): db_file_name = None xml_file = None xml_file_name = None - + app_database_processed = False sgsession_processed = False for ff in files_found: - if ff.endswith(DB_NAME) and not app_database_processed: + if ff.endswith(DB_NAMES) and not app_database_processed: db_file = ff db_file_name = ff.replace(seeker.data_folder, '') _parse_app_database(db_file, db_file_name, report_folder) @@ -131,16 +133,17 @@ def get_mewe(files_found, report_folder, seeker, wrap_text): xml_file_name = ff.replace(seeker.data_folder, '') _parse_xml(xml_file, xml_file_name, report_folder, SGSESSION_FILE, 'SGSession') sgsession_processed = True - + artifacts = [ app_database_processed, sgsession_processed ] if not (True in artifacts): logfunc(f'{APP_NAME} data not found') + __artifacts__ = { - "mewe": ( - "MeWe", - ('*/com.mewe/databases/app_database', '*/com.mewe/shared_prefs/SGSession.xml'), - get_mewe) -} \ No newline at end of file + "mewe": ( + "MeWe", + ('*/com.mewe/databases/app_database', '*/com.mewe/databases/app_v3.db', '*/com.mewe/shared_prefs/SGSession.xml'), + get_mewe) +}