使用LOAD_LIBRARY_AS_DATAFILE调用LoadLibraryEx时,具有独占访问权限的CreateFileW成功

时间:2017-10-13 16:33:31

标签: c++ winapi

我假设如果您使用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工具加载模块之外,我没有验证其他打开的句柄"句柄"。

1 个答案:

答案 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中描述了这种情况:

  

如果用户想要对文件进行写访问,请确保没有   将此文件映射为图像

MmFlushImageSectionMmFlushForWrite的调用失败,而您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();
}