Not a kernel guy

… in the Windows kernel team

Sunday, March 30, 2008

Загадка.

Вот эта программа печатает номер версии указанного пользователем модуля, который она берет из поля “FileVersion” ресурса VS_VERSION_INFO этого модуля. Имя модуля передается как первый параметр командной строки. Для работы с VS_VERSION_INFO используется стандартная библиотека version.dll.

(далее идет много кода)

#define _WIN32_WINNT 0x0501

#include <windows.h>
#include <stdio.h>

void printFileVersion(
    const char* module
    )
{
    DWORD handle;

    // Query size of the buffer we will need
    DWORD size = GetFileVersionInfoSize(module, &handle);

    if (size)
    {
        char* buffer = new char[size];

        // Get own version information
        BOOL res = GetFileVersionInfo(module, handle, size, buffer);

        if (res)
        {
            void* ptr;
            UINT length;

            // Get FileVersion from English section of version information
            res = VerQueryValue(buffer, "\\StringFileInfo\\040904B0\\FileVersion", &ptr, &length);

            if (res)
            {
                // Print FileVersion
                printf("File Version: '%s'\n", ptr);
            }
        }

        delete[] buffer;
    }
}

int __cdecl main(
    int argc,
    const char* argv[]
    )
{
    if (argc < 1 || argc > 2)
    {
        printf("Usage: fileversion.exe <module-name>\n");
        exit(0);
    }

    char buffer[MAX_PATH];
    DWORD size = ExpandEnvironmentStrings(argv[1], buffer, MAX_PATH);

    if (size > 0 && size <= MAX_PATH)
    {
        printFileVersion(buffer);
    }

    return 0;
}

Например, для “%windir%\system32\notepad.exe” на моей машине выводится:

> fileversion.exe %windir%\system32\notepad.exe
File Version: '6.0.6000.16386 (vista_rtm.061101-2205)'

Далее, предположим, что мы пользуемся 32-х битной версией fileversion.exe и мы хотим получить версию 64-х разрядного модуля, установленного в %windir%\system32. Wow64 перенаправляет все файловые операции из %windir%\system32 в %windir%\syswow64. Соответственно, нам нужно запретить перенаправление на время чтения ресурсов из файла:

#if !defined(_WIN64)
BOOL isWow64()
{
    BOOL retval = FALSE;
    if (!IsWow64Process(GetCurrentProcess(), &retval))
    {
        retval = FALSE;
    }

    return retval;
}
#endif

int __cdecl main(
    int argc,
    const char* argv[]
    )
{
    if (argc < 1 || argc > 3)
    {
        printf("Usage: fileversion.exe <module-name> [native]\n");
        exit(0);
    }

#if !defined(_WIN64)
    PVOID FsRedirection;

    if (argc > 2 && isWow64())
    {
        // Disable Wow64 redirection if asked by a user
        Wow64DisableWow64FsRedirection(&FsRedirection);
    }
#endif

    char buffer[MAX_PATH];
    DWORD size = ExpandEnvironmentStrings(argv[1], buffer, MAX_PATH);

    if (size > 0 && size <= MAX_PATH)
    {
        printFileVersion(buffer);
    }

#if !defined(_WIN64)
    if (argc > 2 && isWow64())
    {
        // Restore Wow64 redirection
        Wow64RevertWow64FsRedirection(FsRedirection);
    }
#endif

    return 0;
}

Вопрос: почему попытка получить версию модуля может вызвать вот такое исключение при условии, что перенаправление файловой системы запрещено?

