本文主要通过dd,hexdump和dumpe2fs工具分析ext4的磁盘二进制数据,加深对ext4文件系统的印象,要想理解本建议先阅读下Ext4文件系统介绍 - 理论篇_nginux的博客-CSDN博客。
磁盘超级块数据分析
根据理论篇我们知道ext4 layout中前1024字节是x86的boot secotr,这之后紧接着就是super block信息,如下图:
故super block的信息只要从1024字节开始解析,命令和输出如下:
dd if=./rootfs_ext4.img bs=1 skip=1024| hexdump -Cv -n 2048
其中rootfs_ext4.img是我制作的一个虚拟磁盘,格式化为Ext4文件系统:
根据Ext4理论篇我们知道,磁盘上superblock的前32位是代表Total inode count,inode的数量:
__le32代表是little end存储方式,所以上图中第一个红圈是00010000,即65536,我们通过dumpe2fs命令校验确实如此:
第二个红框的偏移0x38处,值是:0xef53根据super block的存储格式我们知道这个是super block magic number,跟协议里面的规定完全一致:
磁盘inode table位置定位和数据分析
我们已jbd2的inode为例,根据ext4理论篇我们知道,inode 8是一个special inode,专门给jbd2使用,如下:
我们知道inode是存储在inode table中,每个inode size 是256B,所以我们怎么找到inode table的block号?dumpe2fs命令!
红框可以看到inode table是从161号block,block size 4KB inode size 256B,那么8号inode在inode table中的偏移:(8-1) *256B = 0x700,所以我们从161号block地址处偏移0x700就可以找到8号inode内容:
dd if=./rootfs_ext4.img bs=4096 skip=161| hexdump -Cv -n 2048
上述命令相当于跳过161个4K的block,然后打印2048个字节,截取0x700偏移处如下:
根据ext4理论篇中Inode Table我们知道,一个inode 是256B,其中在i_block是在偏移0x28处,占用60字节:
也就是说,从0x700 + 0x28 处对用i_block的60字节,即红框处的内容,而i_block这60字节的组织格式如下:
红框的f30a对应上图的extent_header,根据ext4理论篇中的定义我们知道extent_header数据结构如下:正好f30A对应extent_header的magic number。
磁盘文件进制数据定位
我们磁盘中有个文件1.txt ,起inode num=424:
/ # ls -i 1.txt
424 1.txt
该文件大小21.3K:
/ # ls -lh 1.txt
-rw-r--r-- 1 0 0 21.3K Jul 14 09:52 1.txt
内容如下:
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
abcdefgdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
偏移位置(424-1)* 256B ,相当于26个4KB + 7*256B,所以这个inode相当于161 + 26 = 187 block开始偏移 7 * 256 = 0x700处,故使用如下命令得到424的内容:
dd if=./rootfs_ext4.img bs=4096 skip=187 | hexdump -Cv -n 2048
目前该inode的i_block的格式如下:
上图可以看到ext4_extend_header中eh_entries = 1,eh_depth = 0,代表header之后紧跟着的是一个ext4_extent,而不是ext4_extent_id,ee_block = 0000,0000代表是该extent从文件头开始映射的,ee_length=6代表该ext4_extent连续映射了6个block,start_lo = 0x9602,代表映射的起始物理块号是0x9602 = 38402,所以该文件内容的起始物理block是38402,使用如下命令查看该block的内容:
dd if=./rootfs_ext4.img bs=4096 skip=38402 | hexdump -Cv -n 4096
可以看到输出的内容和文件1.txt的内容一致。
我们同时使用filefrag命令看下1.txt文件的物理block号:可以发现确实也是6个blocks,切开始的物理block num 38402
[root@192 test]# filefrag -v 1.txt
Filesystem type is: ef53
File size of 1.txt is 21812 (6 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 5: 38402.. 38407: 6: eof
1.txt: 1 extent found
参考文章:
黄伟亮:ext4文件系统之裸数据的分析实践