使用hexdump工具追蹤EXT4文件系統中的一個文件


  昨天追蹤EXT4文件系統的過程中出了點問題,就是找不到文件,於是試了一下追蹤FAT32文件系統的,成功之后有了點信心,今天繼續嗑EXT4文件系統,終於找到啦,記錄一下。

  • 操作系統:linux(centos 6.5)
  • 文件系統:EXT4
  • 工具:hexdump,windows自帶計算器
  • 參考資源:《數據重現-文件系統原理精解與數據恢復最佳實踐》(馬林 著)

         《基於EXT4文件系統的數據恢復方法研究》(徐國天)

         題為《Ext4文件系統架構分析》的系列博客

         題為《 深入理解ext4(一)----extent區段》的博客

         題為《ext4的Extent解析》的博客

         題為《ext4_ext_find_extent解析》的博客

        

EXT4文件系統架構(非原創):

  

補充說明:EXT4文件系統中只有0號塊組的超級塊和塊組描述符表的位置是固定的,其他都不固定。其中,超級塊總是開始於偏移位置1024(字節),占據1024個字節,塊組描述符表緊隨超級塊后面,占用的大小是不定。

步驟:

1、查看文件系統基本情況,新建子目錄和文件

  

可以看到掛載在/boot目錄下的文件系統類型是EXT4,因此在改目錄下新建子目錄及文件:

文件內容為:“This test is belong to Boot folder!”文件基本信息如下:

2、查看超級塊,找到0號塊組起始塊號、塊大小、每塊組所含塊數、每塊組i節點數、第一個非保留i節點、每個i節點大小。

命令:hexdump -s 1024 -n 1024 -C /dev/sda1

查看結果:

首先可以看到0x38-0x39是EXT系列文件系統的簽名標志:“53 ef”

0x14-0x17是0號塊組起始塊號:0x01,說明超級塊前面有一個塊為保留塊,用來存儲引導程序。

0x18-0x1b是塊大小:0x00,這里的值指的是將1024字節左移的位數,移動0位也就是1024字節,移動一位相當於乘以2,就是2048字節。

0x20-0x23是每塊組所含塊數:0x2000(十進制8192)

0x28-0x2b是每塊組所含i節點數:0x07f0(十進制2032)

0x54-0x57是第一個非保留i節點號:0x0b(11),一般為lost+found目錄

0x58-0x59是每個i節點結構的大小:0x80(十進制128),也就是每個i節點表項占用128個字節。

3、查看塊組描述符表,找到塊位圖塊、i節點位圖塊、i節點表起始塊號、塊組目錄數。

命令:hexdump -s 2048 -n 1024 -C /dev/sda1

查看結果:

塊組描述符表中每個塊組使用32個字節來描述,因此第一個32字節描述的就是0號塊組。

0x00-0x04是塊位圖塊起始塊號:0x0104

0x05-0x07是i節點位圖塊起始塊號:0x0114

0x08-0x0b是i節點表起始塊號:0x0124

0x10-0x11是該塊組的目錄數:0x02

這里獲取的起始塊號是邏輯塊號(將文件系統所有的塊從0開始遞增編號),因此在計算偏移量時可以直接乘以每塊字節數(0x400,也就是十進制的1024)

這里補充說明一下:EXT3文件系統的塊位圖塊號、i節點位圖塊和i節點表起始塊號是遞增的,而這里他們三個之間卻是相差一個常量:16。

因為這里使用了一個EXT4新引進的結構:Flexible 塊組(flex_bg)

Flexible 塊組

  Flexible 塊組的設計目的是組成更大的邏輯塊組,盡量讓大文件連續,將元數據聚集加快元數據載入。因此它的做法是將幾個塊組的塊位圖塊,i節點位圖塊,i節點表塊放在這個邏輯塊組的第一個塊組中,這樣剩下的塊組中就只存儲了該塊組的超級塊和塊組描述表。

