【Win32】磁盘直接读写扇区


参考地址:http://blog.csdn.net/zuishikonghuan/article/details/50380313

一般的程序不会直接去访问磁盘,毕竟有文件系统(FileSystem)帮助我们轻松地组织文件,但是有时候必须访问磁盘,因为文件系统隐藏了低层次的实现,linux人喜欢把文件系统叫做“虚拟文件系统(VFS)”,其实原因就在这里,比如我们把一个文件从一个分区复制到另一个分区(其实就是从一个分区中读取文件再向另一个分区写入文件,当然一般是分段读取写入的,或者是用虚拟内存(线性地址空间)映射文件),我们不需要关心磁盘上分区的组织方法,比如MBR格式或GPT格式,也不需要关心分区对数据的组织方式,不管是FAT32,NTFS,exFAT,ext2/3/4格式等等,这就是文件系统的魅力所在。咳咳,扯的有点远哈,回归正题,我们的目的是绕过文件系统,直接访问磁盘上的扇区,就像市面上的PE盘制作器一样,可以把引导程序写人U盘的主引导扇区(第一个扇区,一般是512字节)。

演示一下将第一块磁盘的主引导扇区读出来,写的话把ReadFile换成WriteFile,再稍微改下代码就可以了,对了,用BIOS引导系统的看官千万别乱写啊,写坏了MBR就引导不了系统了,修复很麻烦的,用UEFI引导系统的随便写,不怕,因为UEFI不从MBR加载引导程序,这也是UEFI天生免疫鬼影病毒的原因之一。

#include "stdafx.h"
#include<Windows.h>
 
//参数:输出的字符串指针,开始位置,长度
//返回值:读取的大小
DWORD ReadDisk(unsigned char* &out,DWORD start,DWORD size)
{
OVERLAPPED over = { 0 };
over.Offset = start;
HANDLE handle = CreateFile(TEXT("\\\\.\\PHYSICALDRIVE0"), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE)return 0;
unsigned char* buffer = new unsigned char[size + 1];
DWORD readsize;
if (ReadFile(handle, buffer, size, &readsize, &over) == 0)
{
CloseHandle(handle);
return 0;
}
buffer[size] = 0;
out = buffer;
//delete [] buffer;
//注意这里需要自己释放内存
CloseHandle(handle);
return size;
}
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char* a;
DWORD len=ReadDisk(a, 0, 512);
if (len){
for (int i = 0; i < len; i++){
printf("%02X ", a[i]);
}
}
getchar();
return 0;
}

写磁盘代码:

//写磁盘
 DWORD WriteDisk(unsigned char* inbyte, DWORD start, DWORD size)
 {
 OVERLAPPED over = { 0 };
 over.Offset = start;
 HANDLE handle = CreateFile(TEXT("\\\\.\\PHYSICALDRIVE0"), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
 if (handle == INVALID_HANDLE_VALUE)return 0;
 unsigned char* buffer = new unsigned char[size + 1];
 DWORD writesize;
 
 //主要防止其他不必要问题
 memcpy(buffer, inbyte, size);
 
 DWORD dwIOCount=0;
 
 
 if (WriteFile(handle, buffer, size, &writesize, &over) == 0)
 {
 CloseHandle(handle);
 return 0;
 }
 delete [] buffer;  
 CloseHandle(handle);
 return writesize;
 }

代码中需要注意的几个地方:

1。"\\.\PhysicalDrive0"表示第一个物理磁盘,"\\.\PhysicalDrive1"表示第二个物理磁盘,不区分大小写,以此类推。另外别忘了C/C++字符串转义应该写成\\\\.\\
2。dwCreationDisposition参数必须具有OPEN_EXISTING标志。不要问我为什么,微软就是这么说的,不信查MSDN。
3。MSDN上说如果读写的是卷设备,dwShareMode必须要有FILE_SHARE_WRITE标志,但是在w10系统上读写磁盘设备如果不加这个标志CreateFile也会失败,但在w8.1上不会,至于说为什么别问我,问微软吧。
4。如果你用的uefi引导,那么你的mbr前400多个字节可能是空白,博主因为一些特殊原因(方便加载u盘的mbr引导),专门改成了BIOS引导,所以mbr中的引导程序不是空的,所以如果你运行代码发现前400多字节都是0,不要以为出错了。

特别提醒:读写物理磁盘需要管理员权限,如何获取管理员权限看这里,别因为没注意这个导致运行失败而折腾。