diff --git a/scripts/artifacts/geodMapTiles.py b/scripts/artifacts/geodMapTiles.py index e27284df..95202859 100644 --- a/scripts/artifacts/geodMapTiles.py +++ b/scripts/artifacts/geodMapTiles.py @@ -1,29 +1,38 @@ +""" geodMapTiles """ __artifacts_v2__ = { "geodMapTiles": { "name": "GeoD Maptiles", "description": "Parses Map Tile Records from Apple geod Cache", "author": "@ydkhatri", - "version": "0.0.2", - "date": "2024-10-17", + "creation_date": "2024-10-17", + "last_update_date": "2026-06-17", "requirements": "none", "category": "Location", "notes": "", "paths": ('**/MapTiles.sqlitedb*'), - "output_types": ['lava', 'tsv', 'timeline'] + "output_types": "standard" } } -import base64 import gzip import struct import sqlite3 import zlib +from io import BytesIO -from scripts.artifact_report import ArtifactHtmlReport -from scripts.ilapfuncs import logfunc, open_sqlite_db_readonly, does_table_exist_in_db, artifact_processor +from PIL import Image +from pillow_heif import register_heif_opener +from scripts.filetype import guess_mime +from scripts.ilapfuncs import ( + artifact_processor, + check_in_embedded_media, + does_table_exist_in_db, + logfunc, + open_sqlite_db_readonly +) -def ReadVLOC(data): +def read_vloc(data): names = [] total_len = len(data) pos = 8 @@ -43,31 +52,40 @@ def ReadVLOC(data): return names -def ParseTCOL(data): +def parse_tcol(data): '''returns tuple (VMP4 places, VLOC places)''' tcol_places = [] data_size = len(data) - if data_size >=8: - tcol_data_offset = struct.unpack('", tcol_places) - except (OSError, EOFError, zlib.error) as ex: - logfunc('Gzip decompression error from ParseTCOL() - ' + str(ex)) - tcol_places = '' - vmp4_places = ParseVMP4(data[8:tcol_data_offset]) - return vmp4_places, ReadVLOC(tcol_places) - - -def ParseVMP4(data): + if data_size < 8: + return [], [] + + tcol_data_offset = struct.unpack('", tcol_places) + except (OSError, EOFError, zlib.error) as ex: + logfunc('Gzip decompression error from ParseTCOL() - ' + str(ex)) + tcol_places = '' + vmp4_places = parse_vmp4(data[8:tcol_data_offset]) + return vmp4_places, read_vloc(tcol_places) + + +def parse_vmp4(data): + if len(data) < 8: + return [] + num_items = struct.unpack(' len(data): + break item_type, offset, size = struct.unpack(" 0: for row in all_rows: @@ -144,44 +215,21 @@ def geodMapTiles(files_found, report_folder, seeker, wrap_text, timezone_offset) data_parsed = '' data = row['data'] if data: # NULL sometimes - if len(data) >= 11 and data[:11] == b'\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00': - img_base64 = base64.b64encode(data).decode('utf-8') - img_html = f'Map Tile' - data_parsed = img_html - elif len(data) >= 4 and data[:4] == b'TCOL': - vmp4_places, tcol_places = ParseTCOL(data) + name = f"Map Tile {get_hex(row['tileset'])} {get_hex(row['key_a'])}-{get_hex(row['key_b'])}" + data_parsed = check_in_tile_image(file_found, data, name) + if not data_parsed and len(data) >= 4 and data[:4] == b'TCOL': + vmp4_places, tcol_places = parse_tcol(data) vmp4_places = ", ".join(vmp4_places) tcol_places = ", ".join(tcol_places) - elif len(data) >=4 and data[:4] == b'VMP4': - vmp4_places = ParseVMP4(data) + elif not data_parsed and len(data) >= 4 and data[:4] == b'VMP4': + vmp4_places = parse_vmp4(data) vmp4_places = ", ".join(vmp4_places) - #else: - #header_bytes = data[:28] - #hexdump = generate_hexdump(header_bytes, 5) if header_bytes else '' - #data_parsed = hexdump - - if usesDataTable: - data_list.append((row['timestamp'], tcol_places, vmp4_places, data_parsed, get_hex(row['tileset']), - get_hex(row['key_a']), get_hex(row['key_b']), get_hex(row['key_c']), get_hex(row['key_d'])) ) - # row['size']) , row['etag'])) - else: - data_list.append((row['timestamp'], tcol_places, vmp4_places, data_parsed, get_hex(row['tileset']), - get_hex(row['a']), get_hex(row['b']), get_hex(row['c']), get_hex(row['d'])) ) - # row['size']) , row['etag'])) - - description = '' - report = ArtifactHtmlReport('Geolocation') - report.start_artifact_report(report_folder, 'Map Tile Cache', description) - report.add_script() - data_headers = ["Timestamp", "Places_from_VLOC", "Labels_in_tile", "Image", "Tileset", "Key A", "Key B", "Key C", "Key D"]#, "Size", "ETAG") - report.write_artifact_data_table(data_headers, data_list, file_found, html_escape = False) - report.end_artifact_report() - - db.close() - data_headers[0] = (data_headers[0], 'datetime') + row_data = ( + row['timestamp'], tcol_places, vmp4_places, data_parsed, + get_hex(row['tileset']), get_hex(row['key_a']), get_hex(row['key_b']), + get_hex(row['key_c']), get_hex(row['key_d']) + ) + data_list.append(row_data) - # remove the image from lava output until Media Manager is ready - data_list = [(row[0], row[1], row[2], 'See HTML Report', row[4], row[5], row[6], row[7], row[8]) - if row[3] else row for row in data_list] - return data_headers, data_list, file_found \ No newline at end of file + return data_headers, data_list, file_found