Windows:从设备句柄获取文件系统句柄
Windows:从设备句柄获取文件系统句柄
我太懂这种卡壳的挫败感了——好不容易顺着对象命名空间一路挖到HarddiskVolume1,结果想把这个设备句柄转成能操作文件系统的句柄时直接撞墙,确实挺闹心的。让我给你捋捋这里面的门道,还有两个实际能用的解决办法。
首先得戳破核心问题:HarddiskVolume1是Windows对象管理器里的设备对象,它本身不属于文件系统命名空间的目录对象,所以你直接尝试把它当目录打开肯定会失败。要实现从设备对象到文件系统的无缝跳转,得用Native API做一层“转换”,具体可以试试这两个方案:
方案一:直接用设备句柄作为根目录打开文件系统根
这应该是最直接的方法,利用NtCreateFile结合你已经拿到的设备句柄,直接打开它对应的文件系统根目录:
- 先确保你手里的设备句柄有足够的权限,至少要包含
FILE_LIST_DIRECTORY和SYNCHRONIZE权限,不然后续调用会直接返回权限不足的错误。 - 构造
OBJECT_ATTRIBUTES的时候,把RootDirectory字段设为你的设备句柄,ObjectName传一个空的UNICODE_STRING(因为我们要打开的就是设备挂载的文件系统根目录),再加上OBJ_CASE_INSENSITIVE标志避免大小写问题。
给你一段用户态下可直接参考的代码片段:
#include <ntifs.h> #include <windows.h> HANDLE GetFileSystemHandleFromDevice(HANDLE hDevice) { HANDLE hFileSystem = NULL; IO_STATUS_BLOCK iosb = {0}; UNICODE_STRING usEmpty = RTL_CONSTANT_STRING(L""); OBJECT_ATTRIBUTES oa; InitializeObjectAttributes(&oa, &usEmpty, OBJ_CASE_INSENSITIVE, hDevice, NULL); NTSTATUS status = NtCreateFile( &hFileSystem, FILE_LIST_DIRECTORY | SYNCHRONIZE | GENERIC_READ, &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS(status)) { // 可以根据status排查问题,比如STATUS_OBJECT_TYPE_MISMATCH说明设备没挂载文件系统 return NULL; } return hFileSystem; }
方案二:通过卷GUID路径打开文件系统
如果方案一没成功,还可以先查询设备对应的卷GUID,再用GUID路径打开文件系统:
- 调用
NtQueryVolumeInformationFile,传入FileFsVolumeInformation信息类,拿到卷的GUID值。 - 用这个GUID构造形如
\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}的路径,然后直接用NtCreateFile打开这个路径,就能得到文件系统根目录的句柄了。
这里要注意,有些临时挂载的设备可能没有分配GUID,这时候这个方案就不适用,得回到方案一排查权限或者设备是否挂载的问题。
几个避坑关键点
- 权限是重灾区:打开设备句柄的时候,一定要请求后续操作需要的权限,比如要遍历目录就必须要
FILE_LIST_DIRECTORY权限,不然NtCreateFile会返回STATUS_ACCESS_DENIED。 - 先确认设备挂载状态:可以用
NtQueryVolumeInformationFile查询FileFsDeviceInformation,如果返回的FileSystemName是空的,说明这个设备还没挂载文件系统,自然没法拿到文件系统句柄。 - 区分用户态和内核态:如果是在内核态操作,记得在
OBJECT_ATTRIBUTES里加上OBJ_KERNEL_HANDLE标志,用户态就不用加这个。
要是你试了这些方法还是有问题,不妨把调用NtCreateFile返回的NTSTATUS码贴出来,根据具体错误码排查会更高效。
内容来源于stack exchange
相关产品推荐
相关产品推荐

