They are Still Together!: iOS Unified Logs II
A more detailed look at the structure and layout of iOS Unified Logs with a comparison to other areas of data logging storage.
Hey Internet, welcome back to the Forensics with Matt newsletter and welcome back to the iOS Unified Logs series. In today’s post, I am going to discuss the thing I mentioned at the end of last post: a greater detail on the database of the iOS Unified Logs.
In today’s post, I want to mention several things in a similar manner to the last one. I will mention how data looks in areas like the knowledgeC.db database and the SEGB files in the Biome before I mention the Unified Logs. Let’s get on into it.
Data in the Typical Areas
When we look at the typical areas of the device that will contain the same data we look for in the Unified Logs, we will have to use areas like the Biome and knowledgeC.db database to find this information. With the amount of information that these areas store, it may take a great deal of time to parse them by hand. Regardless of. the time it takes, it is still a fact that they contain a wealth of useful data.
On Thursday, 26 June 2025, I generated almost two hours of data points on my test iPhone. This test data consisted of several hours playing podcasts, some time playing music through a world radio tuner app called Radio Garden, and several games (Candy Crush, and a few others not worth naming) that I randomly downloaded through the App Store. With all of these apps and processes noted, I decided to look at how they were represented in two places first. These two places were the Biome’s Now Playing log and the knowledgeC.db Database.
First off, looking in the knowledgeC.db file was not efficient in finding the data I wanted. I had to cross-reference multiple tables to find anything useful. For example, to find the data I wanted to from Radio Garden, I had to cross-reference at least two tables in the database. Those two tables were the ZSTRUCTUREDMETADATA
table and the ZOBJECT
table. There are more columns in the former table thn the latter. In the ZSTRUCTUREDMETADATA
table most of the columns were also filled with NULL data as well. As shown in Figure 1, there are a couple of important columns that show the current state of the radio station on Radio Garden: The Z_DKNOWPLAYINGMETADATAKEY_ARTIST
and the Z_DKNOWPLAYINGMETADATAKEY_TITLE
showed evicence of what stations I had been on.
Figure 1a: a screenshot of Radio Garden
Figure 1b: Radio station information from Radio Garden
Figure 1: Radio Garden: front end vs back end view.
As you may have noticed, these two fields don’t look entirely correct for the information they hold. I will take bets for the reasons why the Radio Garden app lists its data in the metadata → Now Playing
like this. I presume because it’s supposed to be music but it’s not entirely music in the traditional ssense. Even then, it should look more like a real album. I would have expected the song data to look more like:
SONG - ARTIST - ALBUM
RADIO STATION
ASSOCIATED WITH RADIO GARDEN.
The developers could easily have listed it like that, but they chose to do it differently. What’s even crazier is what I see in some of the fields.
You might have noticed the Arabic in some of the fields. You might not know what it is or even be sure how to type it. Fortunately, I can copy it directly and translate it for you. In one field, the text, محمد حماقي - ما بلاش,
represents the song that was playing at the time. It is the song “Let’s Not” (maa balaash) by Muhammad Hamaafi. Out of all of the data in this part of the knowledgeC.db, there is no way to cross reference with other areas of the knowledgeC.db to know exactly which metadata piece corresponds to each time.
On that note, I’d like to briefly touch on the main table of interest from knowledgeC.db: the ZOBJECT
table.This lists out all of the activities in a certain area of time and what processes they belong to. Each process call is listed with a start time and an end time that is written in the Apple time format. This is Unix time since January 1, 2001 UTC. This table also lists out identifiers for the package (UUID and others). The most important ones of all are the package name (ZVALUESTRING
) and the Activity Type (ZSTREAMNAME
). These two pieces of information, together can be put together with the start date and end date to have a basic idea of what’s being done at a certain time. You can see what I mean in figure 2.
Figure 2: Now Playing data and when data was being played.
Podcasts showed similar to what you see on figure 2, but had some major differences on the ZSTRUCTUREDMETADATA
table. As you’ll see in Figure 3, the podcasts tended to sperad their information out across the TITLE
, ALBUM
and ARTIST
columns. This is strange, also, because the ALBUM column often held the date, as is also apparent in Figure 3.
Figure 3: Podcasts in KnowledegC.db ZSTRUCTUREDMETADATA
table.
I’d like to touch on the Now Playing SEGB entries very briefly. You’ll be able to see the Now Playing Biome SEGB files that I found in the directory /var/mobile/Library/Biome/streams/public/NowPlaying/local
. Your file that holds the “Now Playing” will most likely show different numbers as its title, but it will hold similar records to the one I will show. The Biome “Now Playing” entries are much like a combination of the two KnowledgeC tables that I mentioned above. This is because they show some, but not all of the relevant information of a certain point in time. See Figure 4 to see what I mean.
Figure 4: Example of Biome “Now Playing” entries.
ou’ll see from figure 4 that the most important thing a single entry has is the title of what’s playing. It also mentions what is playing the media. In our case, the media is played from the speakers. Then it lists the package the media originates from. The very end of the entry lists what looks to be a timestamp this entry was played at. These timestamps seem to be inaccurate from what I am seeing. There is a chance they are not timestamps.
Data in Unified Logs
When I looked for data form the podcasts and Radio Garden apps, I was surprised how much noise was generated by subprocesses and how everything was logged when I looked for Radio Garden in the logs. When I was processing the logs and looking for Radio Garden, I was surprised to see the thousands of entries that were there just for one day. There were over 33000 for just one day!
Figure 5: The entries recorded on 2025-06-24 for Radio Garden.
When it comes to the things that composed the above over 33000 were over 1000 connections, 19 Application messages, almost 24000 Process workings, 2 Injections, 33 “Common” events, 4 times my volume slider was pressed, 128 events from the haptics engine, 24 ScrollView events, 378 BoringSSL events, 417 hcln haptics events, 117 quic events, 32 events from the radiogarden process, 81 xpc events, 20 rr events, 1 secitemratelimit events, 90 monitor events, 505 feedback events, 2425 EventDispatch events, 597 BackgroundTask events, 45 client events, 88 events related to the keyboard, and the rest of the events were of assorted processes related to other things. The most interesting thing about the way that the Radio Garden logs was that I found the messages on the Unified Logs to be more useless than anything. As opposed to the knowledgeC.db and Biome logs, the Unified Logs had less useful information. Whereas the “Now Playing” Biome logs and the ZOBJECT
and ZSTRUCTUREDMETADATA
sections of knowledgeC.db had distinct and explicit mention of what was playing and whenit was playing, I saw non. of this on Unified Logs, again, this was more of system process-level messaging than actual application logging its activity somewhere.
One such message type that I saw quite a bit was “0xca9000c10 - [PID=1452] WebProcessProxy::didChangeThrottleState(Foreground) Taking foreground assertion for network process
”. It looks more like something I’d see from a coding environment than the app logging its own activities to a log. All other messages were similar to this one in that they generally had some sort of activity code and desctiption of what was done.
When it came to the Podcasts app, there were more activities that happened in the date range I selected. In the selected date’s time range. In total, there was one less than 50000 events generated on this date. The events consisted of the same event types that were found above, with the addition of a “Downloads” event type. This event type is likely to be related to the system checking both whether downloads are in progress or being started, or downloads for a certain podcast that is newly subscribed to is being started.
One major difference between the logs from the Radio Garden app and the Podcasts app is some of the direct references to the files the app creates. For instance, the following string appears several times in the logs between 11:00 and 11:15 on the above date: Ignoring Media Library asset url ipod-library://item/item.mp3?id=4230982856921701404. ‘Keep using podcasts asset url file:///private/var/mobile/Media/Podcasts/6D9F999C-336F-48AD-B733-735A6BAA8D41.mp3
’. It is really interesting that this happens for the Podcasts app and not Radio Garden. I would expect there to be something there greater and related to the URL of the stream of a certain radio station that was being connected to and later on being played and the generated traffic going to the servers from the device and vice-versa.
I also saw several events under the “metrics” category. They have some form of the following ‘AMSMetricsFigaroEventModifier: [807F2B9F] Fetching experiment data
’, ‘Record event - <private>
’, ‘Assertion for background task was invalidated by system, reason: { Error domain=RBSAssertionErrorDomain, code=1’, Updating identifiers for analytics
’, ‘Could not acquire assertion for background task, reason: { Error domain=RBSAssertionErrorDomain, code=1’
and ‘Building JSStack took 0.1424352080002791 seconds
’ among others. These metrics events seem to be events that track playback events and the time that the podcasts are being played. There are also playback events which go hand-in-hand with the ‘Now Playing’ and ‘player’ events. These events show us data about how the app plays the podcast and how it composes the player and how it tracks battery usage and how the system manages system resources.
In the end of analyzing all of these events, I can say two things: there were many events, dozens of thousands of events, and that many (if not all) of the events recorded on the Unified Logs have a sense of vagueness to them. This vagueness comes from the fact that events generally don’t contain human-understandable information that we can view. I much prefer the logging found in the knowledgeC.db and Biome logs because they have such well documented data about what’s playing and what the system is doing in a WAY more human-readable way.
Conclusion
In conclusion, in this first analysis of the iOS Unified Logs, I compared the presentation of the Unified Logs to a couple elements of iOS data that I was more familiar with: the SEGB files and the knoeledgeC.db database. I found some key differences beteeen them, among which I noticed that their presentations gave varying amounts of information, some way less useful than others. I also saw that the Unified Logs gave almost everything that the device was doing in a certain block of time. The way Unified Logs log the information is more akin to how a computer logs processes working and not working, rather than how the previously mentioned knowledgeC.db and Biome logs function. My logs contained a total of millions of events. If you pull these types of logs from your device, ensure that you are very specific on the amount of time you choose to search from because you will also have millions of events.
With that all being said, I think it would be worth doing a future post about Biome logs on various iOS images to see differences in logging and what apps are logged in which files. In the meantime before that post, this has been Matthew from Forensics with Matt talking about different types of iOS logs. Until next time, Matt OUT1