(115c.574): Unknown exception - code c06d007e (!!! second chance !!!)
KERNEL32!RaiseException+0x58:
00000000`7532f35f c9              leave
0:000:x86> k
ChildEBP          RetAddr
0017fd60 00402080 KERNEL32!RaiseException+0x58
0017fdc8 0040119e rabbit!__delayLoadHelper2+0x13b [f:\sp\vctools\delayimp\delayhlp.cpp @ 331]
0017fe0c 0040115b rabbit!_tailMerge_VERSION_dll+0xd
0017ff30 004014a6 rabbit!main+0x8b [d:\projects\notepad2a\trunk\boost\rabbit\main.cpp @ 82]
0017ff80 004012fd rabbit!__tmainCRTStartup+0x1a6 [f:\sp\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 597]
0017ff88 7538e3f3 rabbit!mainCRTStartup+0xd [f:\sp\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 414]
0017ff94 76fccfed KERNEL32!BaseThreadInitThunk+0xe
0017ffd4 76fcd1ff ntdll_76f50000!__RtlUserThreadStart+0x23
0017ffec 00000000 ntdll_76f50000!_RtlUserThreadStart+0x1b
Posted at 10:20 pm •

RSS feed | Trackback URI

15 Comments »

Pingback by Not a kernel guy : Загадка. — March 30, 2008 @ 10:39 pm

[...] from blog.not-a-kernel-guy.com. Published Monday, March 31, 2008 7:39 AM by alexeypa Filed under: Wow64, [...]

 
Comment by e.v.e — March 30, 2008 @ 11:06 pm

Пальцем в небо… Возжелали загрузить не ту DLLку?

P.S. ух-ты, у вас похоже тоже программы, на которых баги воспроизводят, называют кролами…

Comment by Not a kernel guy — March 31, 2008 @ 7:33 am

…называют кролами

Есть такое. :-) Забыл переименовать однако.

Comment by e.v.e — March 31, 2008 @ 8:31 am

Мне вот интересно, откуда это пошло…
Сильно сомневаюсь в параллельной эволюции терминологии…

 
 
 
Comment by Serge Broslavsky — March 30, 2008 @ 11:51 pm
#if !defined(_WIN64)
BOOL isWow64()
{
    BOOL retval = FALSE; /////// <= shouldn't it be TRUE?
    if (!IsWow64Process(GetCurrentProcess(), &retval))
    {
        retval = FALSE;
    }

    return retval;
}
#endif
Comment by Not a kernel guy — March 31, 2008 @ 7:35 am

Без разницы, по идее. Но FALSE надёжнее. IsWow64Process установит флаг в TRUE.

 
 
Comment by Den — March 30, 2008 @ 11:59 pm

Ошибка при отложенной загрузке динамической библиотеки (version.dll).
Видимо, в результате отключения перенаправления, попытались загрузить x64 библиотеку вместо x32.
Вызов GetFileVersionInfoSize(0,0) до отключения перенаправления, теоретически должен все исправить.

Comment by Not a kernel guy — March 31, 2008 @ 7:37 am

Видимо, в результате отключения перенаправления, попытались загрузить x64 библиотеку вместо x32.

Именно.

Вызов GetFileVersionInfoSize(0,0) до отключения перенаправления, теоретически должен все исправить.

Не исправить, а спрятать ошибку. Чтобы исправить - нужно пользоваться sysnative, как ниже указал Anonymous.

 
 
Comment by ivan — March 31, 2008 @ 12:02 am

исключение объясняется просто - так как было отключено перенаправление файловой системы в syswow64 и использовалась отложенная загрузка version.dll - delay load helper пытался загрузить 64-битную версию version.dll, а сделать это в 32-битный процесс нельзя.

Comment by alex — April 18, 2008 @ 3:49 am

Удивительно, а разве библиотеке при загрузке не указали LOAD_LIBRARY_AS_DATAFILE ?
Если нет, это в общем-то дыра в безопасности. Если да, то какой нафиг delay load helper, если загружается “труп” образа ? Трупу ссылки не нужны.

Comment by Not a kernel guy — April 18, 2008 @ 1:31 pm

Удивительно, а разве библиотеке при загрузке не указали LOAD_LIBRARY_AS_DATAFILE ?

Какой библиотеке? version.dll? Так она содержит код вызываемых функций (GetFileVersionInfoSize, GetFileVersionInfo и т.п.). Так что это никакой не труп.

 
 
 
Comment by Anonymous — March 31, 2008 @ 12:50 am

Как написано по представленной ссылке на “File System Redirector”, предпочтительный способ читать из %windir%\system32 - подставить %windir%\sysnative…

Comment by Not a kernel guy — March 31, 2008 @ 7:38 am

Да, это единственный надежный способ.

 
 

[...] комментариях к загадке ответ был дан почти сразу. Действительно, обработчик [...]

 
Pingback by Not a kernel guy : Отгадка. — April 1, 2008 @ 9:29 pm

[...] комментариях к загадке ответ был дан почти сразу. Действительно, обработчик [...]

 

Your Comment (smaller | larger)

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress