文章目录

  • 简介
  • 使用的函数
    • 1.CreateFile()函数打开设备
    • 2.DeviceIoControl()函数返回磁盘设备信息
    • 3.SetFilePointer()函数设置读取磁盘信息位置
    • 4.ReadFile()函数读取磁盘内容
  • 源代码
  • 结果分析
    • MBR部分:
    • 第一个EBR的DPT内容为:
    • 第2个EBR内容
  • 总结

简介

  在win8以后,磁盘格式一般是GPT格式的,做实验是在winXP虚拟机上完成的,partition style是MBR。在虚拟机上分配了40GB的硬盘空间。三个主分区盘C、E、F,一个扩展分区里面有三个逻辑盘G、H、I。

使用的函数

1.CreateFile()函数打开设备

HANDLE CreateFile(
  LPCSTR lpFileName,
   DWORD dwDesiredAccess,
   DWORD dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD dwCreationDisposition,
  DWORD dwFlagsAndAttributes,
  HANDLE hTemplateFile
);

  • 第1个参数lpFileName为要创建或打开的文件或设备的名称。磁盘为TEXT("\\.\PhysicalDrive0"),如果有两个盘,第2个为1。
  • 第2个参数dwDesiredAccess为请求访问文件或设备,常取值为GENERIC_READ, GENERIC_WRITE或两者(GENERIC_READ | GENERIC_WRITE)
  • 第3个参数为dwShareMode,是请求的文件或设备共享模式,可以是读取,写入,两者,删除
  • 第4个参数为lpSecurityAttributes,是指向SECURITY_ATTRIBUTES 结构的指针,如果此参数为NULL,则CreateFile返回的句柄不能由应用程序可能创建的任何子进程继承,使用默认安全属性。
  • 第5个参数dwCreationDisposition,对存在或不存在的文件或设备执行的操作。对于文件以外的设备,此参数通常设置为OPEN_EXISTING。
  • 第6个参数为dwFlagsAndAttributes,是文件或设备属性和标志。
  • 第7个参数为hTemplateFile,具有GENERIC_READ访问权限的模板文件的有效句柄。此参数可以为NULL。
  • 返回值:如果函数成功,则返回值是指定文件,设备,命名管道或邮件槽的打开句柄。如果函数失败,则返回值为INVALID_HANDLE_VALUE。获取错误码,可以调用GetLastError()函数。

2.DeviceIoControl()函数返回磁盘设备信息

BOOL DeviceIoControl(
  HANDLE hDevice,
  DWORD dwIoControlCode,
  LPVOID lpInBuffer,
  DWORD nInBufferSize,
  LPVOID lpOutBuffer,
  DWORD nOutBufferSize,
  LPDWORD lpBytesReturned,
  LPOVERLAPPED lpOverlapped
);

  • 第1个参数为hDevice,是要对其执行操作的设备的句柄,本实验中是CreateFile()函数的返回的设备句柄。
  • 第2个参数dwIoControlCode,是操作的控制代码,该值标识要执行的特定操作以及执行它的设备类型。使用IOCTL_DISK_GET_DRIVE_GEOMETRY,用于获取磁盘信息。
  • 第3个参数为lpInBuffer,是指向输入缓冲区的指针,可以为NULL。
  • 第4个参数为nInBufferSize,是输入缓冲区大小,以字节为单位。
  • 第5个参数为lpOutBuffer,指向输出缓冲区的指针,用于接收操作返回的数据。
  • 第6个参数为nOutBufferSize,是输出缓冲区的大小,以字节为单位。
  • 第7个参数为lpBytesReturned,是一个指向变量的指针,该变量接收存储在输出缓冲区中的数据大小(以字节为单位)。如果输出缓冲区太小而无法接收任何数据,则调用失败, GetLastError()返回 ERROR_INSUFFICIENT_BUFFER,并且lpBytesReturned为零。
  • 第8个参数为lpOverlapped,指向OVERLAPPED结构的指针。如果在未指定FILE_FLAG_OVERLAPPED的情况下打开 hDevice,则忽略lpOverlapped。
  • 返回值:如果操作成功完成,则返回值为非零值。

3.SetFilePointer()函数设置读取磁盘信息位置

DWORD SetFilePointer(
HANDLE hFile,
LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod
);

  • 第1个参数hFile是文件的句柄。
  • 第2个参数为lDistanceToMove,是表示距离的有符号数的低32位,用来指定文件指针的字节偏移。
  • 第3个参数lpDistanceToMoveHigh,是距离的高32位。
  • 第4个参数dwMoveMethod是文件指针移动的起点。

