C 如何为GetModuleFileNameEx禁用WOW64文件系统重定向?

C 如何为GetModuleFileNameEx禁用WOW64文件系统重定向?,c,winapi,wow64,C,Winapi,Wow64,我正在64位Windows 10上通过32位进程运行以下操作: #ifndef _DEBUG WCHAR buffPath[MAX_PATH] = {0}; FARPROC pfn = (FARPROC)::GetModuleHandleEx; HMODULE hMod = NULL; ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX

我正在64位Windows 10上通过32位进程运行以下操作:

#ifndef _DEBUG
    WCHAR buffPath[MAX_PATH] = {0};
    FARPROC pfn = (FARPROC)::GetModuleHandleEx;
    HMODULE hMod = NULL;
    ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 
        GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
        (LPCTSTR)pfn, &hMod);

    PVOID pOldVal = NULL;
    if(::Wow64DisableWow64FsRedirection(&pOldVal))
    {
        ::GetModuleFileNameEx(::GetCurrentProcess(), hMod, buffPath, _countof(buffPath));
        ::Wow64RevertWow64FsRedirection(pOldVal);

        wprintf(L"Path=%s\n", buffPath);
    }
#else
#error run_in_release_mode
#endif
我希望收到的路径是c:\windows\syswow64\KERNEL32.DLL,但它给了我:

Path=C:\Windows\System32\KERNEL32.DLL
知道为什么吗?

当我们通过LoadLibrary[Ex]或LdrLoadDll加载dll时-首先是一些预处理传输的dll名称,比如将api-*转换为实际的dll名称或基于清单重定向dll名称-众所周知的示例comctl32.dll,然后使用此可能修改的dll名称将文件加载为dll。但是wow fs重定向-在这个阶段没有预处理。如果dll成功加载-系统分配结构,并在预处理dll名称后按原样保存传输

GetModuleFileNameEx只需遍历双链接列表和搜索条目,其中DllBase==hModule-如果找到-如果缓冲区足够大,则将FullDllName复制到lpFilename。因此,它只返回加载dll期间使用的dll路径。Wow64DisableWow64FsRedirection对该调用没有任何影响

如果我们想获得dll的真正规范完整路径,需要使用GetMappedFileNameW或with

所以,如果我们希望MAX_路径足够的话,代码就可以了

WCHAR path[MAX_PATH];
GetMappedFileNameW(NtCurrentProcess(), hmod, path, RTL_NUMBER_OF(path));
或者,如果使用ntapi并正确处理任何路径长度:

NTSTATUS GetDllName(PVOID AddressInDll, PUNICODE_STRING NtImageName)
{
    NTSTATUS status;

    union {
        PVOID buf;
        PUNICODE_STRING ImageName;
    };

    static volatile UCHAR guz;
    PVOID stack = alloca(guz);

    SIZE_T cb = 0, rcb = 0x200;

    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = ZwQueryVirtualMemory(NtCurrentProcess(), AddressInDll, 
            MemoryMappedFilenameInformation, buf, cb, &rcb)))
        {
            return RtlDuplicateUnicodeString(
                RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 
                ImageName, NtImageName);
        }

    } while (status == STATUS_BUFFER_OVERFLOW);

    return status;
}
    UNICODE_STRING NtImageName;
    if (0 <= GetDllName(hmod, &NtImageName))
    {
        RtlFreeUnicodeString(&NtImageName);
    }
此外,当我们通过LoadLibrary[Ex]加载dll时,我们还可以将代码更改为MOUNTMGR_IS_VOLUME_NAME&SymbolicLinkName,以获取卷持久名称形式,而不是驱动程序字母形式或LdrLoadDll-首先是一些预处理传输的dll名称,如将api-*转换为实际的dll名称或根据清单重定向dll名称-众所周知的示例comctl32.dll,然后使用此可能修改的dll名称作为dll加载文件。但是wow fs重定向-在这个阶段没有预处理。如果dll成功加载-系统分配结构,并在预处理dll名称后按原样保存传输