上面的塊組描述表中可以看出這個Flexible 塊組是將16個塊組合成了一個邏輯塊組。

  說起Flexible 塊組就要提起元塊組(Media Block Group),因為他和Flexible 塊組是“有你沒我”的關系。Flexible 塊組是移動了塊位圖塊、i節點位圖塊、i節點表塊,元塊組是減少了塊組描述符表的備份,原本塊組描述符表和超級塊一起備份在塊組號為0或者3、5、7的冪的塊組,元塊組是只在一個元塊組的第一、二個塊組和最后一個塊組中備份塊組描述符表,增加元塊組存儲數據的空間。

 

 

 

 

 

 

 

 

 

 

3、從根目錄中找到子目錄

  第一步我們提到了第一個非保留i節點號為11,那么前面的10個保留i節點的作用是什么呢(i節點號從1開始編號),這里只說明2號節點是存儲的是根目錄i節點號,因此我們讀取i節點表的2號表項值就可以找到根目錄所在塊號了。

  計算i節點表項的偏移量涉及到了塊組描述符表中的i節點表起始塊號:0x0124。

  某i節點表項起始字節=i節點起始塊號*每塊所占字節數+(該i節點號-1)*每個i節點表項所占字節數

   0x0124*0x400+(0x02-0x01)*0x80=0x49080

下面就可以讀取根目錄i節點表項值了。

命令:hexdump -s 0x49080 -n 128 -C /dev/sda1

查看結果:

0xa8-0xd7是12個直接塊指針,其中四個字節為一個單位,表示一個塊號。

(這里要解釋的是:EXt4文件系統將12個直接塊指針、1個一級間接塊指針、1個二級間接塊指針、1個三級間接塊指針,一共60個字節用extent結構來替換,但前提是偏移0xa0-0xa3處的標志位置為“00 00 08 00”,而這里全為0,則證明沒有使用extent結構,因此依舊按照塊指針形式查找根目錄)

圖中可以看出根目錄只占用了一個塊,塊號為:0x1104

  根目錄的起始偏移字節為=根目錄所在塊號*每塊所占字節數

則根目錄的起始偏移字節:0x1104*0x400=0x441000

使用命令:hexdump -s 0x441000 -n 1024 -C /dev/sda1 查看根目錄內容:

查看/boot目錄下的文件:

可以看到兩者的內容是相符的,說明我們找的沒有錯。根目錄中BOOTDIR的目錄項用黑色底紋標注。

0x6c-0x6f是該文件內容所在i節點號:0x7f01

0x70-0x71是本目錄項長度:0x10(16字節)

0x72是本目錄項名字長度0x07(7個字節)

0x73是本文件類型:0x02(表示目錄)

0x74開始是文件名的ASCCI碼:“42 4f 4f 54 44 49 52 00”

在這一步中與FAT32文件系統的區別有兩個:

  一是怎么尋找根目錄。FAT32中根目錄在數據區的開頭,因此我們可以直接去數據區讀取;而EXT4文件系統中,我們需要通過2號i節點表找到根目錄所在的塊號,才能看到根目錄內容,這里就可以看出EXT4文件系統將目錄也看作文件了,因為他的讀取方式和普通文件是一樣的,只不過普通文件需要從目錄中得到i節點號,而根目錄是一開始就定好了i節點號。

  二是目錄的大小。FAT32中目錄的大小是固定的(短文件名目錄占32字節,長文件名目錄占多個32字節),所以當文件名過長時,使用了長文件名機制來解決,而EXT4文件系統的目錄項大小是在目錄項中靈活定的。比如這一步中我們查看到的根目錄結果中,開始的12個字節是本目錄項,緊接着12個字節是根目錄項,而我們要找的目標目錄項的長度是16個字節,其中說明部分(i節點號,本目錄項長度字節數,名字長度,文件類型)占用都是一樣的,差就差在文件名部分。但我們也看到文件名后面總有“00”補齊,這是因為目錄項的長度總要是4的倍數,因此不夠時會用0補齊。

