Note: a keen eye by one of my favorite FBI folks caught some issues in the original version of this blog. Specifically, with regards to latitude and longitude values being stored in hexadecimal values. TL;DR, the hexadecimal values were, in fact, NOT latitude and longitude values. Thank you for letting me know!
I am a firm believer that digital forensic artifact discovery is, at times, equal parts persistence and luck, with the latter being a combination of preparation and opportunity. You really never know what you will discover until you actually start looking. Sometimes you start looking for evidence of A and end up finding evidence of B. This year’s Cellebrite CTF resulted in my finding data in a Google Maps artifact that I was aware of, but did not fully understand. I stumbled across it, and others, while writing questions for the Russell extraction. Yes, it was me who wrote those questions.
This will be the first half of a walkthrough of location data in Google Maps. This part will focus on Android, while part 2 will cover iOS.
Google Maps needs no introduction. It is ubiquitious. I will also be skipping the usual UI walk around.
For the uninitiated, Google Maps on Android resides in USERDATA/data/com.google.android.apps.maps/. If you played the Cellebrite CTF this year you will also know that it can also exist in USERDATA/user/PROFILE_NUMBER/com.google.android.apps.maps/. The folder has the expected layout, with a few extras.
Some of these non-standard folders may be familiar. Specifically, app_tts-cache and app_tts-temp. Both of these folders contain audio files that are related to turn-by-turn directions given by Google Assistant during navigation. Kibaffo33 wrote a great blog post about these files, which you can find here, so I am not going to cover them in this post. Please read his post. These files can be handy when you need to put a phone in a location, or you need to map a phone’s movement in a specific time frame.
Users can save locations in Google Maps. There are five default categories: Favorites, Starred Places, Labeled, Want to go, and Travel plans. See Figure 2.
Users can add custom categories as well. In Figure 2, the category “Awesome Places” was created by me. One of the files that stores information about saved locations is gmm_sync.db, and it is found in the /databases folder. The database is not pleasant to deal with manually, but, fortunately, most forensic tools can parse it for you. It can be, however, painstakingly examined if needed. The table of interest is sync_item_data. See Figure 3.
Saved locations can be placed in one of the default categories above, or can be added to a custom category created by the user. Each category is assigned a random identifier, which is then appended to a location’s record within gmm_sync.db. The column item_proto is used to associate the random identifier with the friendly name. See Figure 4 for the friendly name (red box) and random identifier (blue box).
Once the random identifier has been found for a particular category, an examiner can find the location(s) in that category by examining the string_index column for that value, and examining the latitude_e6, longitude_e6, and item_proto columns for the location(s). Figure 5 hightlights the category identifier (blue box) and location (red box). Figure 6 shows the location in the Favorites category with Google Maps.
If you noticed I have not mentioned anything about the timestamps in the timestamp column. I have found that the timestamps can be inconsistent. Doing something as simple as sharing a category (versus keeping it private – the default) will alter the timestamp for everything in a category, so it can be difficult determining when an item was placed in a list.
Categories created by users look slightly different. See Figures 7 and 8.
Users can add a description to a custom category, which is highlighted in the green box in Figures 7 & 8. The friendly name is seen in the red box in both figures, as well. The random identifier is slightly different. In Figure 8 the identifer is seen, but it is not seen the string_index column in Figure 7. Instead it is a Unix epoch timestamp with a string of trailing digits. However, the same logic applies. Taking the value from the string_index column will find all entries within that category. See Figures 9 and 10.
Figure 11 shows how this entry would look to a user.
Users can add labels to locations. For example, if a user wanted to label a location as their home (one of the pre-defined options) they can do so. I set a location for Home and Work. See Figure 12.
The file gmm_myplaces.db contains the information related to labeled locations. See Figure 13.
Figure 13 is a view of the sync_item table in gmm_myplaces.db. The table only contained two entries, Home and Work, so I have overlaid Mushy on top to render the contents (protobuf) of the sync_item column. Everything highlighted in red boxes in Figure 13 is the location I labeled as “Home.” I have redacted portions of it as it represents a location close to my actual house, but just know that the street address along with the latitude, longitude, and a Google Maps URL are available. The areas highlighted in the blue boxes represent when I labled those locations.
The green box is interesting. The key_string value for “Home” is 0:0, which is the cartesianal coordinate for “origin” (I see what you did there, Google). Work is 1:0. While I did not label anything else, I am sure there are other values here.
The next file, also in the /database folder, is gmm_storage.db. This file is also a pain to deal with in that there is a ton of BLOB data in it. The lone table of interest is gmm_storage_table (Figure 14).
The table has a lot of repeating information that can be found elsewhere in the previously discussed files. An example is seen in Figure 15. Note the highlighted values in the blue box align with that seen in sting_index column in Figure 9.
The BLOBs in the _data column in Figure 14 are serialized java, but it also look protobuf-ish. Additionally, there were BLOBs within the serialized Java that I was unable to decode further, likely because the were also serialized Java. The contents in this table can also be slightly deceptive. As an example, I searched for “Sheetz” during testing (a regional gas station and MTO food joint) and there were multiple entries in the table for Sheetz’s at different locations, none of which I visited. So, examiners should be wary about the contents of this database.
Needless to say, gmm_storage.db can be an absolute headache to deal with. But, there is hope.
A lot of times examiners can be so focused on databases that they (myself included) some times neglect other file types. It is easy to get blinders, but to do so is deterimental. The /files folder in Google Maps contains some extremely valueable data.
The first file is one that was covered by Cellebrite’s Jean-Philippe Noat and Ian Whiffin earlier this year in a webinar. The file is new_recent_history_cache.cs, and while it has a .cs extention, the file contains protobuf. During testing I found that the forensic tools I had access to did not recognize this file as protobuf, but some would partially parse it. So, I exported a copy out, removed bytes up to the first hex 0x0A value I encountered, and saved the new copy. That triggered Ian Whiffin’s Mushy tool. See Figure 16.
This file contains Google Maps search history for the signed in account. An examiner can find searches and timestamps of the when the searches occurred in this file. Additionally, this file contains Google Maps searches from other devices on which the Google account was signed in (i.e., sync’d devices) along with a timestamp for when those searches occurred. You can see the search for “Sheetz” at the top of Figure 16 (red box) and a Unix Epoch timestamp just above it (blue box) which is when I conducted the search. There is no exact location associated with that search since the search returned multiple results. If a search had an address that was returned or a set of GPS coordinates, though, it would look different. Figures 17 and 18 are a great examples.
The color coding in both figures is the same. In the blue box is the Unix Epoch timestamp for when the search occurred. In the red box is the street address of the search. The main difference between the two entries is that in Figure 18 there is no explicitly displayed latitude and longitude like there is in Figure 17. Note that the location seen in Figure 18 is one that I searched on a PC in which the account was also logged in. The format is not indicative of the search happening on the PC, but is shown here as an example of how searches are sync’d across devices. For those of you that played the Cellebrite CTF this year, the location in Figure 18 should be familar. 🙂
To see how this all aligns with what the user sees, see Figures 19, 20, and 21.
The file continues past here showing everything that is seen in Figure 19 and then some. This file is great. Keep in mind, however, it only shows searches. Just because a location appears in this file does not mean the phone actually visited that location.
There is another file an examiner can look at to see the location to which the phone last navigated. The file is also in the /files directory and is named saved_directions.data.cs. See Figure 22.
This file will contain two (2) or sometimes three (3) locations depending on the navigation scenario. The latitude and longitude values highlighted in the blue box represent where the phone is located when directions are obtained to a location. The data highlighted in the red box is the intended destination. Here I was at a local pizza restaurant, Michaelangelo’s, and needed directions to New Hope Valley Railway to board a haunted train for Halloween. I searched in Google Maps for New Hope Valley Railway while I was in front of Michaelangelo’s and got directions to the railway. Figure 23 shows how it appeared to me in the Google Maps UI, and Figure 24 is a close up of the starting point.
I do want to stress that the coordinates in blue in Figure 22 are where the phone is located when directions are obtained (the starting point). If I obtain a set of directions, start driving along the route, and then hit “Start” to start the turn-by-turn navigation, the coordinates in the blue box would not change.
The bottom of saved_directions.data.cs has additional data. See Figure 25.
The end of the navigation is seen in Figure 26.
In Figure 25 you can see the time navigation started (green box), the time navigation ended (red box) and where the phone was located when navigation ended. In this scenario the file contained two locations: starting location and ending location with the ending location being the intended destination. Having this information in addition to the information at the top of the file puts the phone in two locations at specific times, which can be valuable to examiners and investigators.
If a user stops navigation prior to arriving at the intended destination, those coordinates are also captured in this file. See Figure 27.
Above, I started navigating to Kohl’s (a department store) in Apex, NC from the Holly Springs Cultural Arts Center. When I was approximately five (5) minutes away from arriving at Kohl’s I stopped the navigation session in Google Maps. The bottom of saved_directions.data.cs is seen in Figure 28.
The same elements are here: start time (green), stop time (red) and ending location (blue). However, the blue box shows where the phone was located when navigation ended. See Figure 29.
In this scenario saved_directions.data.cs had three (3) locations: starting location, intended destination (upper left circle in FIgure 29), and location of where navigation prematurely stopped (lower right circle in Figure 29). Again, this can be extremely beneficial to examiners and investigators. Unfortunately, there is not a file that contains navigation history in this fashion. Each time navigation is initiated, the file’s previous contents are overwritten in lieu of the new navigation session. Also, there is another blob of serialized Java/protobuf data in the middle of this file that I was not able to successfully render.
There is a third file that may be present in /files that examiners will find useful. I say may because a user needs to use Google Maps in Android Auto in order for this file to appear. If it is not present, Google Maps has not been used in that venue. The file is new_recent_history_cache_navigated.cs, and it contains information about locations to which the phone has at least started navigation to using Google Maps via Anrdoid Auto. See Figures 30 and 31.
This file has two important pieces of information. First, the timestamp at which navigation started in Google Maps via Android Auto (blue boxes), and, second, the location being navigated to; however, I will note that just because the location appears here does not mean the phone made it to the location. Again, it just means the phone started navigating to that location.
Generally speaking, I found that searching in Google Maps via the Android Auto interface to be inconsistent. Some searches that were done via Android Auto did not appear in new_recent_history_cache.cs, and other times the searches did appear. So, while Android Auto actions are captured to some degree, examiners should take care to scrutinize the data to ensure that it makes sense and that nothing is missing.
The last file of interest in /files is offline_saved_directions.cs. This file contains the same data as saved_directions.cs, which was discussed earlier.
Heading Home (For Now)
Considering how hard location data is hard to come by in Android, any little bit can help. Google Maps can provide some insight into where a phone was, and when. And even though it is a small amount, every little bit can help.
That is it for now. Part 2 will cover Google Maps on iOS.