如何判断线程是否启用了 WOW 文件系统重定向?

How to tell if WOW file system redirection is on for a thread?

说,我可以使用 Wow64DisableWow64FsRedirection API 来禁用文件系统重定向,但是有没有办法知道线程当前是否正在被重定向?换句话说,有没有像GetWow64FsRedirection这样的API?

没有 API 报告此状态的函数。您应该记住您禁用了重定向。

另一种方法是检查 Windows System32 目录中是否存在 wow32.dll(通常是 C:\Windows\System32)。 在 64 位系统上,此文件应位于 SysWOW64 目录中,因此如果启用文件重定向,将会找到它。 同样,可以检查 wow64.dll 是否存在,它位于 64 位系统的 System32 目录中,如果找不到,则启用重定向。

伪代码为:

bool IsWow64FileSystemRedirectionEnabled()
{
    if (!Is64BitOS()) return false;
    if (FileExists(GetSystem32Directory() + "\wow32.dll")) return true;
    return false;
}

其中:

  • Is64BitOS可以实现如图here
  • FileExists可以实现如图here
  • GetSystem32Directory - 可以如图所示实现 here

抱歉,忘了 post 跟进。正如公认的答案所暗示的那样,没有 API 可以检测到这一点。太糟糕了,因为信息就存储在线程 TEB struct 的未记录部分中。 (请参阅我在代码中的注释。)

下面的代码将检索它。

我必须先说明一下,它是通过反转上述 API 得到的。所以这是一个高度未记录的东西,可能会在 OS 的未来版本中被破坏。所以一定要在使用前做好版本保障。不过,对于 Windows 的所有已发布版本应该没问题,包括 Windows 10 build 17134:

enum YESNOERR{
    ERR = -1,
    NO = 0,
    YES = 1,
};

struct PROC_STATS{
    BOOL b32BitProcessOn64BitOS;
    DWORD dwOS_Major;
    DWORD dwOS_Minor;
    DWORD dwOS_Build;

    PROC_STATS()
    {
        BOOL (WINAPI *pfnIsWow64Process)(HANDLE, PBOOL);
        (FARPROC&)pfnIsWow64Process = ::GetProcAddress(::GetModuleHandle(_T("kernel32.dll")), "IsWow64Process");

        BOOL bWow64 = FALSE;
        b32BitProcessOn64BitOS = pfnIsWow64Process && pfnIsWow64Process(::GetCurrentProcess(), &bWow64) && bWow64;

        LONG (WINAPI *pfnRtlGetVersion)(RTL_OSVERSIONINFOEXW*);
        (FARPROC&)pfnRtlGetVersion = ::GetProcAddress(::GetModuleHandle(_T("ntdll.dll")), "RtlGetVersion");

        OSVERSIONINFOEX osvi = {0};
        osvi.dwOSVersionInfoSize = sizeof(osvi);
        pfnRtlGetVersion(&osvi);

        dwOS_Major = osvi.dwMajorVersion;
        dwOS_Minor = osvi.dwMinorVersion;
        dwOS_Build = osvi.dwBuildNumber;
    }
};

PROC_STATS procStats;


YESNOERR __cdecl GetWow64FsRedirection()
{
    //Checks if Wow64 file system redirection is on for the current thread
    YESNOERR res = ERR;

    __try
    {
        if(procStats.b32BitProcessOn64BitOS)
        {
            //Really easy pre-Win10 v.10.0.10041.0
            if(procStats.dwOS_Major < 10 ||
                (procStats.dwOS_Major == 10 && procStats.dwOS_Build <= 10041))
            {
                //Win XP, 7, 8.1 & earlier builds of Win10
                __asm
                {
                    mov     eax, fs:18h             ; TEB
                    mov     eax, [eax + 0F70h]
                    mov     eax, [eax + 14C0h]

                    xor     ecx, ecx
                    test    eax, eax                ; 0=Wow64FsRedir is on, 1=Off
                    setz    cl
                    mov     [res], ecx
                }
            }
            else
            {
                //Latest builds of Win10 have a separate WoW TEB block
                __asm
                {
                    mov     eax, fs:18h             ; TEB
                    mov     ecx, [eax + 0FDCh]      ; WowTebOffset
                    test    ecx, ecx
                    jns     lbl_no_offset           ; it must precede TEB

                    add     eax, ecx

lbl_no_offset:
                    cmp     eax, [eax + 18h]        ; pick version of the struct
                    jz      lbl_alt

                    mov     eax, [eax + 14C0h]
                    jmp     lbl_check

lbl_alt:
                    mov     eax, [eax + 0E30h]

lbl_check:
                    xor     ecx, ecx
                    test    eax, eax                ; 0=Wow64FsRedir is on, 1=Off
                    setz    cl
                    mov     [res], ecx
                }
            }
        }
        else
        {
            //It's off by default
            res = NO;
        }
    }
    __except(1)
    {
        //Oops, too far in the future -- this no longer works
        res = ERR;
    }

    return res;
}

您可以通过以下方式对其进行测试:

resWow64FsOn = GetWow64FsRedirection();
_tprintf(L"Wow64FsRedirection=%d\n", resWow64FsOn);

void* pOldV;
if(::Wow64DisableWow64FsRedirection(&pOldV))
{
    resWow64FsOn = GetWow64FsRedirection();
    _tprintf(L"Wow64FsRedirection=%d\n", resWow64FsOn);

    ::Wow64RevertWow64FsRedirection(pOldV);

    resWow64FsOn = GetWow64FsRedirection();
    _tprintf(L"Wow64FsRedirection=%d\n", resWow64FsOn);
}
else
{
    _tprintf(L"ERROR: (%d) API Failed\n", ::GetLastError());
}