4、從i節點表中找到子目錄所在塊號

第三步中我們找到指向子目錄的i節點號為0x7f01,也是邏輯i節點號,因此我們要先找到0x7f01在哪個塊組中:

  某i節點所在塊組=該i節點號/每塊組i節點個數

  0x7f01/0x7f0=0x10(十進制16)

  某i節點所在i節點表號=該i節點號%每塊組i節點個數

  0x7f01%0x7f0=0x01

因此0x7f01在16號塊組的i節點表中,在改i節點表的1號表項中。

接下來我們要從塊組描述符表中找到16號塊組的i節點表起始塊號,以便找到子目錄所在塊號。

  某塊組在塊組描述符表中偏移字節=塊組描述符表起始字節+塊組號*每塊組描述符表項字節數

  2048+16*32=2560字節

我們讀取2560偏移字節開始的32字節:

可以看到:0x08-0x0b為i節點表起始塊號:0x020021

讀取16號塊組i節點表的1號i節點表項值:

這里需要重點注意:0x20-0x23處的標志內容為“00 00 08 00”也就是0x080000,表示使用了extent結構,因此這里文件子目錄的搜索就需要按照extent結構來讀取0x28-0x63這60個字節的內容。

有個疑問:EXT4文件系統什么時候使用extent結構,查看0號塊組的10個保留i節點時,看到只有8號也就是日志節點啟用了extent結構,其他都沒有使用,而其他塊組中似乎是都默認啟用extent結構,但也發現了例外,因此不能確定EXT4關於啟用extent結構的規定,后續需要注意!

下面介紹一下extent的結構,內容有參考。

每個extent結構占用12個字節,所以每個i節點表項中可以有60/12=5個extent結構,這其中第一個extent作為extent頭(extent header是一個B+樹的描述頭),剩下的4個是extent體(extent body,由於extent樹中的節點有兩種:索引節點和葉子節點,因此當節點為索引節點時(可以從extent header中區分索引節點和葉子節點)extent body存儲的是下一級extent樹節點信息,當節點為葉子節點時extent body 中存儲的是數據塊塊號信息)

extent樹結構

 

extent數據結構

extent header

 

這里要說明的是:魔數是一個校驗值,只有當校驗結果是0xf30a時B+樹的塊才正確

        節點在extent樹中的深度是從葉子節點算起,因此根節點的深度是最深的(看到有人說根節點的最大深度不超過5),當深度為0時表明是葉子節點,那么這個節點就是數據節點,他后面的extent body就是指向的數據塊,存儲數據塊號;當深度大於0,后面的extent body表示索引節點。

extent body

當為索引節點時

當為葉子節點時

 

補充說明:當extent body表示索引節點時最后最后兩個節點冗余是為了遷就葉子節點。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

從0x28-0x63是extent結構。

extent頭中說明的信息有:本區段有一個extent body,最大區段個數為4,本段在extent樹中深度為0,是葉子節點。

后面緊着的12個字節是extent body說明的信息有:本區段的第一個塊號是0,本區段含有一個塊,本區段指向的數據塊塊號為0x021002。

該塊的偏移字節:0x8400800

5、從子目錄對應的i節點號得到目標文件塊號

查看結果第4步中子目錄塊內容:

加黑色底紋的是本目錄(“.”)和根目錄(“..”)接下來就是目標文件:BOOTTEXT.txt,他的i節點號為:0x7f04

 查看i節點表,找到目標文件的塊號:

  該i節點表項的偏移字節為:0x020021*0x400+(0x7f04%0x7f0-1)*0x80=0x8008580

讀取該偏移字節處開始的128字節內容:

同樣目標文件的i節點表項也啟用了extent結構,按照與第4步同樣的方法分析,得帶目標文件所在塊號0x024005(偏移字節為0x9001400)。

接下來讀取該塊內容:

找到啦!和第一步中使用cat命令查看的文件內容一致。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM