Windows API SysWOW перенаправление неожиданное поведение

У меня есть старая 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 и зарегистрировать их по этому пути?

2

Решение

GetFileVersionInfo* использования LoadLibraryEx сделать свою работу, загрузив файл как файл данных.

По какой-то причине KERNELBASE!BasepLoadLibraryAsDataFile внутри LoadLibraryW звонки ntdll!RtlWow64EnableFsRedirectionEx чтобы отключить перенаправление, и если запрошенный файл находится внутри «% WinDir% \ System32», он пытается загрузить файл снова, на этот раз из «реального» каталога system32.

Это явно по замыслу, и я не могу придумать, как обойти это, не являясь гигантским взломом. Я предполагаю, что они делают это по причинам совместимости.

Однако вы можете обнаружить это примерно так:

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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]