3

Say, I can use Wow64DisableWow64FsRedirection API to disable file system redirection, but is there a way to know if the thread is currently being redirected? In other words, is there an API like GetWow64FsRedirection?

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • If there were such a function, I'd expect it to be in the table of contents at the page you linked. – Mark Ransom May 07 '15 at 19:43
  • I suspect there deliberately isn't because this is a very dangerous function to use, the expectation is that you'll turn it on and off in the same method usually. – Mgetz Oct 25 '18 at 22:31

3 Answers3

2

There is no API function that reports this state. You are expected to remember that you disabled redirection.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks. I'm actually doing it for a logging method (which obviously won't know if that was done.) – c00000fd May 07 '15 at 19:46
  • 1
    Or just call [`GetFinalPathNameByHandle`](https://msdn.microsoft.com/en-us/library/aa364962) on a handle for `%SystemRoot%\System32`. If it's redirected the final path will end at `SysWOW64`. – Eryk Sun May 07 '15 at 19:54
  • Or make the following calls in sequence: `Wow64DisableWow64FsRedirection(&disabled);` `Wow64RevertWow64FsRedirection(disabled);`. The latter call only enables redirection if it was previously enabled. – Eryk Sun May 07 '15 at 21:32
  • @eryksun: Hmm. Interesting. Thanks. You should post it as its own answer and I'll mark it. – c00000fd May 07 '15 at 23:11
0

Another approach is to check for the existence of the wow32.dll in the Windows System32 directory (typically C:\Windows\System32). On 64-bit systems, this file should reside in the SysWOW64 directory, thus if file redirection is enabled, it will be found. Similarly, one can check for the nonexistence of wow64.dll, that resides in the System32 directory on 64-bit systems, and if it's not to be found the redirection is enabled.

The pseudo-code for that would be:

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

Where:

  • Is64BitOS can be implemented as shown here
  • FileExists can be implemented as shown here
  • GetSystem32Directory - can be implemented as shown here
  • First off I wouldn't be hard-coding Windows installation path like that. It may not be `c:\Windows` for all you know. Then I'd be doubly-suspicion about relying on the presence of a file to detect a feature. You may be introducing a security bug into your code with this approach. – c00000fd Oct 26 '18 at 06:47
  • Thanks for commenting, as I said - it's a pseudo-code. I've edited the `System32` path, so it won't be misleading. – Dani Kamanovsky Oct 26 '18 at 13:07
  • Regarding the security issue, once an attacker can place a file in System32, he had either taken ownership or has an administrative rights to it. In such case he could perform much more severe damage. Anyway, this technique isn't perfect as it relies on the above specified limitations - but it's relatively fast (as twice as using the [GetFinalPathNameByHandle](https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea) on a handle for `%SystemRoot%\System32`). – Dani Kamanovsky Oct 26 '18 at 13:45
0

Sorry, forgot to post a follow-up. As the accepted answer suggests, there's no API to detect that. Too bad, because the information is stored right there in the undocumented section of the thread's TEB struct. (See my comments in the code.)

The code below will retrieve it.

I have to preface it though by saying that it was obtained by reversing the aforementioned API. So it's a highly undocumented stuff that will probably break in the future versions of the OS. So make sure to put version safeguards before using it. It should be OK for all released versions of Windows though, including 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;
}

This is how you can test it:

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());
}
c00000fd
  • 20,994
  • 29
  • 177
  • 400