[Win32] 直接读写磁盘扇区(磁盘绝对读写)

本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处: http://blog.csdn.net/zuishikonghuan/article/details/50380313

正讲着驱动开发呢,这里突然插一篇Win32的博文,其实,还是做引子,上一篇博文“IRP与派遣函数”中,我们知道了驱动程序需要处理I/O请求,我们先来看看怎么发出一个I/O请求。

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

演示一下将第一块磁盘的主引导扇区读出来,写的话把ReadFile换成WriteFile,再稍微改下代码就可以了,这些API函数在我之前的一篇博客中有详细解释(参见:http://blog.csdn.net/zuishikonghuan/article/details/46926787),对了,用BIOS引导系统的看官千万别乱写啊,写坏了MBR就引导不了系统了,修复很麻烦的,用UEFI引导系统的随便写,不怕,因为UEFI不从MBR加载引导程序,这也是UEFI天生免疫鬼影病毒的原因之一。
代码如下:

#include "stdafx.h"
#include

//参数:输出的字符串指针,开始位置,长度
//返回值:读取的大小
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;
}

效果图:

[Win32] 直接读写磁盘扇区(磁盘绝对读写)_第1张图片

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

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,不要以为出错了。

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

另外,不准学会了后拿去做病毒啊!做病毒后果自负!

我们就好像读写一个文件一样读写了“磁盘”这个设备,其实上就是把读写操作的I/O请求发送到了“磁盘”这个设备所在驱动程序注册的派遣函数中。
对了,Microsoft为Windows提供了基础的硬件驱动程序,不管磁盘的类型是什么,是IDE磁盘,SCSI磁盘,SATA磁盘,还是从USB上挂的磁盘,都抽象成统一接口的磁盘设备,所以,只要你用的磁盘是Microsoft支持的类型,或者硬件厂商提供了驱动程序,那么上面的代码均可用!

回归正题,我们通过打开“\\.\PhysicalDrive0”,打开了磁盘设备,如果接着我前几篇的博文看,你就会发现,这不就是符号连接吗,没错,这就是磁盘设备的符号连接。同时,“卷”也是设备,卷就是Windows对磁盘上的分区创建的设备,就是“此电脑”(文件资源管理器)中列出的a盘,b盘,c盘……,没错,卷只是一个逻辑上的概念,我们的电脑上也没有“卷”这种设备,但Windows为其创建了设备(严格意义上并非是操作系统创建的,创建设备不是操作系统的任务,应该说是Microsoft为Windows提供的基础设备驱动程序创建的),比如c盘的设备名一般是“\Device\HarddiskVolume1”,符号连接名是“\??\C:”(R0下)和“\\.\C:”(R3下),其实,我们看到的*盘就是驱动开发中的符号连接!用设备管理器修改盘符,其实就是通知卷驱动程序删除并重新创建符号连接。

结合上一篇“IRP与派遣函数”和上上篇“NT驱动的基本结构”,想必你已经大致有眉目了吧,下一篇和下下篇就会详细介绍如何在驱动程序中处理I/O请求了。

你可能感兴趣的:(Win32SDK,驱动开发)