CreateFile:直接对原始磁盘进行写入操作“访问被拒绝” - Vista,Win7

Posted

技术标签:

【中文标题】CreateFile:直接对原始磁盘进行写入操作“访问被拒绝” - Vista,Win7【英文标题】:CreateFile: direct write operation to raw disk "Access is denied" - Vista, Win7 【发布时间】:2012-01-31 10:57:24 【问题描述】:

相关的微软文档是:Blocking Direct Write Operations to Volumes and DisksCreateFile, remarks on Physical Disks and Volumes

可执行文件是用 C++ 编写的,它调用CreateFile() 打开一个没有文件系统的 SD 卡。在没有管理员权限的情况下,CreateFile() 和连续的 ReadFile() 调用对于 GENERIC_READ 是成功的。

CreateFileGENERIC_WRITE 失败,即使具有管理员权限也是如此。在资源管理器中,我在属性 > 兼容性 > 权限级别下设置了以管理员身份运行。我还尝试从管理员 cmd 运行可执行文件(以 Ctrl+Shift+Enter 开头,“管理员:”在窗口标题中,适当提升)。尽管如此,我还是得到了ERROR_ACCESS_DENIED (0x5)。

我是否必须将其他内容传递给CreateFile 我不知道什么是安全属性,我只是在第 92 行传递 NULL、relevant code is here,在第 48 行传递 here .

或者是否应该设置其他任何东西来以管理员权限运行该进程?


一个相关问题:

Can I get write access to raw disk sectors under Vista and Windows 7 in user mode?Raw partition access in Windows VistaHow to obtain direct access to raw HD data in C?Is there a clean way to obtain exclusive access to a physical partition under Windows?

【问题讨论】:

如果没有文件系统创建文件应该失败。也许在读取至少一个字节之前它不会失败,而写入则试图在打开时创建一个实际(空)文件。 @DannyVarod 阅读就像一个魅力,我已经阅读了大量数据并且数据是正确的。请参阅Microsoft's doc、CreateFile是处理没有文件系统的驱动器的方法。 什么值作为 access 参数传递给open_device() @wallyk GENERIC_WRITE,另见line 48。我已经在这个问题上设置了赏金。 让我们从基础开始:是否已请求独占写入权限? 【参考方案1】:

虽然@MSalters 的答案是有道理的,但这不是我的代码的工作方式。事实上,它是如此违反直觉,我花了几天时间确保代码确实有效。

这些代码 sn-ps 位于经过验证的大众消费市场软件产品中。当它需要修改磁盘结构时,它会卸载 win32 卷,以便修改 NTFS 或 FAT 文件系统结构。有趣的是,卷访问句柄是只读的:

    char    fn [30];
    snprintf (fn, sizeof fn, "\\\\.\\%s:", vol -> GetVolName ());

    vol_handle = CreateFile (fn, GENERIC_READ,
                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                            OPEN_EXISTING,
                            FILE_FLAG_NO_BUFFERING | FILE_FLAG_RANDOM_ACCESS,
                            NULL);

    if (vol_handle == INVALID_HANDLE_VALUE)
    
          // show error message and exit
    

如果无法获得对卷或分区的写入权限,如果用户在严厉警告后授权,则此代码会强制卸载:

if (!DeviceIoControl (vol_handle, FSCTL_DISMOUNT_VOLUME,
                                            NULL, 0, NULL, 0, &status, NULL))

    DWORD err = GetLastError ();
    errormsg ("Error %d attempting to dismount volume: %s",
                                                        err, w32errtxt (err));


// lock volume
if (!DeviceIoControl (vol_handle, FSCTL_LOCK_VOLUME,
                                            NULL, 0, NULL, 0, &status, NULL))

     // error handling; not sure if retrying is useful