GetModuleFileNameEx只需遍历双链接列表和搜索条目,其中DllBase==hModule-如果找到-如果缓冲区足够大,则将FullDllName复制到lpFilename。因此,它只返回加载dll期间使用的dll路径。Wow64DisableWow64FsRedirection对该调用没有任何影响

如果我们想获得dll的真正规范完整路径,需要使用GetMappedFileNameW或with

所以,如果我们希望MAX_路径足够的话,代码就可以了

WCHAR path[MAX_PATH];
GetMappedFileNameW(NtCurrentProcess(), hmod, path, RTL_NUMBER_OF(path));
或者,如果使用ntapi并正确处理任何路径长度:

NTSTATUS GetDllName(PVOID AddressInDll, PUNICODE_STRING NtImageName)
{
    NTSTATUS status;

    union {
        PVOID buf;
        PUNICODE_STRING ImageName;
    };

    static volatile UCHAR guz;
    PVOID stack = alloca(guz);

    SIZE_T cb = 0, rcb = 0x200;

    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = ZwQueryVirtualMemory(NtCurrentProcess(), AddressInDll, 
            MemoryMappedFilenameInformation, buf, cb, &rcb)))
        {
            return RtlDuplicateUnicodeString(
                RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 
                ImageName, NtImageName);
        }

    } while (status == STATUS_BUFFER_OVERFLOW);

    return status;
}
    UNICODE_STRING NtImageName;
    if (0 <= GetDllName(hmod, &NtImageName))
    {
        RtlFreeUnicodeString(&NtImageName);
    }

此外,我们还可以将代码更改为MOUNTMGR_IS_VOLUME_NAME&SymbolicLinkName for get VOLUME persistent NAME form而不是driver letter form

GetModuleHandleEx只返回保存的模块名,用于加载dll。Wow64DisableWow64FsRedirection对此没有也不能有任何影响。您可以使用GetMappedFileName来获取真实的文件系统path@RbMm:它保存在哪里,PEB结构?是的,GetMappedFileName返回了正确的路径。它是设备路径形式。您知道有什么简单的方法可以将其转换为资源管理器使用的格式,即C:\而不是\Device\HardiskVolumeN?顺便说一句,GetMappedFileName不需要Wow64DisableWow64FsRedirectionit保存在GetModuleFileNameEx从这里返回的_LDR_DATA_TABLE_条目中。甚至在文件名/路径中保留大小写。您可以通过自加载一些dll并在name-GetModuleFileNameEx中使用不寻常的大小写组合来轻松测试这一点,并将其返回给您。当GetMappedFileName-返回真实的文件系统时path@RbMm:\u LDR\u DATA\u TABLE\u内核空间中的条目,对吗?当然GetMappedFileName也不依赖于Wow64DisableWow64FsRedirection这是ZwQueryVirtualMemory上的shell,MemoryMappedFileName信息..GetModuleHandlex只返回保存的模块名,用于加载dll。Wow64DisableWow64FsRedirection对此没有也不能有任何影响。您可以使用GetMappedFileName来获取真实的文件系统path@RbMm:它保存在哪里,PEB结构?是的,GetMappedFileName返回了正确的路径。它是设备路径形式。您知道有什么简单的方法可以将其转换为资源管理器使用的格式,即C:\而不是\Device\HardiskVolumeN?顺便说一句,GetMappedFileName不需要Wow64DisableWow64FsRedirectionit保存在GetModuleFileNameEx从这里返回的_LDR_DATA_TABLE_条目中。甚至在文件名/路径中保留大小写。您可以通过自加载一些dll并在name-GetModuleFileNameEx中使用不寻常的大小写组合来轻松测试这一点,并将其返回给您。当GetMappedFileName-返回真实的文件系统时path@RbMm:_LDR_DATA_TABLE_内核空间中的条目,对吗?当然GetMappedFileName也不依赖于WOW64禁用WOW64FSRedirection这是ZwQueryVirtualMemory上的shell,MemoryMappedFileName信息。。