【发布时间】:2017-10-13 16:33:30
【问题描述】:
我的假设是,如果您使用 CreateFileW 请求独占访问,如果它已经打开,我应该会收到共享冲突。但是,我遇到了一个并非如此的示例。如果调用 LoadLibraryEx 以加载设置了 LOAD_LIBRARY_AS_DATAFILE 标志的 DLL,则 CreateFileW 成功返回。但是有些操作会被拒绝(例如设置文件结尾等属性)。有没有更好的方法来检测这些文件是否打开?我是否错误地使用了 CreateFileW?在没有 LOAD_LIBRARY_AS_DATAFILE 标志的情况下加载 DLL 会导致 CreateFileW 失败,表明它无法访问该文件,因为它正在被另一个进程使用。
HMODULE hModule = LoadLibraryEx(L"\\Pathto\\module.dll", NULL, NULL);
DWORD access = GENERIC_READ | GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY;
DWORD creation = OPEN_EXISTING;
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
HANDLE file = CreateFileW(L"\\Pathto\\module.dll", access, 0, NULL, creation, flags, 0);
以上将导致 CreateFileW 失败,错误代码为 32(无法访问,因为它正在被另一个进程使用),这是预期的结果。如果我将标志添加到 LoadLibraryEx:
HMODULE hModule = LoadLibraryEx(name, NULL, LOAD_LIBRARY_AS_DATAFILE);
然后对 CreateFileW 使用完全相同的调用,然后我被告知它是成功的,尽管稍后在尝试设置文件结尾时我会遇到问题(例如)。此外,删除文件将失败并出现拒绝访问错误(没有应用程序或任何其他具有打开句柄的应用程序)。
其他奇怪的行为涉及与加载的库的硬链接。如果我为加载的模块生成一个新的硬链接,并尝试删除替代的新创建的硬链接,它也会失败(没有打开文件句柄,只是加载了模块)。为什么?它不应该只是删除链接并取消引用链接计数,或者在模块关闭时安排删除,因为我之前可以获得独占访问权限吗?
另外值得注意的是,该进程本身在特权用户帐户中运行,并启用了以下附加权限: SE_SECURITY_NAME、SE_BACKUP_NAME、SE_RESTORE_NAME、SE_TAKE_OWNERSHIP_NAME
如何确定在加载库时您是否真正拥有对文件的独占访问权限?
编辑:只是为了仔细检查,除了通过 SysInternals 工具“句柄”加载模块之外,我没有验证其他打开的句柄。
【问题讨论】:
-
我猜数据只是放在内存中,但文件没有保持打开状态。 blogs.msdn.microsoft.com/oldnewthing/20141120-00/?p=43573 可能是相关的。
-
我认为还有更多。它显然仍被拥有进程引用(如果您在 SysInternals Process Explorer 中查看,则在该进程的生命周期内列为 DLL)。您的链接还指出它已映射到进程地址空间。另外,为什么没有解释就投反对票?这很容易重现。如果这是一个“愚蠢”的问题,请解释原因。
-
Raymond 的博客建议,如果它仅作为数据文件打开,则不应将其列为 DLL。顺便说一句,反对票不是我的。
-
@JonathanPotter - 文件并非在所有情况下都保持打开状态。这里的所有任务都是如何映射文件 - 作为图像或数据。并请求对文件的写访问权。正是在这一点上出错 - docs.microsoft.com/en-us/windows-hardware/drivers/ifs/…
-
句柄引用文件对象,该对象引用文件的文件/流控制块。为了将文件映射为图像/数据,内存管理器使用 FCB 的section object pointers。当打开文件进行写访问或设置文件的删除处置时,文件系统使用
MmFlushForWrite或MmFlushForDelete调用MmFlushImageSection。为硬链接打开的文件对象使用来自底层 SCB/FCB 的节对象指针。