Windows API SysWOW重定向意外行为

时间:2018-01-12 02:23:54

标签: c++ windows winapi syswow64

我有一个旧的32位安装程序,它将一些32位依赖项DLL安装到Windows系统文件夹中。我发现它无法在64位系统上安装某些32位DLL,因为SysWOW重定向正在做一些我不理解的事情。

安装程序依赖于Windows API函数GetFileVersionInfo来指示DLL是否已经存在较新的版本号。但是,我现在看到的情况是文件MSVCR100.DLL已存在于System32文件夹中,但不存在于SysWOW64文件夹中。当GetFileVersionInfo用于测试C:\ Windows \ System32 \ MSVCR100.DLL时,我希望它重定向到C:\ Windows \ SysWOW64 \ MSVCR100.DLL。似乎如果SysWOW64中不存在该文件,那么它在System32中看起来是一个后备。因此,安装程序认为MSVCR100.DLL已经存在并且无法安装它。

我创建了一个C ++ Win32控制台应用程序来测试它。整个代码是:

int _tmain(int argc, _TCHAR* argv[])
{
    char sysDirName[64], sysWow64DirName[64];
    char fileName[256];

    strcpy_s(fileName, argv[1]);
    GetSystemDirectory((LPSTR)sysDirName, 256);
    GetSystemWow64Directory((LPSTR)sysWow64DirName, 256);

    test_file(sysDirName, fileName);
    test_file(sysWow64DirName, fileName);

    return 0;
}

void test_file(char *dir, char* fileName)
{
    char filePath[256];
    DWORD verInfoSize, tempDWORD;
    BOOL found;
    byte buff[8192];

    PathCombine((LPSTR)filePath, (LPSTR)dir, (LPSTR)fileName);
    verInfoSize = GetFileVersionInfoSize((LPSTR)filePath, &tempDWORD);
    found = GetFileVersionInfo((LPSTR)filePath, 0, verInfoSize, buff);
    if (found)
        printf("%s   --found\n", filePath);
    else
        printf("%s   --NOT found\n", filePath);
}

我在3台不同的64位计算机上测试过,包括Win 10,Win 7,我得到的结果相同。

如果MSVCR100.DLL在SysWOW64中但在System32中没有,那么我的测试显示重定向按预期工作:

>testSysFile msvcr100.dll
C:\WINDOWS\system32\msvcr100.dll   --found
C:\WINDOWS\SysWOW64\msvcr100.dll   --found

如果MSVCR100.DLL既不在System32也不在SysWOW64中,那么结果是预期的:

>testSysFile msvcr100.dll
C:\WINDOWS\system32\msvcr100.dll   --NOT found
C:\WINDOWS\SysWOW64\msvcr100.dll   --NOT found

如果MSVCR100.DLL在System32但不在SysWOW64中,那么结果会显示出意想不到的错误:

>testSysFile msvcr100.dll
C:\WINDOWS\system32\msvcr100.dll   --found
C:\WINDOWS\SysWOW64\msvcr100.dll   --NOT found

网络搜索向我展示了有关SysWOW重定向的大量信息,但我找不到任何关于此行为的文档或讨论。这真的是我应该期待的吗?我的测试还显示,如果我使用API​​函数GetSystemWow64Directory,我可以拥有一个不依赖于重定向的文件路径。是否可以安全地复制DLL并在那条路径上注册它们?

1 个答案:

答案 0 :(得分:2)

GetFileVersionInfo*使用LoadLibraryEx通过将文件作为数据文件加载来完成其工作。

由于某些原因KERNELBASE!BasepLoadLibraryAsDataFile LoadLibraryW调用ntdll!RtlWow64EnableFsRedirectionEx来禁用重定向,如果请求的文件位于“%WinDir%\ System32”内,则它会再次尝试加载文件,这次来自“真正的”system32目录。

这显然是设计上的,我想不出一个不是一个巨大的黑客的方法。我认为出于兼容性原因,他们会这样做。

然而,您可以使用以下内容检测它:

bool validFile = !(GetFileAttributes(filePath) & FILE_ATTRIBUTE_DIRECTORY);
bool falsePositive = gotversioninfo && !validFile;