【问题标题】:Windows API SysWOW redirection unexpected behaviorWindows API SysWOW 重定向意外行为
【发布时间】:2018-06-21 11:15:47
【问题描述】:

我有一个旧的 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 并在该路径上注册它们是否安全?

【问题讨论】:

  • 您或安装程序是否正在采取任何措施来禁用 FS 重定向?在这些函数上设置断点并查看。
  • 嗯,这就是测试程序的全部代码。我听说过函数 Wow64DisableWow64FsRedirection,我当然不会调用它。我还能做些什么来禁用重定向?抱歉,我不明白你关于断点的建议。
  • “我有一个旧的 32 位安装程序,它将一些 32 位依赖 DLL 安装到 Windows 系统文件夹中。” - 当然,是 i> 您需要解决的错误。您的安装程序无权写入系统文件夹。将您的依赖项保存在应用程序文件夹中。除非您准备好回答无法回答的问题:“您的卸载程序应该做什么?”

标签: c++ windows winapi syswow64


【解决方案1】:

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

由于某种原因,KERNELBASE!BasepLoadLibraryAsDataFileLoadLibraryW 内调用 ntdll!RtlWow64EnableFsRedirectionEx 以禁用重定向,如果请求的文件在 "%WinDir%\System32" 内,那么它会尝试再次加载文件,这次是从 "real " system32 目录。

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

但是,您可以通过以下方式检测它:

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

【讨论】:

  • 是的,完全正确。奇怪的是LoadLibraryEx 的这种行为没有记录在案。 - prnt.sc/hzb9s7
  • 啊,谢谢。这似乎在 GetFileVersionInfo 上达成了交易。但是,我刚刚修改了我的测试程序以应用 found = (GetFileAttributes((LPSTR)filePath) != 0xFFFFFFFF);而不是调用 GetFileAttributes,当目标文件在 System32 但不在 SysWOW64 中时,这似乎显示了预期和期望的行为。我的想法是,在我的安装程序中,最简单的方法是在调用 GetFileVersionInfo 之前调用 GetFileAttributes 来确定文件的存在。你觉得这个计划有什么问题吗?
  • @TonyPulokas - 调用GetFileAttributes 是检查文件是否存在的好方法。这里没有任何问题
  • GetFileAttributes 可能没问题,我使用 CreateFile 是因为我不想请求任何类型的访问权限。 GetFileAttributes 可能会被具有该名称的目录欺骗,但这不太可能。
  • 即使存在同名目录 - 后续调用 GetFileVersionInfo* 将返回错误 - 在这种情况下,它不会尝试禁用重定向(它仅在之前调用返回 STATUS_NO_SUCH_FILE 的情况下调用不会是真的)。和GetFileAttributes 也不需要任何文件访问权限
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-16
  • 1970-01-01
  • 1970-01-01
  • 2017-11-30
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
相关资源
最近更新 更多