我假设如果您使用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工具加载模块之外,我没有验证其他打开的句柄"句柄"。
答案 0 :(得分:1)
您的案例可以在下一次测试中更清楚地显示
ULONG TestImageAccess(PCWSTR name, BOOL bImage, BOOL bRequestWriteAccess)
{
SetLastError(0);
HANDLE hFile = CreateFileW(name, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
HANDLE hSection = CreateFileMappingW(hFile, 0,
bImage ? PAGE_READONLY|SEC_IMAGE : PAGE_READONLY|SEC_COMMIT, 0, 0, 0);
CloseHandle(hFile);
if (hSection)
{
hFile = CreateFileW(name,
bRequestWriteAccess ? GENERIC_WRITE : GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
CloseHandle(hSection);
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
}
}
return GetLastError();
}
void TestImageAccess(PCWSTR filename)
{
TestImageAccess(filename, TRUE, TRUE); // ERROR_SHARING_VIOLATION
TestImageAccess(filename, FALSE, TRUE); // NOERROR
TestImageAccess(filename, TRUE, FALSE); // NOERROR
TestImageAccess(filename, FALSE, FALSE);// NOERROR
}
当我们请求写访问到文件并将文件映射作为图像
时,我们得到了ERROR_SHARING_VIOLATION
Executable Images
中描述了这种情况:
如果用户想要对文件进行写访问,请确保没有 将此文件映射为图像
MmFlushImageSection
对MmFlushForWrite
的调用失败,而您STATUS_SHARING_VIOLATION
- 正好在此行。
LoadLibraryEx
的 LOAD_LIBRARY_AS_DATAFILE
在标记为0的情况下使用SEC_COMMIT
创建文件部分 - SEC_IMAGE
- 以及图像部分
这里的特权绝对不相关
如何确定您是否真正拥有对文件的独占访问权限 什么时候加载库?
只需打开您需要的访问权限并执行您需要的操作即可。是的,当您尝试截断映射文件时,您可能会收到错误ERROR_USER_MAPPED_FILE
。但这里无能为力。例2
ULONG TestImage2(PCWSTR name)
{
HANDLE hFile = CreateFileW(name, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY|SEC_COMMIT, 0, 0, 0);
CloseHandle(hFile);
if (hSection)
{
PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
CloseHandle(hSection);
if (pv)
{
hFile = CreateFileW(name,GENERIC_WRITE|GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
FILE_END_OF_FILE_INFO eof = { };
// ERROR_USER_MAPPED_FILE will be here
SetFileInformationByHandle(hFile, FileEndOfFileInfo, &eof, sizeof(eof));
CloseHandle(hFile);
}
UnmapViewOfFile(pv);
}
}
}
return GetLastError();
}