4.ReadFile()函数读取磁盘内容

BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);

  • 第1个参数hFile,是文件/设备句柄。
  • 第2个参数lpBuffer,是指向缓冲区的指针,用于接收读取的数据。
  • 第3个参数nNumberOfBytesToRead,是要读取的最大字节数。
  • 第4个参数lpNumberOfBytesRead,用于接收读取的字节数。
  • 第5个参数lpOverlapped可以为NULL。

源代码

#include <windows.h>
#include <winioctl.h> //DDK驱动开发与控制
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#define BufferLength 1024//将四个连续字节存放的值转为int型
uint32_t transtoint(unsigned char a[])
{uint32_t sum = 0UL;uint32_t temp = 0UL;for (int i = 3; i>=0; i--){temp = a[i];//先赋值                temp = temp <<( 8 * (3-i));      sum = sum | temp;}return sum;
}
//十六进制输出
bool HexOutput(char* buf, size_t len,bool ismbr, ULONGLONG * baseaddr,ULONGLONG * nextaddr,int EBRnum)
{bool mbrflag=1;//在读取MBR的时候判断条目是主分区还是扩展分区条目 unsigned char a = buf[0];if(ismbr)printf("-----------------------------------------------------");elseprintf("--------------------------第%d个EBR------------------",EBRnum);//printf("第一字节是:%x\n\n", a);if(ismbr)printf("          第一部分(MBR):\n\n");elseprintf("          第一部分(EBR):\n\n");int flag = 0;for (size_t i = 0; i < len; ++i){unsigned char c = buf[i]; // must use unsigned char to print >128 value flag++;if (c < 16)printf("0%x ", c);elseprintf("%x ", c);if (i == 445){flag = 0;printf("\n\n          第二部分(分区表):\n");}if (i == 509){flag = 0;printf("\n\n          第三部分(结束标志):\n");}if ((flag) % 16 == 0)printf("\n");}printf("\n<-------------------分区表信息解析------------------->\n\n");printf("\n\n分区地址和大小分别为: \n\n");   int limit=ismbr?509:477;//如果已经知道是扩展分区的EBR,不用读取那么多,rank=1是分区表,rank=2是指向下一个的for (int m = 445, rank = 1; m < limit&&rank<=4; m += 16, rank++){unsigned char fifth = buf[m + 5];//取得第五位文件系统标志位,十六进制为05H或者0FH是扩展分区        if(fifth==0x5||fifth==0xf)//是扩展分区条目,不用往后读了 {printf("This is an extend patition!\n");mbrflag=0;    rank = 4;}//不是mbr是扩展分区EBR if (fifth < 16) //调整输出格式printf("第%d分区表标志位为: 0%x\n", rank, fifth);elseprintf("第%d分区表标志位为: %x\n", rank, fifth);if (fifth == 0x00)//当第五位(标志位)是00时,代表分区表信息为空,无分区{printf(" 分区表为空\n\n");//也不用往后读了 }else {//分区项 unsigned char offsetadd[4] = { 0 };//倒着读,高字节在高地址处for (int n = m + 12, t = 0; n > m + 8, t < 4; n--, t++){unsigned char temp = buf[n];if (temp < 16)printf("  0%x  ", temp);elseprintf("  %x  ", temp);offsetadd[t] = buf[n];}//计算地址,转换为十进制扇区数LBAprintf("\n");uint32_t tempadd = transtoint(offsetadd);printf("\n开始地址为: %I64x", (ULONGLONG)tempadd * (ULONGLONG)512 + *baseaddr);if(ismbr&&!mbrflag)// if in mbr and got a extend entry,the EBR at relsecor+nowbase(0){*baseaddr=(ULONGLONG)tempadd* (ULONGLONG)512 + *baseaddr;//only change once*nextaddr = (ULONGLONG)0UL;}               else if (!mbrflag)//if it's the extend entry{*nextaddr = (ULONGLONG)tempadd * (ULONGLONG)512;}printf("\n\n");printf("大小:");for (int p = m + 16, w = 0; p > m + 12, w < 4; p--, w++){unsigned char temp1 = buf[p];if (temp1 < 16)printf("  0%x  ", temp1);elseprintf("  %x  ", temp1);offsetadd[w] = buf[p];}//计算大小,转化为GB单位printf("\n");uint32_t tempsize = transtoint(offsetadd);if(ismbr && !mbrflag)printf("\n扩展盘总大小为: %lu 扇区 = %lf GB \n", tempsize, ((double)tempsize / 2.0 / 1024.0 / 1024.0));else if(!ismbr){printf("\n第%d逻辑盘大小为: %lu 扇区 = %lf GB \n",EBRnum, tempsize, ((double)tempsize / 2.0 / 1024.0 / 1024.0));}elseprintf("\n该盘大小为: %lu 扇区 = %lf GB \n", tempsize, ((double)tempsize / 2.0 / 1024.0 / 1024.0));}}printf("\n\n");return (mbrflag);
}//函数:对主分区表进行解析,分别得到每个分区的偏移地址以及分区大小
BOOL GetDriveGeometry(DISK_GEOMETRY *pdg, int addr)
{HANDLE hDevice;               // 设备句柄BOOL bResult;                 // results flagDWORD junk;                   // discard resultsccchar lpBuffer[BufferLength] = { 0 };//通过CreateFile来获得设备的句柄hDevice = CreateFile(TEXT("\\\\.\\PhysicalDrive0"), // 设备名称,这里指第一块硬盘GENERIC_READ,                // no access to the driveFILE_SHARE_READ | FILE_SHARE_WRITE,  // share modeNULL,             // default security attributesOPEN_EXISTING,    // disposition0,                // file attributesNULL);            // do not copy file attributesif (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive{printf("Creatfile error!May be no permission!ERROR_ACCESS_DENIED!\n");return (FALSE);}//通过DeviceIoControl函数与设备进行IObResult = DeviceIoControl(hDevice, // 设备的句柄IOCTL_DISK_GET_DRIVE_GEOMETRY, // 控制码,指明设备的类型NULL, 0, // no input bufferpdg,sizeof(*pdg),     &junk,                 // # bytes returned(LPOVERLAPPED)NULL); // synchronous I/OLARGE_INTEGER offset;//long long signedoffset.QuadPart = (ULONGLONG)addr * (ULONGLONG)512;//0SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);//从0开始读MBRif(GetLastError())printf("错误类型代号:%ld\n\n", GetLastError());//如果出错了DWORD dwCB;//从这个位置开始读 BOOL bRet = ReadFile(hDevice, lpBuffer, 512, &dwCB, NULL);//如果不是MBR,bool finished=0; int EBRnum=0;ULONGLONG *baseaddr=new ULONGLONG,*nextaddr= new ULONGLONG;//扩展分区起始地址,EBR地址 *baseaddr = (ULONGLONG)0;*nextaddr = (ULONGLONG)0;finished=HexOutput(lpBuffer, 512,true,baseaddr,nextaddr,EBRnum);//先是读取MBRif(finished)CloseHandle(hDevice);else{//继续读do{EBRnum++;memset(lpBuffer, 0, sizeof(lpBuffer));offset.QuadPart = (ULONGLONG)(*baseaddr + *nextaddr);//find the EBRSetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);//读EBRif(GetLastError())printf("错误类型代号:%ld\n\n", GetLastError());//如果出错了ReadFile(hDevice, lpBuffer, 512, &dwCB, NULL);}while(!HexOutput(lpBuffer, 512,false,baseaddr,nextaddr,EBRnum));CloseHandle(hDevice);}delete baseaddr;delete nextaddr;return bResult;
}
extern int add[20];
extern int disknum;
int main()
{DISK_GEOMETRY pdg;            // 保存磁盘参数的结构体BOOL bResult;                 // generic results flagULONGLONG DiskSize;           // size of the drive, in bytesprintf("<-----------------欢迎使用分区读取程序----------------->\n\n");bResult = GetDriveGeometry(&pdg, 0);if (bResult){DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *(ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;printf("磁盘总大小 = %I64d (Bytes) = %I64d (Gb)\n", DiskSize, DiskSize / (1024 * 1024 * 1024));}else{printf("GetDriveGeometry failed. Error %ld.\n", GetLastError());}return ((int)bResult);
}

结果分析

运行程序解析磁盘信息的结果,与使用Winhex查看计算是一致的。

MBR部分:

分区地址和大小分别为:

第1分区表标志位为: 07
00 00 00 3f
开始地址为: 7e00
大小: 02 7f 8c b2
该盘大小为: 41913522 扇区 = 19.985925 GB

第2分区表标志位为: 07
02 7f 8c f1
开始地址为: 4ff19e200
大小: 00 3f fa c5
该盘大小为: 4192965 扇区 = 1.999362 GB

第3分区表标志位为: 07
02 bf 87 b6
开始地址为: 57f0f6c00
大小: 00 3f fa c5
该盘大小为: 4192965 扇区 = 1.999362 GB

This is an extend patition!
第4分区表标志位为: 0f
02 ff 82 7b
开始地址为: 5ff04f600
大小: 02 00 53 aa
扩展盘总大小为: 33575850 扇区 = 16.010213 GB

查看C盘信息,开始地址7E00,20G:

查看E盘信息,开始抵制4FF19E200,大小2G:

查看F盘信息,开始地址57F0F6C00,大小2G:

查看第4个DPT对应的扩展分区的EBR,扩展分区的EBR所在地址位5FF04F600:

第一个EBR的DPT内容为:


  第一个条目地址信息中3F 00 00 00是63,指向第一个逻辑盘。计算这个逻辑盘开始地址为63*512=7E00H,加上5FF04F600H得到5FF057400H,这就是G盘的起始位置。G盘的大小信息为0E 12 A0 00,也就是10490382个扇区,10490382*512/1024/1024/1024=5GB。

  第2个条目是第5个字节内容是05H,表示是扩展分区。(之前MBR中的第4个扇区第5字节是0FH,也表示这是一个扩展分区)。扩展分区的地址信息为A0124DH,也就是相对于扩展分区开始位置5FF04F600H起的第10490445个扇区(换成字节是140249A00H)处存放着下一个扩展分区的MBR。这个位置是140249A00H+5FF04F600H =73F299000H。在这个位置,的确放着下一逻辑盘,也就是H盘的EBR。用同样方式可以计算。
 

第1分区表标志位为: 07
00 00 00 3f
开始地址为: 5ff057400
大小: 00 a0 12 0e
第1逻辑盘大小为: 10490382 扇区 = 5.002204 GB

This is an extend patition!
第2分区表标志位为: 05
00 a0 12 4d
开始地址为: 73f299000
大小: 00 a0 12 4d
第1逻辑盘大小为: 10490445 扇区 = 5.002234 GB

第2个EBR内容

分区地址和大小分别为:
第1分区表标志位为: 07
00 00 00 3f
开始地址为: 5ff057400
大小: 00 a0 12 0e
第2逻辑盘大小为: 10490382 扇区 = 5.002204 GB

This is an extend patition!
第2分区表标志位为: 05
01 40 24 9a
开始地址为: 87f4e2a00
大小: 00 c0 2f 10
第2逻辑盘大小为: 12594960 扇区 = 6.005745 GB

总结

  MBR的四个分区表的组合有两种:全部是主分区;三个主分区+一个扩展分区。在阅读分区表条目的时候,(从第1字节开始)第5字节中存放的信息也比较重要,如果是05H或者是0FH,表示这是一个扩展分区条目,地址信息指向的是EBR,否则如果不是0,就是一个主分区条目,指向的是每个主分区的开始扇区。如果是在EBR中,在扩展分区表部分,只有前两个条目有效,最后两个是全为0的没有用到,第1个条目指向了目前已经发现了的逻辑盘,第2个条目如果不是全0,说明还有下一个逻辑盘,指向的就是下一个EBR。
  地址信息Relative在主分区中,是0。在扩展分区中,是主扩展分区的开始位置所在扇区,可以从MBR中获取到。而Sectors指的是分区占的总扇区数,在MBR中,第4个如果是扩展分区的话,表示是整个扩展分区里面所有逻辑盘的大小。
  自己电脑的分区逻辑图如图所示:


PS:程序写的时候有的显示BUG这种就没有改了。。。。。

C语言读取磁盘分区信息(MBR、DPT、EBR)相关推荐

  1. 两种磁盘分区形式MBR(只支持4个主分区)和GPT

    两种磁盘分区形式MBR(只支持4个主分区)和GPT: MBR: master boot record(主引导记录),存在于驱动器开始部分的特殊启动扇区,是存在于驱动器开始部分的一个特殊启动扇区,包括已 ...

  2. linux服务器引导分区,Linux系统的引导过程和磁盘分区信息

    Linux系统的引导过程和磁盘分区信息 作者:chinaitlab 佚名 2005-12-07 00:00 评论 分享 [IT168 服务器学院] 系统的引导过程和磁盘分区信息 在PC机上,最初的启动 ...

  3. 磁盘分区格式(MBR分区和GPT分区)和启动引导模式(Legacy和UEFI)的关系

    文章目录 1. 专业名词概览 2. 磁盘分区格式:MBR分区和GPT分区 2.1 简介 2.2 区别 3. 启动引导模式:Legacy BIOS和UEFI BIOS 3.1 Legacy BIOS的启 ...

  4. 使用partx重读磁盘分区信息及自动挂载分区的方法

    在之前的帖子<Linux调整分区后Grub修复>中提到,Linux调整磁盘分区大小后会出现Grub引导损坏的问题,可以参考那篇帖子中的方法,进入grub rescue进行修复. 但是修复后 ...

  5. Linux 磁盘分区(MBR和GPT,loop详细分区方法介绍)

    磁盘分区和格式化操作是比较接近硬件底层的操作,这两个操作也是至关重要的,决定了磁盘的使用效率和磁盘的数据安全.(相信现在应该没有什么特别的需要,一般都已经抛弃了ext2,ext4文件格式了吧~~~~, ...

  6. 磁盘分区方式——MBR与GPT之学习笔记

    大数据时代,硬盘作为数据存储工具,是生产生活中必不可少的工具.在数据日益繁多的情况下,如何让对数据进行有效管理变得愈发重要.磁盘分区,是对数据进行有效管理的重要手段之一. 磁盘分区,就是使用分区编辑器 ...

  7. linux mbr 分区表修复,磁盘分区中MBR的模拟损坏及修复

    目前对于硬盘的分区方式有两种:MBR和GPT.本文只是为了介绍分区中的MBR的备份和恢复,所以不对GPT分区做过多的介绍. 我们先来对MBR的分区方式进行一个简单的介绍: 上图说明: 采用MBR分区的 ...

  8. linux:查看磁盘分区信息和文件系统格式

    查看实例上的数据盘信息(GPT/MBR) 磁盘标签类型对应: dos => MBR gpt => GPT # fdisk -l磁盘 /dev/vda:42.9 GB, 4294967296 ...

  9. linux分区语言,Linux磁盘分区(9)-Go语言中文社区

    分区的基础知识: 模式:mbr分区: 1.最多支持四个主分区 2.系统只能安装主分区 3.扩展分区要占一个主分区 4.MBR最大只支持2TB,但拥有最好的兼容性 gtp分区: 1.支持无限多个主分区( ...

最新文章

  1. checkstyle安装使用
  2. 19 java程序员面试宝典视频课程之正则表达式
  3. 这是自动驾驶的战国时期,也是技术发展的黄金时期
  4. python软件开发-如何编写Python软件开发文档(7个技巧)
  5. mongod副本集的安装配置
  6. 重置npm设置_密码重置用户流程4部曲
  7. java jdk 序列化_JDK 11:Java序列化的终结开始了吗?
  8. numpy T、transpose()函数、swapaxes()函数
  9. day28 java的集合(6)Properties和TreeSet
  10. 俄罗斯方块-C语言-完整代码
  11. php smarty入门,smarty教程专题
  12. coco2d-x 3.0游戏实例学习笔记 《跑酷》 第二步---游戏界面amp;全新的3.0物理世界...
  13. Redis的持久化操作---RDBAOF
  14. linux系统可以装access吗,安装华为FusionAccess Linux版本的方法
  15. 报错:npm ERR code EPERM
  16. 噪声为什么是高频信号_人类是信号,但科技将我们视为噪音
  17. 物联网常用协议:MQTT、CoAP、LwM2M、HTTP、LoRaWAN和NB-IoT
  18. cesium 三维坐标系绘制
  19. 网络属性里的残留网络服务卸载错误0x8007007e导致卡巴斯基安装到klim6.sys错误27300回滚
  20. 自学python(mac)----读写文件

热门文章

  1. 目标检测经典算法和API详解(笔记)
  2. android 删除号码恢复,手机联系人误删了怎么恢复
  3. Java中面试官常问问题
  4. mysql不停机主从配置
  5. 我方卧底发自美团的真实Android资料
  6. 千万别再用pyinstaller打包idle了!
  7. [爬虫架构] 如何在分布式爬虫架构中动态维护一个代理IP池(付费代理)
  8. 盛大借助Bambook程序达人赛推开放平台
  9. 热水器进水阀与角阀连接处漏水
  10. 干掉“我的电脑”中超级解霸V8的图标