通过简单工具定位ext4文件系统中的裸数据

一、工欲善其事必先利其器

  我在系统上通过如下2条命令创建了一个ext4格式的“内存磁盘”

mkfs.ext4 /dev/ram0
mount /dev/ram0 /ram

  接着拷贝一些文件到 /ram目录下,其中一个就是 /ram/uio/uio_begin.sh

  首先通过 dumpe2fs /dev/ram0了解到文件系统的如下信息

Blocks per group:         32768
Inodes per group:         8192
Inode blocks per group:   512
First block:              0
Block size:               4096
Inode size:               256

  sh-4.3# stat /ram/uio/uio_begin.sh

  File: /ram/uio/uio_begin.sh
  Size: 168             Blocks: 8          IO Block: 4096   regular file
Device: 100h/256d       Inode: 49155       Links: 1
Access: (0750/-rwxr-x---)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2019-02-01 00:22:34.000000000
Modify: 2019-02-01 00:22:34.000000000
Change: 2019-02-01 00:22:34.000000000


二、定位文件inode所在的block

  从上面的信息我们了解到文件/ram/uio/uio_begin.sh的inode号为49155。
  而一个block组包含8192个inodes,因而uio_begin.sh所在的group这样计算: 49155/8192 = 6 ... 3,所以uio_begin.sh在第7个block组,即group6(从group0开始)。
  了解到uio_begin.sh文件所在的组为group6,然后通过group6中inode table起始地址 + uio_begin.sh的inode偏移就可计算出uio_begin.sh文件inode位置。
  (1)寻找偏移
  uio_begin.sh所在的inodetbl偏移:49155%8192 -1 = 2(inodes)
  一个inode大小为256B, so文件在inode table中的偏移为2*256B=512=0x200
  (2)找到group6中inode table的block,此处可以借助工具dumpe2fs /dev/ram0获取

Group 6: (Blocks 196608-229375)
  Block bitmap at 196608 (+0)
  Inode bitmap at 196609 (+1)
  Inode table at 196610-197121 (+2)
  32251 free blocks, 8189 free inodes, 1 directories
  Free blocks: 197122-198655, 198659-229375
  Free inodes: 49156-57344

从上面的信息可以看到group6中Inode table起始地址在block 196610,so,下面我们就dump出此inode table的内容瞧一瞧:
 
dd if=/dev/ram0 bs=4096 skip=196610 | hexdump -C -n 2048
sh-4.3# dd if=/dev/ram0 bs=4096 skip=196610 | hexdump -C -n 2048

