數字取證分析人員在分析macOS時,很難獲得關于程序執行的相關信息,但現在情況已有所改觀。在macOS 10.13(High Sierra)中,Apple推出了CoreAnalytics,這是一種系統診斷機制,可以獲取系統上執行過的Mach-O程序記錄,時間跨度大約為1個月左右。CoreAnalytics可以為內部威脅調查任務以及應急事件響應提供許多非常有價值的信息,可以用于以下場景:
1、確定系統的使用時長,粒度以天為單位;
2、確定特定日期有哪些程序被運行過,是以前臺還是以后臺模式運行;
3、大致確定程序處于運行或活動狀態的時長,也能大致給出程序啟動或者以交互式前臺方式運行的次數。
本文從技術角度大致介紹并分析了macOS 10.13中的CoreAnalytics機制,同時也介紹了如何將這類信息解析為更容易理解的格式,幫助調查人員分析取證。
CoreAnalytics可以提供關于程序執行的歷史紀錄以及當前記錄,基本上以天為單位。這些數據來自于兩個源:
1、/Library/Logs/DiagnosticReports/
目錄中以.core_analytics
為擴展名的文件,內容為JSON格式:解析前兩條記錄可以獲得有關診斷過程的啟動及結束時間戳信息,解析后面的數據可以獲得診斷期間系統及應用的使用情況;
2、/private/var/db/analyticsd/aggregates/
目錄中文件名類似GUID的文件,內容為嵌套數組:在當前診斷過程期間,子系統將臨時階段性程序執行數據以聚合文件形式報告給數據分析守護程序。階段性數據通常會在診斷周期結束時推送到.core_analytics
文件中。
診斷周期由.core_analytics
文件的前兩行定義,分別確定診斷周期的開始及結束時間。每個診斷周期在在00:00:00 UTC后的系統首次休眠或者關閉時就會結束。前面提到過,在診斷周期結束時,當日的數據在提交到.core_analytics
文件用作長期存儲前,會先存放在聚合文件中。因此,CoreAnalytics無法用來確定程序運行的時間范圍(只能大約給出24小時的時間區域)。
為了處理這種場景,我們編寫了一個Python腳本(請訪問我們的GitHub下載),該腳本可以解析CoreAnalytics以及聚合文件,將結果寫入到更加清晰的JSON或者CSV文件中。CoreAnalyticsParser腳本可以支持如下功能:
1、解析每個.core_analytics
文件中記錄的診斷周期開始及結束時間,并將其轉換為UTC以及IOS8601時間;
2、從每個.core_analytics
文件中提取與每條記錄相關的可用字段;
3、將以秒數表示的原始值轉換為更容易理解的%H:%M:%S
strftime
格式;
4、將與comappleosanalyticsappUsage
子系統關聯的聚合文件解析為每個 .core_analytics
文件中該子系統所生成的相同字段。
在.core_analytics
文件中某個應用的執行記錄大致如下所示:
{ ‘message’: { ‘activations’: 105,
‘activeTime’: 4250,
‘activityPeriods’: 12,
‘appDescription’: ‘com.google.Chrome ||| 67.0.3396.87 (3396.87)’,
‘foreground’: ‘YES’,
‘idleTimeouts’: 4,
‘launches’: 0,
‘powerTime’: 12537,
‘processName’: ‘Google Chrome’,
‘uptime’: 26110},
‘name’: ‘comappleosanalyticsappUsage’,
‘uuid’: ‘4d7c9e4a-8c8c-4971-bce3-09d38d078849’}
表1. Google Chrome對應的CoreAnalytics記錄樣例
由CoreAnalyticsParser解析后,同一個記錄會被解析成如下結果:
{ ‘src_report’: ‘/path/to/Analytics_2018-06-29-173717_ML-C02PA037R9QZ.core_analytics’,
‘diag_start’: ‘2018-06-29T00:00:09Z’,
‘diag_end’: ‘2018-06-30T00:37:17.660000Z’,
‘name’: ‘comappleosanalyticsappUsage’,
‘uuid’: ‘4d7c9e4a-8c8c-4971-bce3-09d38d078849’,
‘processName’: ‘Google Chrome’,
‘appDescription’: ‘com.google.Chrome ||| 67.0.3396.87 (3396.87)’,
‘appName’: ‘com.google.Chrome’,
‘appVersion’: ‘67.0.3396.87 (3396.87)’,
‘foreground’: ‘YES’,
‘uptime’: ‘26110’,
‘uptime_parsed’: ‘7:15:10’,
‘powerTime’: ‘12537’,
‘powerTime_parsed’: ‘3:28:57’,
‘activeTime’: ‘4250’,
‘activeTime_parsed’: ‘1:10:50’,
‘activations’: ‘105’,
‘launches’: ‘0’,
‘activityPeriods’: ’12’,
‘idleTimeouts’: ‘4’}
表2. CoreAnalyticsParser腳本將圖1中CoreAnalytics的結果解析成JSON數據
注意:如上解析結果為JSON格式數據,可以使用-j
選項輸出為JSON數據。默認情況下,解析腳本會將結果輸出為CSV格式。
該腳本可以在實時系統上運行,也可以處理包含CoreAnalytics或者聚合文件的目錄。
.core_analytics
文件中包含JSON記錄,這些記錄可以表示程序執行歷史及時間戳信息,時間戳可以劃出歷史數據所對應的特定診斷周期。這些文件位于/Library/Logs/DiagnosticReports/
目錄中,文件名采用Analytics_YYYY_MM_DD_HHMMSS_<systemname>.core_analytics
格式。文件名中的時間戳基于的是系統的本地時間信息。在10.13版本之前,DiagnosticReports
目錄只包含程序故障及崩潰報告,現在,不論程序是否崩潰,該目錄中都會包含與程序執行有關的數據。
負責生成和收集系統分析及診斷數據的守護程序同樣會維護/private/var/db/analyticsd
目錄中已預先寫好的CoreAnalytics文件信息。在該目錄中,currentConfiguration.json
文件貌似維護著一個字典集,對應與子系統相匹配的名稱、UUID以及數據類型。
在/private/var/db/analyticsd/journals
目錄中,da2-identity.json
文件包含最近生成的CoreAnalytics文件中的_marker
記錄列表。第一條記錄通常會比當前可用的第一個CoreAnalytics文件要早上7-10天,最后一條記錄對應最近寫入后的報告。通常情況下,這些數據可以用來確認預期的所有.core_analytics
文件都存在且未被篡改。
定義診斷周期
.core_analytics
文件的首條記錄包含一個時間戳字段,字段值對應診斷周期結束的時間。雖然時間戳以本地時間為基礎,但帶有時區信息。如果該字段值未被修改,則應當匹配該文件的上次修改時間戳。換句話說,只有在診斷周期結束后,.core_analytics
文件才會被寫入到這個目錄中。
{ ‘bug_type’: ‘211’,
‘os_version’: ‘Mac OS X 10.13.5 (17F77)’,
‘timestamp’: ‘2018-06-05 17:16:48.19 -0700’}
表3. .core_analytics
文件的第一行記錄,包含診斷周期結束時間戳信息
我們可以在以_marker
開頭的JSON記錄中找到診斷周期的開始時間,即startTimestamp
字段中的UTC時間戳。
{ ‘_marker’: ”,
‘_preferredUserInterfaceLanguage’: ‘en’,
‘_userInterfaceLanguage’: ‘en’,
‘_userSetRegionFormat’: ‘US’,
‘startTimestamp’: ‘2018-06-05T00:19:13Z’,
‘version’: ‘1.0’}
表4. .core_analytics
文件的第二行記錄,包含診斷周期開始時間戳信息
CoreAnalytics文件基本上每天都會寫入到DiagnosticReports
目錄中,并且在系統使用期間,兩個記錄文件的時間間隔基本上無縫連接。在診斷期間,如果系統處于睡眠或者關機狀態,則不會生成CoreAnalytics文件。
診斷周期開始時間 | 診斷周期結束時間 |
---|---|
2018-06-08T01:51:23Z | 2018-06-09T01:50:01.370000Z |
2018-06-10T16:49:09Z | 2018-06-11T03:53:15.140000Z |
2018-06-11T03:53:14Z | 2018-06-12T02:50:17.410000Z |
2018-06-12T02:50:17Z | 2018-06-13T00:17:45.870000Z |
2018-06-13T00:17:45Z | 2018-06-14T01:17:06.340000Z |
表5. 系統連續使用幾天時,.core_analytics
文件之間無縫連接,當系統未激活時則會出現斷檔
根據我們對/private/var/db/analyticsd/Library/Preferences/analyticsd.plist
這個二進制plist文件的分析結果,這些文件通常會在每天00:00:00 UTC時間后系統首次睡眠或關閉時在DiagnosticReports
目錄中生成。該plist文件以Unix Epoch格式記錄了.core_analytics
的上次提交時間以及下次提交時間。
Key: cadence
Type: String
Value:
{ ‘bootToken’: 1530574585000000,
‘lastSubmission’: 1531256233,
‘nextSubmission’: 1531267200,
‘osVersion’: ’17E202′,
‘version’: 1}
表6. analyticsd.plist
文件內容,包含上次提交及下次提交時間戳信息
然而我們的測試顯示,報告通常會在提交時間過后的首次睡眠或者關機時寫入。
系統使用信息
在時間戳及marker記錄之后,comappleosanalyticssystemUsage
子系統所生成的數據反映了系統的運行時長(以秒為單位)。該子系統可能會在主機睡眠或關閉后生成新的紀錄。將這些記錄中的uptime
字段值加起來后就可以得到系統處于活躍狀態下的總時間。Uptime
字段非常簡單,為uptime
值的千位數。activeTime
字段很有可能表示的是系統運行狀態下被使用的時長(以秒為單位),如下兩條記錄所示,系統有兩個階段處于喚醒狀態下(時長分別為4分鐘以及40分鐘),總時長為44分38秒,但使用時長僅為14分26秒。
{ ‘message’: { ‘Uptime’: 0,
‘activations’: 2,
‘activeTime’: 42,
‘idleTimeouts’: 1,
‘uptime’: 247},
‘name’: ‘comappleosanalyticssystemUsage’,
‘uuid’: ‘00866801-81a5-466a-a51e-a24b606ce5f1’}
{ ‘message’: { ‘Uptime’: 2000,
‘activations’: 2,
‘activeTime’: 824,
‘idleTimeouts’: 1,
‘uptime’: 2431},
‘name’: ‘comappleosanalyticssystemUsage’,
‘uuid’: ‘00866801-81a5-466a-a51e-a24b606ce5f1’}
表7. 反應系統使用狀態的兩條記錄
接下來的兩條記錄分別為2小時的心跳記錄一次1天的心跳記錄。這些記錄的作用尚未澄清,因為這些心跳記錄似乎與診斷周期的時長或者任何程序的運行時間無關。BogusFieldNotActuallyEverUsed
這個字段名很可能表示不僅該字段已被棄用,甚至這條數據本身已被棄用。
{ ‘message’: { ‘BogusFieldNotActuallyEverUsed’: ‘null’, ‘Count’: 7},
‘name’: ‘TwoHourHeartbeatCount’,
‘uuid’: ‘7ad14604-ce6e-45f3-bd39-5bc186d92049’}{ ‘message’: { ‘BogusFieldNotActuallyEverUsed’: ‘null’, ‘Count’: 1},
‘name’: ‘OneDayHeartBeatCount’,
‘uuid’: ‘a4813163-fd49-44ea-b3e1-e47a015e629c’}
表8. 心跳記錄
應用使用信息
后面開始的每一行都包含3個鍵:name
、uuid
以及message
。name
以及uuid
鍵可以映射到生成該記錄的特定子系統,message
字段包含一個嵌套JSON記錄,其中包含其他一些數據。我們所觀察到的一些最為常見的子系統以及UUID值如下所示:
子系統名 | UUID |
---|---|
comappleosanalyticsappUsage | 4d7c9e4a-8c8c-4971-bce3-09d38d078849 |
comappleosanalyticssystemUsage | 00866801-81a5-466a-a51e-a24b606ce5f1 |
comappleosanalyticsMASAppUsage | 0fd0693a-3d0a-48be-bdb2-528e18a3e86c |
TwoHourHeartbeatCount | 7ad14604-ce6e-45f3-bd39-5bc186d92049 |
OneDayHeartBeatCount | a4813163-fd49-44ea-b3e1-e47a015e629c |
表9. 向守護程序報告數據的常見子系統及對應的UUID
我們的測試表明,這些UUID在運行macOS 10.13.4以及10.13.5系統上均保持一致,這表明UUID僅與子系統及子系統的版本有關,如果Apple將來修改子系統時,這些值可能也會發生改變。
comappleosanalyticsappUsage
子系統會為執行的每個程序生成一條記錄。
{ ‘message’: { ‘activations’: 105,
‘activeTime’: 4250,
‘activityPeriods’: 12,
‘appDescription’: ‘com.google.Chrome ||| 67.0.3396.87 (3396.87)’,
‘foreground’: ‘YES’,
‘idleTimeouts’: 4,
‘launches’: 0,
‘powerTime’: 12537,
‘processName’: ‘Google Chrome’,
‘uptime’: 26110},
‘name’: ‘comappleosanalyticsappUsage’,
‘uuid’: ‘4d7c9e4a-8c8c-4971-bce3-09d38d078849’}
表10. comappleosanalyticsappUsage
子系統生成的.core_analytics
示例記錄
message
下包含的9個字段可能會為分析人員的取證工作提供大量信息:
1、activeTime
可能提供程序處于前臺運行時的秒數;
2、activityPeriods
可能提供程序被調到前臺運行的次數;
3、appDescription
直接來自于應用程序包中Info.plist
的相關信息。如果Info.plist
中的相關鍵值信息格式錯誤或者為空,這里字段的值則會顯示為???
;
在CoreAnalytics記錄中存放的數據滿足如下格式:
<CFBundleIdentifier> ||| <CFBundleShortVersionString> (<CFBundleVersion>)
表11. CoreAnalytics記錄的數據格式
例如,Google Chrome.app
的Info.plist
文件中可以根據如下鍵值提取出所需的信息:
<key>CFBundleIdentifier</key>
<string>com.google.Chrome</string>
<key>CFBundleShortVersionString</key>
<string>67.0.3396.99</string>
<key>CFBundleVersion</key>
<string>3396.99</string>
表12. Google Chrome.app
應用Info.plist
中的相關鍵值
如果程序以獨立的Mach-O可執行文件形式運行,或者Info.plist
不可用、格式錯誤或者不完整,那么appDescription
就會顯示為UNBUNDLED ||| ???
。
例如,GlobalProtect中Info.plist
的CFBundleVersion
鍵值就無法獲取到:
com.paloaltonetworks.GlobalProtect ||| 4.0.2-19 (???)
表13. GlobalProtect的CoreAnalytics記錄中對應的appDescription
值
其他字段的意義如下:
4、foreground
字段的值為YES
或者NO
,表示程序是否在前臺運行;
5、idleTimeouts
的含義目前尚未澄清;
6、launches
可能表示的是診斷報告期間應用的啟動次數。如果應用在診斷周期開始前啟動,那么launches
的值為0;
7、根據我們的測試結果,powerTime
可能表示的是程序處于運行狀態并消耗AC電源的時間(以秒為單位);
8、processName
的值來自于應用程序包中Info.plist
文件的CFBundleExecutable
鍵值;
舉個例子,Google Chrome.app
中Info.plist
文件的該鍵值信息如下:
<key>CFBundleExecutable</key>
<string>Google Chrome</string>
表14. Google Chrome.app
應用Info.plist
中的CFBundleExecutable
鍵值
如果程序為獨立的Mach-O可執行文件,或者Info.plist
不可用、格式錯誤或者不完整,這個字段仍然會在CoreAnalytics記錄正確生成。根據我們的測試結果,目前我們尚未澄清守護程序獲取該數據所使用的是哪個輔助來源。
如下所示,在某些情況下,processName
字段將會留空。在這些場景中,我們實際上無法通過CoreAnalytics中推測執行的是哪個程序。
{ ‘message’: { ‘activations’: 0,
‘activeTime’: 0,
‘activityPeriods’: 0,
‘appDescription’: ‘UNBUNDLED ||| ???’,
‘foreground’: ‘NO’,
‘idleTimeouts’: 0,
‘launches’: 2,
‘powerTime’: 0,
‘processName’: ”,
‘uptime’: 24},
‘name’: ‘comappleosanalyticsappUsage’,
‘uuid’: ‘4d7c9e4a-8c8c-4971-bce3-09d38d078849’}
表15. 無名程序所對應的CoreAnalytics記錄
9、uptime
可能表示的是程序運行的總時長(以秒為單位),該數字并未包含系統睡眠或者關閉的時間。在診斷期間,某些程序(如Dock)的運行時間很可能與系統運行時間相近或完全匹配。在上文的系統使用信息部分中,兩個uptime
(247及2431)的總和與Dock應用的uptime
值(2678)完全匹配,如下所示:
{ ‘message’: { ‘activations’: 0,
‘activeTime’: 0,
‘activityPeriods’: 0,
‘appDescription’: ‘com.apple.dock ||| 1.8 (1849.16)’,
‘foreground’: ‘NO’,
‘idleTimeouts’: 0,
‘launches’: 0,
‘powerTime’: 0,
‘processName’: ‘Dock’,
‘uptime’: 2678},
‘name’: ‘comappleosanalyticsappUsage’,
‘uuid’: ‘4d7c9e4a-8c8c-4971-bce3-09d38d078849’}
表16. Dock應用對應的CoreAnalytics記錄
在我們的測試中,我們發現另一個子系統(即comappleosanalyticsMASAppUsage
)往CoreAnalytics文件中寫入了與Microsoft OneNote有關的記錄。JSON嵌套數據中的鍵值與comappleosanalyticsappUsage
子系統所寫的鍵值有所不同。這條記錄并沒有使用一個appDescription
字段,而是將CFBundleIdentifier
和CFBundleShortVersionString
(以及CFBundleVersion
)寫入identifier
以及version
字段中。除了launches
之外,該記錄還缺少其他所有字段。
{ ‘message’: { ‘identifier’: ‘com.microsoft.onenote.mac’,
‘launches’: 1,
‘version’: ‘15.32 (15.32.17030400)’},
‘name’: ‘comappleosanalyticsMASAppUsage’,
‘uuid’: ‘0fd0693a-3d0a-48be-bdb2-528e18a3e86c’}
表17. Microsoft OneNote對應的CoreAnalytics記錄,由另一個子系統生成
可能其他子系統所生成的數據結構也會有所不同。
在診斷周期結束時,CoreAnalytics數據會被寫入到文件中,在此之前我們有可能能恢復這些數據。
在數據提交并推送到當天的CoreAnalytics文件之前,/private/var/db/analyticsd/aggregates/
目錄充當了每個子系統的臨時性暫存目錄。每個子系統在該目錄中都對應一個階段性文件,文件名為子系統的UUID值。比如,4d7c9e4a-8c8c-4971-bce3-09d38d078849
文件包含了1.0版comappleosanalyticsappUsage
子系統所生成的報告數據(這些數據在00:00:00 UTC時間后的首次睡眠或者關機時會寫入到/Library/Logs/DiagnosticReports/
目錄的CoreAnalytics文件中)。這些文件的內容似乎為嵌套數組,比如Google Chrome所對應的數組如下所示:
[ [‘Google Chrome’, ‘com.google.Chrome ||| 67.0.3396.99 (3396.99)’, ‘YES’],
[5660, 145, 0, 0, 5, 2, 1020]]
表18. Google Chrome所對應的聚合數據
這些值對應comappleosanalyticsappUsage
子系統所生成的CoreAnalytics記錄中的一些字段,具體如下:
[ [processName, appDescription, foreground],
[uptime, activeTime, launches, idleTimeouts, activations, activityPeriods, powerTime]]
表19. 聚合數據的數組結構
解析聚合文件中中數組的值,將其與上述字段一一對應后,我們現在就可以在當天分析數據被提交至CoreAnalytics文件前,分析當天應用的使用情況。
CoreAnalytics可以為我們提供關于系統及應用程序使用情況的大量信息,程序執行歷史跨度長達一個月的,可以在調查任務中起到關鍵作用,由于調查行為本身特性,證據往往無法在現場第一時間收集,此時能起到的作用也就更加明顯。盡管Apple提供的官方文檔可能會進一步澄清某些字段的用途及含義,研究人員可以以本文為基礎,開始研究macOS系統上的應用活動數據。