Finding Phones With Google Maps Part 1 (Android)

Lost. But not.

Note: there is an important update to this article. Please see the appended portion.

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.

Starting Navigation

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.

Figure 1. Google Maps folder.

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.

Figure 2. Saved location categories.

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.

Figure 3. sync_item_data.

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).

Figure 4. Friendly name and random identifier.

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.

Figure 5. Associated the category with the location.
Figure 6. Favorites.

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.

Figure 7. Custom location entry.
Figure 8. Custom category item_proto blob.

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 9. An entry from a custom saved category.
Figure 10. Custom save category item_proto value.

Figure 11 shows how this entry would look to a user.

Figure 11. User-created saved location category.

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.

Figure 12. My (Labeled) Places.

The file gmm_myplaces.db contains the information related to labeled locations. See Figure 13.

Figure 13. sync_item table from gmm_myplaces.db

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).

Figure 14. gmm_storage_table.

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.

Figure 15. Custom save category in gmm_storage_table.

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.

Files

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.

Figure 16. Mushy output for new_recent_history_cache_search.cs.

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.

Figure 17. A format of a search in new_recent_history_cache_search.cs
Figure 18. Another format from the same file.

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.

Figure 19. Google Maps search history in the Maps UI.
Figure 20. Search history from new_recent_history_cache_search.cs (Part 1).
Figure 21. Search history from new_recent_history_cache_search.cs (Part 2).

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.

Figure 22. Top of saved_directions.data.cs.

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.

Figure 23. Directions obtained.
Figure 24. Close up of location where directions were obtained.

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.

Figure 25. Start/Stop times and ending location.

The end of the navigation is seen in Figure 26.

Figure 26. End of navigation.

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.

Figure 27. Navigating to Kohl’s in Apex, NC.

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.

Figure 28. Stopped early.

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.

Figure 29. Location of phone compared to the intended destination after stopping navigation early.

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.

Figure 30. Top of new_recent_history_cache_navigated.cs.
Figure 31. Next entry in the same file.

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.

An Update (2025-03-29)

Digital forensics is constantly changing, and as practitioners, the responsibility is ours to make sure we stay up to date. App behaviors change which give rise to changed artifacts, new artifacts, and new edge-cases. This is the nature of our discipline. My employer recently received a question that, upon research, led to the discovery of changes in Google Maps on Android, and, quite possibly, a missed edge-case by yours truly. These changes are significant enough that appending this blog post was the only option.

I’d like give a huge acknowledgment to my colleague Ian Whiffin (Thank you, sir!) for his testing, too. It was a team effort.

What’s Different

The changes discussed below relate to the file saved_directions.data.cs. In the original post, this file was described as storing information related to the last navigation session that was not done via Android Auto, and this part remains true. It is the content of this file where the change lies, and it depends on the behavior of the user and when certain actions take place.

For testing, I used my Pixel 5a, running Android 15, and Google Maps version 25.12.01.737373685. During each navigation session saved_directions.data.cs was pulled multiple times from the phone, usually coinciding with a change in the navigation session, either by me or by the phone.

To recap, see Figure 32.

Figure 32. Beginning of saved_directions.data.cs.

The area in the red box in Figure 32 is where the phone was when I fetched the directions, and the item in the blue box is the intended destination. I was stationary when I fetched the directions seen here. Figure 33 shows the start of the navigation session. The blue dot is where my car was (red box), and the grey dot (green box) is where Google Maps wanted me to start the route. Those two locations are approximate, but far enough that Google Maps made the distinction.

Figure 33. Google Maps. On the phone.

Figure 34 shows how the red and green boxes plotted in Maps online.

Figure 34. Plotted GPS coordinates.

The “new thing” (or the thing I originally missed) in saved_directions.data.cs is seen in Figure 35 below. Highlighted in the green box, there is a key value “Your Location” that has an accompanying set of GPS coordinates. Testing has shown that this value typically (more on that in a moment) aligns with the coordinates at the beginning of the file. In Figure 33, Maps wanted me to go to the start of the navigation route (green box), and that location is logged as Your Location in saved_directions.data.cs. While this set of coordinates are not exact, they are approximately 13.95 meters (45.78 feet) of where I was when I fetched the directions. Again, not exact, but approximate.

Figure 35. Your Location in saved_directions.data.cs.

Your Location is finicky, to say the least, but not completely unpredictable. To illustrate, see Figure 36. This is the same navigation session as seen in Figure 32. During this session, I diverted from the route once by taking a premature left turn prior to reaching my intended destination.

Figure 36. saved_direction.data.cs after diverting from the route.

This is the beginning of saved_directions.data.cs from the same session as before, and it is completely different. The coordinates where I originally fetched the directions were gone. Further, the intended destination had moved to the very beginning of the file, and the coordinates associated with Your Location had changed and were at the beginning of the file, which is seen in Figure 37.

Figure 37. Same session. Different Your Location coordinates.

Figure 38 shows Google Maps right after I took the left turn. The Your Location coordinates match what was seen in the Google Maps UI. It had recalculated the route based on the diversion, and updated Your Location as the “new” starting point. Notice that the grey dot seen in the green box in Figure 33 has reappeared here (also in a green box in Figure 38).

Figure 38. Just after the left turn and Maps recalculation.