然后写入相当简单,除了将文件指针定位为 512 字节扇区:

    long    hipart = sect >> (32-9);
    long    lopart = sect << 9;
    long    err;

    SetLastError (0);       // needed before SetFilePointer post err detection
    lopart = SetFilePointer (vol_handle, lopart, &hipart, FILE_BEGIN);

    if (lopart == -1  &&  NO_ERROR != (err = GetLastError ()))
    
            errormsg ("HWWrite: error %d seeking drive %x sector %ld:  %s",
                            err, drive, sect, w32errtxt (err));
            return false;
    

    DWORD   n;

    if (!WriteFile (vol_handle, buf, num_sects*512, &n, NULL))
    
            err = GetLastError ();
            errormsg ("WriteFile: error %d writing drive %x sectors %lu..%lu:  %s",
                            err, drv, sect, sect + num_sects - 1,
                            w32errtxt (err));
            return false;
    

【讨论】:

对不起,当我注意到你的回答时,我已经奖励了赏金。无论如何,你能把你的答案说得更明确一些吗?您是否想说仅 GENERIC_READ 就足以获得写访问权限? @Ali:GENERIC_READ 确实如此。一旦锁定成功,后续的写操作就可以正常工作。至于积分,也许你可以投票? :-) 是的,对于赏金我真的很抱歉,我赞成你的问题。我会试试你写的东西,如果它真的有效,我会在问题的末尾添加一个注释。这是我现在能做的最好的了…… 谢谢你,它拯救了我的一天。但是我仍然需要五个小时来弄清楚对于 \\.\PhysicalDriveX 路径,没有 GENERIC_WRITE 它不会让你在 Windows 7 上编写。 @daminetreg:自从几年前公司被出售以来,我不知道客户在 Vista/Win7/Win8 上运行我的代码的任何反馈,但是,从你们的 cmets 看来,API变得更加直观。【参考方案2】:

很少需要GENERIC_WRITE。你很可能想要GENERIC_READ|GENERIC_WRITE

【讨论】:

好的,这就是问题所在 :) 你能解释一下为什么吗? 不是 100% 确定,还没有审查你的整个代码。许多“修改”风格的操作通过读取大量数据、更改他们想要的位并将整个数据块写回来工作。例如。您无法将一个字节物理地写入硬盘,但文件系统却假装您可以。显然你需要读写权限。 顺便提一下,SD 卡的块大小异常大,通常为 128k。我不知道 Windows 如何在低级别处理此问题,但很可能您需要读取访问权限才能写入小于此数量的数量(在硬件级别,您将 128k 读入内存,更改部分您需要更改、擦除块并将其写回;Windows 内核很可能会决定需要读取访问权限才能执行此操作,即使读取不是由用户级代码启动)。 @Jules:这对操作系统是隐藏的。【参考方案3】:

在 MSDN 的 CreateFile 文档中有注释:

对磁盘或卷的直接访问受到限制。有关详细信息,请参阅帮助和支持知识库http://support.microsoft.com/kb/942448 中的“更改文件系统和存储堆栈以限制 Windows Vista 和 Windows Server 2008 中的直接磁盘访问和直接卷访问”。

它指的是Vista/2008,但可能也适用于Win7。

【讨论】:

我已经阅读了,但我该怎么办?问题是什么?在文档中,如果未安装卷或 如果卷有没有文件系统。”就我而言,没有文件系统。【参考方案4】:

从 x86 移植到 x64 代码时,我遇到了类似的问题。您提到您正在为您的 SECURITY_ATTRIBUTES 参数传递null;在我真正开始创建/传递此参数之前,我自己使用这种方法遇到了拒绝访问错误。

【讨论】:

不幸的是,我只有 VB.NET 代码来展示这个,而且因为我使用的是 .NET 框架,所以发布它可能只是浪费你的时间 - 但如果你知道,请告诉我无论如何希望我这样做。

以上是关于CreateFile:直接对原始磁盘进行写入操作“访问被拒绝” - Vista,Win7的主要内容,如果未能解决你的问题,请参考以下文章

根据 GetLastError 直接写磁盘导致错误代码 5

如何通过 CreateFile 获取用于原始直接打印的 USB 打印机文件名? [关闭]

kafka基础

c++ 获取磁盘句柄

用原始usb c ++写入文件

FileMapping写的内容什么时候会flush到磁盘?