前一篇已經看過 Run List 裡的 Length、Relative Offset、LCN 和 Byte Offset 要怎麼算,這篇就直接把這些結果拿來實際還原檔案。
這次使用的 Disk Image 是 HL-WS03.001,目標是找回其中被刪除的 manifest_0512.png。
整個流程會先在 $MFT 中找到 manifest_0512.png 對應的 MFT Record,再從這筆 Record 的 $DATA Attribute 找出 Run List,最後把分散在 Image 不同位置的資料重新拼回來。
先用 HxD 開啟 HL-WS03.001,搜尋 FILE0。
搜尋後會找到很多結果,這些結果每一筆相差 1024 Bytes,也就是一筆一筆的 MFT Record。

逐筆查看內容,在 Offset 78848 的 Record 中,可以從右側的文字區看到 manifest_0512.png。

因此可以確認這一筆就是目標檔案所對應的 MFT Record。
找到正確的 MFT Record 後,接著就在這筆 Record 裡尋找 $DATA Attribute。
$DATA 的 Type ID 是 80 00 00 00。
在 Offset 79128 可以看到 80 00 00 00 ,也就是 $DATA Attribute 的實際起始位置 ($DATA Attribute Offset)。

在 $DATA Attribute 開頭往後 8 Bytes 的位置,可以看到 Non-resident Flag 為 01。
代表這個檔案的內容不是直接存放在 MFT Record 裡,而是記錄在其他 Cluster 中,因此接下來需要透過 Run List 找到真正的資料位置。
Run List 的起始位置會記錄在 $DATA Header 中,而這個 Offset 就位在 $DATA Attribute 開頭往後 32 Bytes 的位置。
這筆 $DATA 的起點是 79128,所以:
79,128 + 32
= 79,160
從這個位置可以看到 40 00,以 Little-endian 轉換後為 64 Bytes,表示 Run List 位在 $DATA Attribute 開頭往後 64 Bytes 的位置。
因此:
79,128 + 64
= 79,192
跳到 Offset 79192,可以找到:
21 13 5A 48 22 16 00 CF EC 21 0D 56 14 00

這就是 manifest_0512.png 的 Run List。
按照 DAY 22 介紹的方式解開後,可以得到:
| Run | Length | Relative Offset | LCN | Byte Offset |
|---|---|---|---|---|
| Run 1 | 19 Clusters | Start | 18,522 | 75,866,112 |
| Run 2 | 22 Clusters | -4,913 | 13,609 | 55,742,464 |
| Run 3 | 13 Clusters | +5,206 | 18,815 | 77,066,240 |
有了 Byte Offset,就知道三段 File Data 分別位在 Disk Image 的哪個位置。
這個 Volume 的 Cluster Size 是 4096 Bytes,因此還要根據每個 Run 的 Length 算出實際需要取出的資料大小。
Run 1 有 19 Clusters:
19 × 4,096
= 77,824 Bytes
Run 1 的起始位置是 75,866,112,因此結束位置為:
75,866,112 + 77,824 - 1
= 75,943,935
Run 2 有 22 Clusters:
22 × 4,096
= 90,112 Bytes
Run 3 有 13 Clusters:
13 × 4,096
= 53,248 Bytes
整理後:
| Run | Start Offset | Length | End Offset |
|---|---|---|---|
| Run 1 | 75,866,112 | 77,824 Bytes | 75,943,935 |
| Run 2 | 55,742,464 | 90,112 Bytes | 55,832,575 |
| Run 3 | 77,066,240 | 53,248 Bytes | 77,119,487 |
接著就可以在 HxD 裡把三段資料分別取出。
先按 Ctrl + G 跳到 Run 1 的起始位置 75866112。
再使用 Ctrl + E 選取 77824 Bytes。

將 Run 1 的資料複製起來,新增檔案 manifest_0512.bin 並貼上。

接著用相同的方法取出 Run 2 和 Run 3,並依序接在 manifest_0512.bin 的尾端。
Run 2
Start Offset:55742464
Length:90112 Bytes
Run 3
Start Offset:77066240
Length:53248 Bytes
三個 Run 總共有:
19 + 22 + 13
= 54 Clusters
因此拼接後的大小為:
54 × 4,096
= 221,184 Bytes
不過,這個 221,184 Bytes 是檔案配置到的空間大小,還不一定等於檔案真正的內容大小。
回到原本的 $DATA Attribute,可以從 Header 裡確認這個檔案的 Allocated Size 和 Logical Size。
在 Non-resident $DATA 中,從 Attribute 開頭往後 40 Bytes 的位置記錄的是 Allocated Size。
00 60 03 00 00 00 00 00
以 Little-endian 轉換後為:
0x36000 = 221,184 Bytes
而從 $DATA Attribute 開頭往後 48 Bytes 的位置,記錄的是 Logical Size。
7C 57 03 00 00 00 00 00
以 Little-endian 轉換後為:
0x3577C = 219,004 Bytes
因此,這個檔案的 Allocated Size 是 221,184 Bytes,但真正的 Logical Size 只有 219,004 Bytes,兩者相差 2,180 Bytes。
也就是說,三個 Run 雖然總共配置了 221,184 Bytes 的空間,但真正屬於檔案內容的只有前 219,004 Bytes,最後多出的 2,180 Bytes 並不屬於原始檔案內容。
因此,拼接完成的 manifest_0512.bin 還需要進一步 Trim。在 HxD 中,從 Decimal Offset 219004 開始選取到檔案結尾並刪除,只保留前 219,004 Bytes,就能得到正確的檔案大小。

Trim 完成後,再將檔案重新命名成 manifest_0512.png 並開啟,就可以看到成功還原的 Shipping Manifest。