Overall, the structure of saved_directions.data.cs was in complete disarray. In addition to the change at the beginning of the file, the end of the file did not have the start/end timestamp of the navigation session, as seen in Figure 39. It simply had the ending location, which is where I came to a stop after the premature left turn. Keep in mind that I was testing, and that this set of coordinates could be different from Your Location depending on where the user ended the navigation session and where the last recalculation occurred. To find the start and end times of the navigation session, I had to scroll approximately three quarters of the way through the file to find them (Figure 40 for the end time, Figure 41 for the start time).

Figure 39. he end of saved_directions.data.cs.
Figure 40. The end of the navigations session.
Figure 41. The start of the navigation session.

To confirm this finding, I reran the test again. Figure 42 shows the route calculation in the Maps UI. Figure 43 shows the coordinates in saved_directions.data.cs, and Figure 44 shows those coordinates on a map.

Figure 42. Fetched route in Maps.
Figure 43. Coordinates from saved_directions.data.cs.
Figure 44. Mapped coordinates.

The coordinates in Figure 43 are approximate to those in the Your Location value. Figure 45 shows Your Location in saved_directions.data.cs, and Figure 46 shows those coordinates on a map. You’d be forgiven if you think Figures 44 and 46 are the same picture, but they are not.

Figure 45. our Location coordinates.
Figure 46. Your Location coordinates on a map.

The coordinates are approximate enough that one cannot see a difference when plotting the coordinates, but again, not exact. Once I started the trip I followed the navigation for a while and, just as before, made a premature left turn prior to reaching the intended destination. See Figure 47.

Figure 47. Turning before the intended destination.

Just as was seen in Figure 38, the grey dot had moved in the Google Maps UI (green box in Figure 47).

Inspecting saved_directions.data.cs finds similar calamity as before. The original coordinates at the beginning of the file are gone, the intended destination is at the very beginning of the file, and Your Location has not only changed but has also moved towards the beginning of the file. One additional change is that the start and end times of the session were not at the end of the file; there a little over three quarters of the way through the file, but were closer together than before. See Figures 48 and 49 for the beginning of the file and the start/end times, respectively.

Figure 48. Beginning of saved_directions.data.cs.
Figure 49. Start (bottom) and end (top) times of navigation session.

The next test involved fetching a set of directions, traveling a little along the route, and then starting the navigation session. The was a previous test in the original blog post and it held true in this test as long as I did not travel too far along the suggested route: the top set of coordinates remained. Figure 50 shows fetching the directions in Google Maps.

Figure 50. Stationary when getting the directions.

Note that my location and the grey dot are approximately in the same location. I then moved approximately 37.14 meters (approximately 121.84 feet). See Figure 51.

Figure 51. Moved from the original location. Still on the route.

I sat for just a moment, and then started the navigation session. Note that there is a distinct difference between where I fetched the directions and where I started the session. See Figure 52.

Figure 52. I moved. A little.

Examining saved_directions.data.cs finds the file as the original testing did. The location at which I fetched the directions was at the beginning of the file. Figures 53 and 54 show the results.

Figure 53. The fetching location is at the beginning.
Figure 54. Mapped coordinates from Figure 53.

The Your Location coordinates were also where I fetched the directions; they were the exact same set of coordinates as seen in Figure 53. See Figure 55.

Figure 55. Your Location coordinates.

I ran the test again, but this time I drove a little further along the route. While I was driving (slowly) I was watching the Google Maps UI. Figure 56 shows the location at which I fetched the directions.

Figure 56. Fetching directions. Again.

As with the previous test, I drove a short distance along the calculated route and the phone did nothing beyond advancing the blue dot. Eventually, I drove far enough where the blue dot turned into a blue triangle. See Figure 57.

Figure 57. What is happening?

I stopped for a minute and then started the navigation session, and immediately pulled saved_directions.data.cs. Figure 58 shows the beginning of the file.

Figure 58. Where is the destination?

The beginning of the file looks completely different. Here, the destination is missing, and the Your Location reflect where I actually started the navigation session (Figure 59), not where I had originally fetched the directions.

Figure 59. New Your Location. Plotted.

The intended destination had moved farther into saved_directions.data.cs. See Figure 60.

Figure 60. Intended destination moved.

Also note that the grey dot had remained in the original location (green box – Figure 61), but its coordinates were not seen in saved_directions.data.cs. See Figure 61.

Figure 61. The dot is there, but not.

Once I started the navigation session, I followed the route for a bit and then made a left turn off of the route (green box in Figure 62). As expected, Google Maps recalculated the route. See Figure 62.

Figure 62. Another premature left turn.

I pulled saved_directions.data.cs once again. The results were interesting. See Figure 63.

Figure 63. Back to normal. Sorta.

Figure 63 shows the beginning of the file. The coordinates in the red box are the same as those seen in Figure 58 (Your Location). The intended destination is also back to where it was expected within saved_directions.data.cs. Your Location, however, had changed. See Figure 64.

Figure 64. Your Location. Changed.

As was seen previously, Your Location updated to reflect where I had diverged from the route (green box in Figure 62). Figure 65 shows the plotted coordinates.

Figure 65. Your Location plotted.

Arriving. Again.

saved_directions.data.cs has several nuances, which can cause it to not look as it did in my original testing. Whether that is a result of some changes to Google Maps or behavior I missed in my first batch of research is yet to be seen. Regardless, the extra information about the nuances of this file can help explain why it does not look as neat as it did originally.

We practitioners are in a constant state of learning; our discipline requires it.

7 thoughts on “Finding Phones With Google Maps Part 1 (Android)

  1. Thanks for this blogpost. When could we expect part 2 in regards to Google Maps on iOS? 🙂

Leave a Reply