今天要研究是接續上篇的Windows XML Event Log (EVTX),要進入他的事件紀錄本身,我們把文件分為文件標頭(file header)、資料塊(chunks)、尾隨空值(trailing empty values)區塊,上次講到紀錄記在chunk裡,在其chunk header後會有一筆筆用2a2a0000當簽名開頭的紀錄,每筆紀錄在FileTime之後,也就是紀錄的24 byte後,就是他的XML文檔,每筆紀錄的最後會再抄一次這筆紀錄的大小當作結尾,而今天要講的就是這個XML文檔的寫法,即使有參考資料,對照自己的文件也花了一些時間,下面是筆者努力看懂的部分,如果哪裡說得不好請各個大大見諒~
一樣的,我們複製%SystemRoot%\System32\Winevt\Logs
的Setup.evtx作為範例,看到1218行(16進位),前面剛結束8個byte的FileTime,後面接著是用[MS-EVEN6]協定的二進位XML文件,通常向下會有四個部分:
我們的範例沒有Prologue,他主要是XML文件的一種宣告,我們往下看Fragment,他包含fragment header跟一個element或template instance。
fragment header總共有4個byte長,原則上都會以0f01 0100開頭,包含fragment header的token跟版本號等。
再來是一個element或template instance,我們的範例檔以Template instance這種紀錄居多,他的大小可變,以0c開頭做作為Template instance的token,後面會有Template的定義段跟Template的資料段,這兩段的大小也不一定,裡面也會有數據大小的資料。
如果遇到的是element,則會有下面幾種物件:
好,我盡力了……後面的判讀實在看不懂又對不上,不過這已經對文檔局格有基礎的理解,這樣可以做到一些事,我們可以嘗試刪除一筆紀錄,在事件檢視器中,日誌都只能全部清空或自動覆寫,無法刪除單筆,有了這兩天的知識,我們其實可以來個實作做到手動改寫日誌:
圖片來源:https://blog.fox-it.com/2017/12/08/detection-and-recovery-of-nsas-covered-up-tracks/
這是一個刪除日誌的示意圖,我們說每筆紀錄會以2a2a0000作為開頭簽名,有幾筆紀錄就應該要有幾個2a2a0000,這個我們先稱他叫Record Header,後面會寫紀錄的長度,並在紀錄的結尾再寫一次,那如果我們把長度延伸到下筆記錄,就意味著中間記錄的刪除,也就是改寫成圖中的New Size,不過當然,後面還要改寫校驗值等等讓文件合理,我們就一步步往下做,記得日誌先備份,我們同樣以範例的Setup.evtx做改寫,嘗試修改最後一筆記錄。
File Header的Next recordidentifier要減掉一,上篇提到這份日誌存了96筆記錄,下一筆是97,因為這裡要刪除一筆,所以下一筆的指標就會是96,所以我們把第25個byte的61改成60。
再來File Header的資料改完了,所以接下要去第124 byte後修改4個byte的CheckSum,重新計算一遍前120 byte的CRC32值才會通過校驗程序,這裡筆者計算完是A36BA7FA(計算的時候input要設定為Hex而不是ASCII,筆者找到的計算機),記得用小端寫法,所以要寫faa7 6ba3。
因為Chunk header的修改需要用到新的記錄結尾位置,所以我們先到Event Record改Size,可以查詢最後一個2a2a0000,應該要是最後一筆記錄,可以看到後面的60代表是我們要刪除的第96筆記錄,中間e001 0000表示長度有480個byte,往前看到上筆記錄的結尾f001 0000表示長度有496個byte。
所以480+496=976個byte,換成十六進位就是03d0,小端寫法就是d003 0000,把這個新的Size放進第95筆資料在開頭顯示的大小,和第96筆資料在結尾顯示的大小。
最後回到Chunk header,如果有多個Chunk就是找最後一個,這裡只有一個所以就是4096 byte之後。
首先要把Last event record number跟Last event record identifier從60改成5f表示記錄到95筆。
再來是Chunk header的44 byte後的Last event record data offset,他是描述從Chunk header到最後一筆資料前的大小,所以現在是a628也就是42536個byte,減掉倒數第二筆(第95筆)資料的大小(496 byte),就會變成42040 byte(a438),所以我們要把這個指標改為小端寫法 38a4 0000。
接著是Event records checksum,他是從塊頭結束的第一筆記錄開始一直到最後一筆記錄結束,這段資料的CRC32值,也就是第4096+512=4608 byte開始到最後一筆資料的結尾也就是最後一個d003 0000(原第96筆資料記錄大小的結尾),筆者計算完的結果是327CBA0B,小端寫法0bba 7c32。
最後則是在Chunk header有一個Checksum,他位在整個標頭的第124 byte後4個byte,他是整個Chunk header的前120 byte跟128-512 byte的CRC32值,直接刪掉中間的8個byte合併成504個byte的資料段去計算就對了,用十六進位的說法就是找位址0×1000-0×1078,0×1080-0×1200(0x表示16進位的意思),筆者這裡計算完是0xC6540581,小端寫法8105 54c6。
整個Chunk header修改完:
接著我們到事件檢視器,在右側欄位按開啟儲存的記錄,打開剛剛修改完的檔案……我在這裡猶豫了許久,這是一整篇下來唯一一個可以測試的地方,失敗就要全部重檢查,結果竟然過了!皆大歡喜差點在半夜叫出來~~
我們可以看到這裡的記錄確實變成95筆,而我們照日期排序一看,跟之前在系統的比對會發現,他的確刪除了最後一筆資料,也就是最新的一筆記錄,選這個記錄檔也是因為他比較不常更動。
如果我們有修改錯誤,像是某個checksum算錯,就會無法開啟像下面這樣:
至於復原就是把剛剛做的全部倒回去做就對了,網路上似乎也有工具可以做得到,而上述的方法也是NAS方程式組織的DanderSpritz中的eventlogedit實現方式,不過說到底其實只是隱藏資料,真正要刪除的話就是要把剛剛最後一筆記錄的部分全部改寫成00做清空。
寫到這裡才發現自己缺的東西很多,從一開始的大小端,編輯16進位的文件,CRC32值一開始還以為是10進位的格式又轉換一遍,直到後來對原文件計算才知道是錯的又繼續找,發現還要把文件內容當作hex值input進去,中間幾度看不doc在寫什麼,看著別人做不會發現實際的困難,有興趣的話你也可以嘗試,總之這樣子,假設我們都對這些日誌了解了,下篇就來解決問題吧~~
參考資料:
https://github.com/libyal/libevtx/blob/main/documentation/Windows%20XML%20Event%20Log%20(EVTX).asciidoc
https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/444383/
https://blog.fox-it.com/2017/12/08/detection-and-recovery-of-nsas-covered-up-tracks/
https://www.convertworld.com/zh-hant/numerals/hexadecimal.html
https://crccalc.com/