开始先说下DBR, DBR是继MBR 之后最先访问的地方,MBR利用int 13h 读取MBR并将之加载到物理地址0x7c00的地方. 然后将段地址:代码地址入栈后retf跳过去运行.
MBR利用BIOS中断int 13h读取数据加载到内存指定位置..传统的int 13h调用最多只能识别1024个磁头:
前面MBR讲解MBR的时候,有结构如下
/*+0x01*/ uchar StartHead; // 分区起始磁头号 (1磁头 = 63 扇区,取值 0~255 之间)
/*+0x02*/ uint16 StartSector:10; // 启始柱面号 10位 (1柱面 = 255 磁头,取值 0~1023 之间)
/*+0x02*/ uint16 StartCylinder:6; // 启始扇区号 6位 (取值 1 到 63 之间)
此结构可容纳最大值为FF FF FF (现在这个值基本都写成FE FF FF, 而废弃不用), 即最大能寻址的就是255柱面, 1023磁头, 63扇区,计算扇区个数为:
1023*255*63+255*63+63 = 16450623
再按每扇区 512 字节算, 那么它容量为 8 GB ≈ 512*16450623 B = 7.84 GB
传统的int 13h中断就受限于8G的限制, Microsoft等多家公司制定了int 13h扩展标准,让int 13h读写磁盘中断可以突破8G限制. 现在的计算机BIOS都是按扩展int 13h标准编写的代码.(具体详细内容可参考"扩展 int 13h规范").
按MBR分区表里面的 SectionPrecedingPartition 逻辑扇区偏移(注意,这个逻辑扇区偏移是从0开始算的,读取出来值为63,而物理扇区是从1开始计算的,逻辑扇区转换物理扇区的时候必须+1才是正确的) 可以找到DBR的位置.可以看看winhex的显示
以下就偷懒不从MBR寻址分区的DBR了,而是直接打开盘符读取 (这样打开的第一个扇区就是DBR),这样做有个缺点,就是你用这个handle值将不能进行内存映射,只能一次多读取几个扇区来加快分析磁盘的速度(当前用的是一次读取20M数据然后分析)。
- HANDLE handle = CreateFile ( TEXT("\\.\C:") ,
- GENERIC_READ,
- FILE_SHARE_READ|FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
DBR结构定义为(对照winhex模板信息查看):
- ////////////////////////////////////////////////////////////////////////////
- //
- // NTFS 的DBR 数据结构
- //
- ////////////////////////////////////////////////////////////////////////////
- typedef struct _BIOS_PARAMETER_BLOCK {
- /*+0x0B*/ uint16 BytesPerSector; // 字节/扇区一般为0x0200 即512
- /*+0x0D*/ uchar SectorsPerCluster; // 扇区/簇
- /*+0x0E*/ uint16 ReservedSectors; // 保留扇区
- /*+0x0F*/ uchar Fats; //
- /*+0x11*/ uint16 RootEntries; //
- /*+0x13*/ uint16 Sectors; //
- /*+0x15*/ uchar Media; // 媒介描述
- /*+0x16*/ uint16 SectorsPerFat; //
- /*+0x18*/ uint16 SectorsPerTrack; // 扇区/磁轨
- /*+0x1A*/ uint16 Heads; // 头
- /*+0x1C*/ uint32 HiddenSectors; // 隐藏扇区
- /*+0x20*/ uint32 LargeSectors; // checked when volume is mounted
- }BIOS_PARAMETER_BLOCK, *pBIOS_PARAMETER_BLOCK;
- typedef struct _NTFS_Boot_Sector{
- /*+0x00*/ uchar JmpCode[3]; // 跳转指令
- /*+0x03*/ char OemID[8]; // 文件系统ID
- /*+0x0B*/ BIOS_PARAMETER_BLOCK PackedBpb; // BPB
- /*+0x24*/ uchar Unused[4]; // 未使用,总是为
- /*+0x28*/ uint64 NumberSectors; // 扇区总数
- /*+0x30*/ lcn MftStartLcn; // 开始C# $MFT (簇) 乘以 BIOS_PARAMETER_BLOCK.SectorsPerCluster 值得到扇区号
- /*+0x38*/ lcn Mft2StartLcn; // 开始C# $MFTMirr (簇)
- /*+0x40*/ uchar ClustersPerFileRecordSegment; // 文件记录大小指示器
- /*+0x41*/ uchar Reserved0[3]; // 未使用
- /*+0x44*/ uchar DefaultClustersPerIndexAllocationBuffer; // 簇/索引块
- /*+0x45*/ uchar Reserved1[3]; // 未使用
- /*+0x48*/ uint64 SerialNumber; // 64位序列号
- /*+0x50*/ uint32 Checksum; // 校验和
- /*+0x54*/ uchar BootStrap[426]; // 启动代码
- /*+0x1FE*/ uint16 RecordEndSign; // 0xAA55 结束标记
- }NTFS_Boot_Sector, *pNTFS_Boot_Sector;
在读取DBR的时候,一些数据以后经常会用到,那么需要根据DBR里面的信息保存以后会用到的信息,下面定义一个常用的保存信息结构:
- // 保存 NTFS 的基本信息
- typedef struct _NTFS_INFO
- {
- uint32 BytesPerSector; // 每扇区的字节数
- uint32 SectorsPerCluster; // 每簇的扇区数
- uint32 BytesPerCluster; // 每簇的字节数
- uint64 SectorCount; // 扇区总数
- uint64 MftStart; // MFT表开始簇
- uint64 MftMirrStart; // MFT备份表开始簇
- uint32 BytesPerFileRecord; // 每个文件记录的字节数一般为512*2
- uint16 VolumeLabelLength; // 卷名长度,卷名从MFT第4个项0x60属性得到(与0x30属性相似)
- wchar VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH]; // 卷名
- uint16 vcnlen;
- uchar vcn[VCN_LENTH];
- } NTFS_INFO, *PNTFS_INFO;
其中 MAXIMUM_VOLUE_LABEL_LENGTH定义为
- #define MAXIMUM_VOLUME_LABEL_LENGTH (32*sizeof(wchar))
NTFS_Boot_Sector .MftStartLcn*NTFS_Boot_Sector. PackedBpb .SectorsPerCluster得到MFT所在扇区号,这里为 786432*8 = 6291456扇区(字节偏移为 6291456*512= 3221225472 ( 十六进制0xC0000000))。然后MFT表里面的内容是根据簇号来读取数据的,那么可以定义一个根据簇号,读取数据的函数,如下形式:
- typedef struct _Partition_Stand_Post
- {
- HANDLE handle; // 分区句柄
- uint64 CluNnum; // 簇号
- uint32 BytesPerCluster; // 每簇字节
- uint64 CluCount; // 簇数量
- PNTFS_INFO NtfsInfo; // 指向NTFS_INFO 结构
- }Partition_Stand_Post, *pPartition_Stand_Post;
- // 按簇读取数据,
- // 传入 一个Partition_Stand_Post结构体指针,并指定buf,读取大小
- // 结果返回读取的数据指针
- PBYTE ReadClues(pPartition_Stand_Post post, PBYTE buf, DWORD lenth)
- {
- DWORD dwbytes = 0;
- LARGE_INTEGER li = {0};
- li.QuadPart = post->CluNnum*post->BytesPerCluster;
- SetFilePointer(post->handle, li.LowPart, &li.HighPart, FILE_BEGIN);
- ReadFile(post->handle, buf, lenth, &dwbytes, NULL);
- if (lenth == dwbytes)
- {
- return buf;
- }
- return NULL;
- }
原文:http://blog.csdn.net/jha334201553/article/details/9089119