目标: 找到/boot/Image文件的数据块
0.ext4文件系统布局
sudo dumpe2fs /dev/mmcblk0p1
输出
sudo dumpe2fs /dev/mmcblk0p1
dumpe2fs 1.44.1 (24-Mar-2018)
Filesystem volume name: <none>
Last mounted on: /
Filesystem UUID: 0091ad72-a6a0-4cd7-9f64-75b0c06f4583
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 524288
Block count: 2097152
Reserved block count: 104857
Free blocks: 708331
Free inodes: 356662
First block: 0
Block size: 4096
Fragment size: 4096
Group descriptor size: 64
Reserved GDT blocks: 1023
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 8192
Inode blocks per group: 512
Flex block group size: 16
Filesystem created: Fri Oct 10 16:01:29 2025
Last mount time: Sat Jan 1 09:00:17 2000
Last write time: Sat Jan 1 09:00:17 2000
Mount count: 2
Maximum mount count: -1
Last checked: Tue Oct 14 18:35:14 2025
Check interval: 0 (<none>)
Lifetime writes: 107 MB
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 256
Required extra isize: 32
Desired extra isize: 32
Journal inode: 8
First orphan inode: 271049
Default directory hash: half_md4
Directory Hash Seed: 9a23ae96-0c0d-4279-8d95-4bc605292e1c
Journal backup: inode blocks
Checksum type: crc32c
Checksum: 0x5a001698
Journal features: journal_incompat_revoke journal_64bit journal_checksum_v3
Journal size: 64M
Journal length: 16384
Journal sequence: 0x00001121
Journal start: 8197
Journal checksum type: crc32c
Journal checksum: 0xd573dcb6
Group 0: (Blocks 0-32767) csum 0x8e29 [ITABLE_ZEROED]
Primary superblock at 0, Group descriptors at 1-1
Reserved GDT blocks at 2-1024
Block bitmap at 1025 (+1025), csum 0x56053078
Inode bitmap at 1041 (+1041), csum 0x64306ca9
Inode table at 1057-1568 (+1057)
0 free blocks, 7 free inodes, 727 directories
Free blocks:
Free inodes: 396, 2276, 2280, 2470-2471, 2716, 2804
Group 1: (Blocks 32768-65535) csum 0x9dfa [ITABLE_ZEROED]
Backup superblock at 32768, Group descriptors at 32769-32769
Reserved GDT blocks at 32770-33792
Block bitmap at 1026 (bg #0 + 1026), csum 0xf93b5b4a
Inode bitmap at 1042 (bg #0 + 1042), csum 0x099df3c4
Inode table at 1569-2080 (bg #0 + 1569)
33 free blocks, 0 free inodes, 558 directories
Free blocks: 33800-33815, 33960-33975, 42671
Free inodes:
其中的关键信息
首先是超级块中存储的
Group descriptor size: 64
Block size: 4096
Blocks per group: 32768
Inode size: 256
Inodes per group: 8192
Inode blocks per group: 512
第一个说明group descriptor table(GDT, 块组描述表)的大小是64个, 总共有64个group
这里简单说明一下ext4各级单位之间的关系
最顶层的为group
再下一层的为block
再下一层为bytes
数据块的块号指的是block的号,所以想找到数据块就是 数据块号x block size
inode号则稍微是有点不一样的, 应该这样理解, 即对inode来说
底部好像是一个连续的数组, 然后每个8192个(inodes per group) 算一个group
它的大小是inode size (Bytes)
因此总共是占了 8192 x 256 / 4096 = 512个block (即Inode blocks per group)
但其实每个group inode所在的位置是不确定的, 这个是需要查询GDT来获取的
比如说
Group 0: (Blocks 0-32767) csum 0x8e29 [ITABLE_ZEROED]
Primary superblock at 0, Group descriptors at 1-1
Reserved GDT blocks at 2-1024
Block bitmap at 1025 (+1025), csum 0x56053078
Inode bitmap at 1041 (+1041), csum 0x64306ca9
Inode table at 1057-1568 (+1057)
0 free blocks, 7 free inodes, 727 directories
Free blocks:
Free inodes: 396, 2276, 2280, 2470-2471, 2716, 2804
这个就说明, 它的Inode table在1057-1568块的位置
然后整个组在0-32767的位置
然后0号group默认是用来放主超级块的
所以它这里会告诉你主超级块在0号块, GDT在1-1号块(因为只有64个group,每个descriptor 64字节,所以64×64=4096字节=1块)
- Reserved GDT blocks at 2-1024 是系统预留给将来扩展的GDT空间
我自己电脑上的输出是这样的
Group 0: (Blocks 0-32767) csum 0xb0fe [ITABLE_ZEROED]
Primary superblock at 0, Group descriptors at 1-120
Reserved GDT blocks at 121-1144
Block bitmap at 1145 (+1145), csum 0x1f55a79e
Inode bitmap at 1161 (+1161), csum 0x61a30a41
Inode table at 1177-1688 (+1177)
276 free blocks, 8172 free inodes, 2 directories, 8171 unused inodes
Free blocks: 9645-9648, 9750-9751, 9881-9882, 9900-9913, 10112-10239, 10358-10361, 10495-10508, 10576-10579, 10867-10869, 10888-10911, 10986-10990, 11085-11100, 11281, 32376-32387, 32438-32464, 32521-32534, 32766-32767
Free inodes: 21-8192
可以看到其实是在1-120的, 然后后面的121-1144是保留用的,默认应该是0, 注意这里提到的都是块号
所以假如我需要找inode table, 则要从1177-1688这里找
然后group 0的布局如下所示
Group 0: (Blocks 0-32767)
┌─────────────────────────────────────────────────────┐
│ 块 0: 主超级块 (在块0的1024-2047字节位置) │
├─────────────────────────────────────────────────────┤
│ 块 1: 块组描述符表 │
├─────────────────────────────────────────────────────┤
│ 块 2-1024: 保留的GDT块 (未来扩展用) │
├─────────────────────────────────────────────────────┤
│ 块 1025: Block bitmap (4096字节,标记32768个块) │
├─────────────────────────────────────────────────────┤
│ 块 1026-1040: 未使用 (间隙) │
├─────────────────────────────────────────────────────┤
│ 块 1041: Inode bitmap (1024字节,标记8192个inode)│
├─────────────────────────────────────────────────────┤
│ 块 1042-1056: 未使用 (间隙) │
├─────────────────────────────────────────────────────┤
│ 块 1057-1568: Inode表 (512个块,存储8192个inode) │
├─────────────────────────────────────────────────────┤
│ 块 1569-32767: 实际数据块 │
└─────────────────────────────────────────────────────┘
然后如果你选择了稀疏超级块存储这一特性, 备份超级块只会被存储特定的group上. 即前面还是会有几块用是用来充当超级块的备份的,
1.查找/boot/Image
启动用文件
一定存在, 所以拿这个作为查找用的例子
首先 / 的inode 号被固定为2
因此它在
2/8192 = 0
2%8192 = 2
第0块的第2个inode
查上面的表可知
第0个的inode table在1057x4096
第2个inode在偏移 256x(2-1)的位置
然后用dd去读对应大小的内容
这里是我知道它使用的ext4引入的extent格式 这个会在前面的flag中说明
ext2/3用的是12个直接块+间接块的形式, 但是这样是比较低效率的, 所以引入了extent格式.
但是它们用的这个位置是没有变化的 即40开始的位置
然后extent格式下, 头占12B
struct ext4_extent_header {
__le16 eh_magic; // 0xF30A
__le16 eh_entries; // 当前 extent 条目数
__le16 eh_max; // 最大可容纳 extent 数
__le16 eh_depth; // 树深度(0 表示叶子节点)
__le32 eh_generation; // 通常为 0
};
然后每个条目内容是
struct ext4_extent {
__le32 ee_block; // 逻辑块号(文件内的偏移,以块为单位)
__le16 ee_len; // 范围长度(块数)
__le16 ee_start_hi; // 物理块号高16位(用于 >32位地址)
__le32 ee_start_lo; // 物理块号低32位
};
我们关心的是后面这16+32位
但可以看到16位是00, 所以我们直接看最后的32位, 即再跳过8B
neu@neu-desktop:~$ sudo dd if=/dev/mmcblk0p1 bs=1 count=12 skip=$((1057*4096+256+40+12)) 2>/dev/null | hexdump -C
00000000 00 00 00 00 01 00 00 00 21 24 00 00 |........!$..|
0000000c
neu@neu-desktop:~$ sudo dd if=/dev/mmcblk0p1 bs=1 count=4 skip=$((1057*4096+256+40+12+8)) 2>/dev/null | hexdump -C
00000000 21 24 00 00 |!$..|
00000004
所以数据块在
0x2421 = 9249
然后读数据块的内容
9249x4096B
neu@neu-desktop:~$ sudo dd if=/dev/mmcblk0p1 bs=4096 skip=9249 count=1 | hexdump -C
1+0 records in
1+0 records out
00000000 02 00 00 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |................|
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.000179881 s, 22.8 MB/s
00000010 0c 00 02 02 2e 2e 00 00 0b 00 00 00 14 00 0a 02 |................|
00000020 6c 6f 73 74 2b 66 6f 75 6e 64 00 00 01 00 06 00 |lost+found......|
00000030 0c 00 04 02 62 6f 6f 74 01 00 02 00 0c 00 03 02 |....boot........|
00000040 62 69 6e 00 0c 00 00 00 0c 00 03 02 64 65 76 00 |bin.........dev.|
00000050 0e 00 00 00 0c 00 03 02 65 74 63 00 c5 00 02 00 |........etc.....|
00000060 0c 00 04 02 68 6f 6d 65 c6 00 02 00 0c 00 03 02 |....home........|
00000070 6c 69 62 00 4b 00 06 00 10 00 05 02 6d 65 64 69 |lib.K.......medi|
00000080 61 00 00 00 4c 00 06 00 0c 00 03 02 6d 6e 74 00 |a...L.......mnt.|
00000090 4d 00 06 00 0c 00 03 02 6f 70 74 00 01 00 04 00 |M.......opt.....|
000000a0 0c 00 04 02 70 72 6f 63 ff 0a 00 00 14 00 0a 01 |....proc........|
000000b0 52 45 41 44 4d 45 2e 74 78 74 00 00 02 00 04 00 |README.txt......|
000000c0 0c 00 04 02 72 6f 6f 74 06 00 04 00 0c 00 03 02 |....root........|
000000d0 72 75 6e 00 2e 00 04 00 0c 00 04 02 73 62 69 6e |run.........sbin|
000000e0 eb 00 04 00 0c 00 04 02 73 6e 61 70 ec 00 04 00 |........snap....|
000000f0 0c 00 03 02 73 72 76 00 ed 00 04 00 0c 00 03 02 |....srv.........|
00000100 73 79 73 00 ee 00 04 00 0c 00 03 02 74 6d 70 00 |sys.........tmp.|
00000110 ef 00 04 00 0c 00 03 02 75 73 72 00 67 12 02 00 |........usr.g...|
00000120 0c 00 03 02 76 61 72 00 82 bd 00 00 cc 0e 32 01 |....var.......2.|
00000130 74 65 67 72 61 31 39 34 2d 6d 62 31 2d 62 63 74 |tegra194-mb1-bct|
00000140 2d 72 61 74 63 68 65 74 2d 70 32 38 38 38 2d 30 |-ratchet-p2888-0|
00000150 30 30 30 2d 70 32 38 32 32 2d 30 30 30 30 2e 63 |000-p2822-0000.c|
00000160 66 67 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |fg..............|
00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000ff0 00 00 00 00 00 00 00 00 0c 00 00 de f3 4c 5b 21 |.............L[!|
00001000
存储的目录项的逻辑是这样的
struct ext4_dir_entry_2 {
__le32 inode; // 对应的 inode 编号
__le16 rec_len; // 本记录总长度(用于链表)
__u8 name_len; // 文件名长度
__u8 file_type; // 文件类型(如 DIR, REG, SYMLINK 等)
char name[]; // 文件名(不以 \0 结尾)
};
我们要找的是inode, 所以从name向前去掉32位, 共4B就是我们要的
所以inode号是0x060001 = 393217
393217/8192=48
393217%8192=1
48块的inode table起始在1572896
256x(1-1) = 0
然后按照和之前一样的方法我们就可以找到boot的数据块在
neu@neu-desktop:~$ sudo dd if=/dev/mmcblk0p1 bs=1 skip=$((1572896*4096+40)) count=$((256-40)) | hexdump -C
00000000 0a f3 01 00 04 00 00 00 00 00 00 00 00 00 00 00 |................|
00000010 01 00 00 00 20 20 18 00 00 00 00 00 00 00 00 00 |.... ..........|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 88 68 69 f3 |.............hi.|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 ce 47 00 00 20 00 14 ac 00 9c d2 2c |.....G.. ......,|
00000060 00 9c d2 2c 80 3c ca 8f 59 bd e8 68 54 fe 34 b3 |...,.<..Y..hT.4.|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
216+0 records in
216+0 records out
216 bytes copied, 0.0038682 s, 55.8 kB/s
000000d8
0x182020 = 1581088
然后就能发现Image
neu@neu-desktop:~$ sudo dd if=/dev/mmcblk0p1 bs=4096 skip=1581088 count=1 | hexdump -C
1+0 records in
1+0 records out
00000000 01 00 06 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |................|
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.000166152 s, 24.7 MB/s
00000010 0c 00 02 02 2e 2e 00 00 02 00 06 00 0c 00 03 02 |................|
00000020 64 74 62 00 03 00 06 00 10 00 05 01 49 6d 61 67 |dtb.........Imag|
00000030 65 00 00 00 05 00 06 00 38 00 2e 01 74 65 67 72 |e.......8...tegr|
可以观察到, Image放在了 0x060003 即目录后两个inode处
2710

被折叠的 条评论
为什么被折叠?



