1 Windows File System
1.1 Windows分区知识
因为保存主分区信息的MBR(Master Boot Record)只能容纳4个分区信息,也就是说只能有4个主分区。如果你想要更多的分区,只能将其中的一个主分区再划分,再划分出来的分区叫做逻辑分区,被划分的主分区又叫扩展分区,逻辑分区信息是保存在EBR(Extended Boot Record)里的。Linux系统中规定了主分区号为sda1-sda4或者hda1-hda4,而逻辑分区只能从sda5开始。
Q:U盘被识别为/dev/sda4,而不是sda1?
A:因为U盘的这个分区写在分区表(MBR DPT,Disk Partition Table)的第四项所以是sda4(DPT每个entry的第一个字节为引导标志,0x80表示活动分区,0x00表示非活动分区),可以用命令重新写到第一项。
sudo sfdisk -d /dev/sda > sda_table
gedit sda_table
sudo sfdisk /dev/sda < sda_table
或者
dd if=/dev/sda of=./mbr.bin bs=512 count=1
1.2 MBR
MBR分为GRUB.MBR和DOS.MBR。
由于硬盘上扇区从偏移0到偏移62属于同一个磁道0,虽然DOS.MBR仅占用一个扇区,但是需要将DOS.MBR后面的偏移1到偏移62保留,所以磁盘上第一个分区的第一个扇区是从偏移63开始的。
USB-ZIP和USB-FDD会将U盘的第一个扇区格式化成DOS.PBR而不是DOS.MBR。
USB-FDD和USB-ZIP的来历:软盘的容量小,没有分区结构,所以软盘是没有MBR的,整个软盘只有一个分区,第一个扇区就是PBR。
MBR实际上也是一个bootloader,可以使用如下命令获得MBR的内容
dd if=/dev/sda of=./mbr.bin bs=512 count=1
MBR:扇区内偏移地址0 ~ 0x1BD
DPT:DOS Partition Table,扇区内偏移地址0x1BE~ 0x1FD,其中又分为4个分区表:
第一个分区表:0x1BE ~ 0x1CD
第二个分区表:0x1CE ~ 0x1DD
第三个分区表:0x1DE ~ 0x1ED
第四个分区表:0x1EE ~ 0x1FD
DPT阐述
字节偏移 说明
0 引导标志。若值为80H表示活动分区,若值为00H表示非活动分区。
1-3 本分区的起始磁头号、扇区号、柱面号。其中:磁头号--第1字节;扇区号--第2字节的低6位;柱面号—为第2字节高2位+第3字节8位
4 分区类型符:
00H——表示该分区未用(即没有指定);
01h——FAT12基本分区
04H——FAT16基本分区
06H——big FAT16基本分区;
0BH——FAT32基本分区;
05H——扩展分区;
07H——NTFS分区;
0FH——(LBA模式)扩展分区(83H为Linux分区等)
5-7 本分区的结束磁头号、扇区号、柱面号。其中:
磁头号——第1字节;
扇区号——第2字节的低6位;
柱面号——第2字节的高2位+第3字节
8-11 分区起始扇区数,指分区相对于记录该分区的分区表的扇区位置之差 (该分区表:LBA = 0x0)
12-15 本分区的总扇区数
1.3 PBR
偏移量 字节数 含义
00--02H 3 跳转到引导代码
03--0AH 8 厂商标识和DOS版本
0B--0CH 2 BPB参数信息,每个扇区的字节数
0DH 1 每个分配簇的扇区数(2的整数倍)
0E--0FH 2 保留扇区数
10H 1 FAT个数
11--12H 2 根目录登记项数(所允许的最大数值)
13--14H 2 磁盘扇区总数
15H 1 磁介质类型说明
16--17H 2 每个FAT表所占的扇区数
18--19H 2 每个磁道(柱面)的扇区数
1A--1BH 2 磁头的个数
1C--1FH 4 当前DOS分区前面的隐含扇区数
27--2AH 4 FAT16格式磁盘系列号
2B--35H 10 FAT16卷标名
36--3AH 5 FAT16磁盘格式标志
1.4 python解析MBR和PBR
1.4.1 parse_mbr.py
import hashlib
import sys
import os
# dd if=/dev/block/sda of=/data/mbr.hex bs=512 count=1
def print_usage():
print("Usage:\n" + sys.argv[0] + " MBR file\n")
def parse_mbr():
f = open(sys.argv[1], 'r')
# PART 1
print("PART 1")
offset = 0x1be
f.seek(offset)
str_data = f.read(16)
print(" ".join(hex(ord(n)) for n in str_data))
print("boot: %r" % str_data[0])
print("FS Type: %r" % str_data[4])
# PART 2
print("\nPART 2")
offset = 0x1ce
f.seek(offset)
str_data = f.read(16)
print(" ".join(hex(ord(n)) for n in str_data))
print("boot: %r" % str_data[0])
print("FS Type: %r" % str_data[4])
# PART 3
print("\nPART 3")
offset = 0x1de
f.seek(offset)
str_data = f.read(16)
print(" ".join(hex(ord(n)) for n in str_data))
print("boot: %r" % str_data[0])
print("FS Type: %r" % str_data[4])
# PART 4
print "\nPART 4"
offset = 0x1ee
f.seek(offset)
str_data = f.read(16)
print(" ".join(hex(ord(n)) for n in str_data))
print("boot: %r" % str_data[0])
print("FS Type: %r" % str_data[4])
f.close()
if __name__ == '__main__':
if len(sys.argv) < 2:
print_usage()
exit()
parse_mbr()
1.4.2 parse_pbr.py
import hashlib
import sys
import os
# dd if=/dev/block/sda1 of=/data/pbr.hex bs=512 count=1
def print_usage():
print("Usage:\n" + sys.argv[0] + " PBR file\n")
# http://elm-chan.org/docs/fat_e.html
def parse_pbr():
f = open(sys.argv[1], 'rb')
offset = 0
f.seek(offset)
str_data = f.read(3)
print("Boot Code: " +
" ".join(hex(ord(n)) for n in str_data))
str_data = f.read(8)
print("DOS Ver: " + str_data)
str_data = f.read(2)
print("Bytes per Sector: " +
" ".join(hex(ord(n)) for n in str_data))
str_data = f.read(1)
print("Sectors per Cluster: " +
" ".join(hex(ord(n)) for n in str_data))
str_data = f.read(2)
print("Num of Reserved Sectors: " +
" ".join(hex(ord(n)) for n in str_data))
str_data = f.read(1)
print("Num of FAT: " +
" ".join(hex(ord(n)) for n in str_data))
str_data = f.read(2)
print("FAT12/16 - Num of Root Dirs: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 0x13
f.seek(offset)
str_data = f.read(2)
print("FAT12/16 - Num of Sectors: " +
" ".join(hex(ord(n)) for n in str_data))
str_data = f.read(1)
print("Media Type: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 0x16
f.seek(offset)
str_data = f.read(2)
print("FAT12/16 - Sectors per FAT: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 0x1C
f.seek(offset)
str_data = f.read(4)
print("Hide Sectors before EBR: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 0x20
f.seek(offset)
str_data = f.read(4)
print("Num of Huge Sectors: " +
" ".join(hex(ord(n)) for n in str_data))
print("\n")
offset = 39
f.seek(offset)
str_data = f.read(4)
print("FAT12/16 - Volume ID: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 43
f.seek(offset)
str_data = f.read(11)
print("FAT12/16 - Label: " + str_data)
offset = 54
f.seek(offset)
str_data = f.read(8)
print("FAT12/16 - FS Type: " + str_data)
print "\n"
offset = 36
f.seek(offset)
str_data = f.read(4)
print("FAT32 - Sectors per FAT: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 44
f.seek(offset)
str_data = f.read(4)
print("FAT32 - Root Cluster: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 0x43
f.seek(offset)
str_data = f.read(4)
print("FAT32 - Volume ID: " +
" ".join(hex(ord(n)) for n in str_data))
offset = 0x47
f.seek(offset)
str_data = f.read(11)
print("FAT32 - Label: " +
" ".join(hex(ord(n)) for n in str_data) +
", " + str_data)
offset = 0x52
f.seek(offset)
str_data = f.read(8)
print("FAT32 - FS Type: " +
" ".join(hex(ord(n)) for n in str_data) +
", " + str_data)
f.close()
if __name__ == '__main__':
if len(sys.argv) < 2:
print_usage()
exit()
parse_pbr()
1.5 FAT32分配单元大小
FAT32分配单元大小 - 簇的大小,譬如16KB,命令chkdsk f:\
2 Linux文件系统
2.1 GRUB简介
GRUB镜像组成:
- GRUB.MBR(boot.img)
- 硬盘扇区offset 1 到offset 62放置GRUB的core.img
- /boot分区的boot/grub/grub.cfg
2.2 block设备性能分析工具
CONFIG_BLK_DEV_IO_TRACE
@ external/e2fsprogs/debugfs
@ external/blktrace
需要加下面的声明在blkparse.c,否则编译出错。
extern int strverscmp (const char *s1, const char *s2);
blktrace -d /dev/block/sda -o - | blkparse -i - -o /data/blk.parsed
根据扇区offset找到具体的文件:
ls -l /dev/block
debugfs -R "stats" /dev/block/sda1 |grep "Block size"
BLKNO=SECTOR_OFFSET/8
debugfs -R "icheck $BLKNO" /dev/block/sda1
GOT THE INODE NUMBER FROM THE LAST CMD: 9
debugfs -R "ncheck 9" /dev/block/sda1
2.3 iodump
iodump可以显示fullpath。
2.4 Linux command
fdisk -l /dev/block/sda
fdisk -l mbr.img
gdisk -l gpt.img
2.5 EXT4 Encryption
CE: Credential Encrypted
DE: Device Encrypted
ENOKEY: Required key not available
FBE:File-Based Encryption,加密的仅仅是文件内容和文件名,其他的信息比如文件大小,权限等都没有加密,这些内容就是filesystem metadata
Metadata分区:加密文件大小,权限等除了文件内容和文件名之外的文件信息,/metadata/vold/metadata_encryption/key
github ext4-crypt
add_key() - e4crypt add_key
keyctl_search()
keyctl_unlink()
3 Abbreviations
DPT: Disk Partition Table
EBR: Extended Boot Record
MBR: Master Boot Record
PBR: Partition Boot Record