00000000  e8 41 00 00 00 10 00 00  5a 91 53 5c 4a 91 53 5c  |.A......Z.S\J.S\|
00000010  4a 91 53 5c 00 00 00 00  00 00 02 00 08 00 00 00  |J.S\............|
00000020  00 00 00 00 00 00 00 00  00 08 03 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000060  00 00 00 00 ac 81 4d 5b  00 00 00 00 00 00 00 00  |......M[........|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000100  e8 81 00 00 c8 00 00 00  4a 91 53 5c 4a 91 53 5c  |........J.S\J.S\|
00000110  4a 91 53 5c 00 00 00 00  00 00 01 00 08 00 00 00  |J.S\............|
00000120  00 00 00 00 00 00 00 00  01 08 03 00 00 00 00 00  |................|
00000130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000160  00 00 00 00 ad 81 4d 5b  00 00 00 00 00 00 00 00  |......M[........|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200  e8 81 00 00 a8 00 00 00  4a 91 53 5c 4a 91 53 5c  |........J.S\J.S\|
00000210  4a 91 53 5c 00 00 00 00  00 00 01 00 08 00 00 00  |J.S\............|
00000220  00 00 00 00 00 00 00 00  02 08 03 00 00 00 00 00  |................|
00000230  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000260  00 00 00 00 ae 81 4d 5b  00 00 00 00 00 00 00 00  |......M[........|
00000270  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

  文件inode的偏移为0x200,我们看看inode中第一个字段是否符预期:
  inode的第一个成员字段为:

0x0 __le16 i_mode

  它占16个bit,其值为:0x41e8,即8进制的100750,
  即100000(表示regular file) | 750(访问权限),这与stat stat /ram/uio/uio_begin.sh结果一致:
  sh-4.3# stat /ram/uio/uio_begin.sh

  File: /ram/uio/uio_begin.sh
  Size: 168             Blocks: 8          IO Block: 4096   regular file
Device: 100h/256d       Inode: 49155       Links: 1
Access: (0750/-rwxr-x---)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2019-02-01 00:22:34.000000000
Modify: 2019-02-01 00:22:34.000000000
Change: 2019-02-01 00:22:34.000000000

三、从inode到文件数据块

  在文件较小的时候使用直接data block存储。这里就只考虑这种情况。
  inode主要包含两部分内容:文件属性和数据块指针(60Bytes),其中数据块指针放在inode->i_block[15]数组中:

0x28    60 bytes    i_block[EXT4_N_BLOCKS=15]

  通过偏移inode结构+偏移0x28,然后hexdump找到:

00000220  00 00 00 00 00 00 00 00  02 08 03 00 00 00 00 00  |................|

  第一个数据库块是0x00030802,即十进制229376

dd if=/dev/ram0 bs=4096 skip=198658 | hexdump -C -n 2048

  sh-4.3# dd if=/dev/ram0 bs=4096 skip=198658 | hexdump -C -n 2048

00000000  20 65 63 68 6f 20 30 30  30 30 3a 30 30 3a 30 33  | echo 0000:00:03|
00000010  2e 30 20 3e 20 2f 73 79  73 2f 62 75 73 2f 70 63  |.0 > /sys/bus/pc|
00000020  69 2f 64 72 69 76 65 72  73 2f 65 31 30 30 30 2f  |i/drivers/e1000/|
00000030  75 6e 62 69 6e 64 20 0a  20 65 63 68 6f 20 22 38  |unbind . echo "8|
00000040  30 38 36 20 30 78 31 30  30 65 22 20 3e 20 2f 73  |086 0x100e" > /s|
00000050  79 73 2f 62 75 73 2f 70  63 69 2f 64 72 69 76 65  |ys/bus/pci/drive|
00000060  72 73 2f 75 69 6f 5f 70  63 69 5f 67 65 6e 65 72  |rs/uio_pci_gener|
00000070  69 63 2f 6e 65 77 5f 69  64 20 0a 20 6c 73 20 2d  |ic/new_id . ls -|
00000080  6c 20 2f 73 79 73 2f 62  75 73 2f 70 63 69 2f 64  |l /sys/bus/pci/d|
00000090  72 69 76 65 72 73 2f 75  69 6f 5f 70 63 69 5f 67  |rivers/uio_pci_g|
000000a0  65 6e 65 72 69 63 2f 0a  00 00 00 00 00 00 00 00  |eneric/.........|
000000b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

然后我们验证一下里面的内容是否一致:
sh-4.3# cat /ram/uio/uio_begin.sh
 

echo 0000:00:03.0 > /sys/bus/pci/drivers/e1000/unbind
echo "8086 0x100e" > /sys/bus/pci/drivers/uio_pci_generic/new_id
ls -l /sys/bus/pci/drivers/uio_pci_generic/

  果然一致,牛逼。

四、从文件名定位文件

  如果我们只知道"/ram/uio/uio_begin.sh"这个字符串,在不借助"stat" 工具的情况下,如何找到uio_begin.sh的inode呢?
要回答上面的问题,我们首要讲几个事实。
  首先,系统中根目录文件"/"的inode号固定为2;
  其次,与普通文件类似,目录文件也有一个inode和至少一个用于存储数据的block,inode 记录该目录的相关权限属性以及数据block指针。
  不同的是,目录文件的数据block中存储的是记录在这个目录下的文件名与该文件名占用的inode号,具体如下:

struct ext2_dir_entry_2 {
    __le32    inode;            /* Inode number */
    __le16    rec_len;        /* Directory entry length */
    __u8    name_len;        /* Name length */
    __u8    file_type;
    char    name[];            /* File name, up to EXT2_NAME_LEN */
};

  我们来分解一下"/ram/uio/uio_begin.sh",它包含 根目录、目录ram、目录uio和普通文件uio_begin.sh总共4个文件。
  有了上面的知识,我们就可以先通过根目录"/"的inode号找到"/"的数据块;这个数据块中包含着目录文件"ram"的inode号和名字;
  有了"ram"的inode,就相当于有了"ram"数据---目录项,即可找到"uio"这个目录文件;
  同理,又可以通过"uio"数据块中存储的目录项最终定位到uio_begin.sh文件的inode号。
  找到uio_begin.sh文件的inode也就意味着我们只需重复上面的第二、第三节中的步骤即可。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值