У меня есть старая 32-разрядная программа установки, которая устанавливает некоторые 32-разрядные библиотеки зависимостей в системную папку Windows. Я обнаружил, что не удается установить некоторые из 32-разрядных библиотек DLL в 64-разрядной системе, поскольку перенаправление SysWOW делает то, чего я не понимаю.
Программа установки полагалась на функцию API Windows 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 и зарегистрировать их по этому пути?
GetFileVersionInfo*
использования LoadLibraryEx
сделать свою работу, загрузив файл как файл данных.
По какой-то причине KERNELBASE!BasepLoadLibraryAsDataFile
внутри LoadLibraryW
звонки ntdll!RtlWow64EnableFsRedirectionEx
чтобы отключить перенаправление, и если запрошенный файл находится внутри «% WinDir% \ System32», он пытается загрузить файл снова, на этот раз из «реального» каталога system32.
Это явно по замыслу, и я не могу придумать, как обойти это, не являясь гигантским взломом. Я предполагаю, что они делают это по причинам совместимости.
Однако вы можете обнаружить это примерно так:
bool validFile = !(GetFileAttributes(filePath) & FILE_ATTRIBUTE_DIRECTORY);
bool falsePositive = gotversioninfo && !validFile;
Других решений пока нет …