Saturday 28 November 2020

iOS14 Maps History BLOB Script

 

Another BLOBBY SQL (Sequel)!

A quick post to introduce a new iOS 14 Apple Maps History helper script ...
Thanks to Heather Mahalik for sharing her research and for both her and her associate Sahil's testing.
You can read about Heather's iOS14 research at her blog here.

The script (ios14_maps_history.py) focuses on the Apple Maps app's MapsSync_0.0.1 SQLite database which can contain the last 3-5 directions/searches.
There are 32 tables in the database but as we see in Heather's query below - most of the history info is stored in a table called ZHISTORYITEM and in the ZMIXINMAPITEM table. Both tables can contain protobuf BLOBs which are extracted by the script for further processing by the user along with an HTML summary report.

SELECT
ZHISTORYITEM.z_pk AS 'Item Number',
CASE
when ZHISTORYITEM.z_ent = 14 then 'coordinates of search'
when ZHISTORYITEM.z_ent = 16 then 'location search'
when ZHISTORYITEM.z_ent = 12 then 'navigation journey'
end AS 'Type',
datetime(ZHISTORYITEM.ZCREATETIME+978307200,'UNIXEPOCH','localtime') AS 'Time Created',
datetime(ZHISTORYITEM.ZMODIFICATIONTIME+978307200,'UNIXEPOCH','localtime') AS 'Time Modified',
ZHISTORYITEM.ZQUERY AS 'Location Search',
ZHISTORYITEM.ZLOCATIONDISPLAY AS 'Location City',
ZHISTORYITEM.ZLATITUDE AS 'Latitude',
ZHISTORYITEM.ZLONGITUDE AS 'Longitude',
ZHISTORYITEM.ZROUTEREQUESTSTORAGE AS 'Journey BLOB',
ZMIXINMAPITEM.ZMAPITEMSTORAGE as 'Map Item Storage BLOB'
from ZHISTORYITEM
left join ZMIXINMAPITEM on ZMIXINMAPITEM.Z_PK=ZHISTORYITEM.ZMAPITEM;
From the query we can see there 3 types of entry:
- "Location search"
- "Coordinates of search" (usually has a "Map Item Storage" BLOB in ZMAPITEMSTORAGE column)
- "Navigation journey" (usually has a "Journey" BLOB in ZROUTEREQUESTSTORAGE column)

Please note as per Heather's blog - "Time Created" (and presumably "Time Modified") are NOT accurate records of when the search was executed.

"Location search" entries (i.e. search location text) seem to be followed by "Coordinates of search" entries (containing the latitude/longitude of the search location).

When directions are requested, a "Navigation journey" entry is created with a "Journey BLOB" which contains the start/end locations.
However, "Navigation journey" entries also seem to be generated even if the user does not explicitly ask for a journey to be calculated. There were 2 such entries in Sahil's data despite him not navigating with the device.

Further research is required into these BLOBs - hence the script :)

The ios14_maps_history.py runs Heather's query and creates an HTML report (called iOS14-MapsReport.html) with links to the extracted BLOB files.
Each BLOB is extracted from the database and stored in the user's nominated output directory.
The script has been tested with Python3 on Ubuntu 20 and Win10x64.

Usage example for Ubuntu 20.04 LTS with Python 3.8.2:
python3 ios14_maps_history.py -d MapsSync_0.0.1 -o optest
This will output Heather's query to an HTML table with hyperlinks to each extracted BLOB file.
All files will be created in the user nominated "optest" directory.

The corresponding command line output looks like:

Running ios14_maps_history.py v2020-09-19

Processed 15 entries

Please refer to iOS14-MapsReport.html in "optest" directory
Exiting ...

Usage example for Win10 with Python 3.6:
c:\Python36\python.exe ios14_maps_history.py -d MapsSync_0.0.1 -o opdir
Here's what the output HTML table looks like:
 
Note: lat/longs were redacted to protect the not-so-innocent ;)

The outputted BLOBs can be researched further with tools like protobuf_inspector.
This is a very funky tool which pretty prints a protobuf and also interprets 64bit fields in multiple ways (useful for finding potential lat/longs).
Its also "pipping" easy to install ... 
pip install protobuf-inspector

Monkey has used protobuf_inspector on extracted Apple Maps protobufs to find some destination Yelp reviews and what appears to be epoch millisecond timestamps (ref. 1JAN1970) which occur just after a GUID.
However, because its not my test data and its a small sample size, I can't confirm if its the time of search ...

Anyway, this is where this post ends ... Good luck to those about to dive further into the protobuf swamp!
If you happen to use this script to find something interesting, please leave a comment and share the knowledge :)