[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Defense in depth -- the Microsoft way (part 45): filesystem redirection fails to redirect the application directory

Hi @ll,

on x64 editions of Windows, RegEdit.exe exists both as
%windir%\regedit.exe and %windir%\SysWOW64\regedit.exe.

<https://msdn.microsoft.com/en-us/library/aa384187.aspx> states

| [...] whenever a 32-bit application attempts to access [...]
| %windir%\regedit.exe is redirected to %windir%\SysWOW64\regedit.exe.

But what is the "application directory" when a 32-bit application
runs %windir%\regedit.exe?
Is it %windir% or %windir%\SysWOW64, i.e. is it determined before
or after the redirection?

Remember that the "application directory" comes first in the
standard/default DLL search order, as documented in

Since the 32-bit system DLLs are located in %windir%\SysWOW64, NOT
in %windir%, this makes a difference...

1. compile the following source as 32-bit program:

--- POC.C ---
#pragma comment(lib, "KERNEL32.LIB")

#pragma comment(linker, "/ENTRY:WinMainCRTStartup")
#pragma comment(linker, "/SUBSYSTEM:Windows")

#include <windows.h>

void WinMainCRTStartup()

    if (!CreateProcess("C:\\Windows\\regedit.exe", "* /M",
                       NULL, NULL, FALSE, 0L, NULL, NULL, &si, &pi))

    if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)

    if (!CloseHandle(pi.hThread))

    if (!CloseHandle(pi.hProcess))

--- EOF ---

2. download <http://home.arcor.de/skanthak/temp/REGEDIT.CAB> and
   extract its contents to %windir%:
      WUSA.EXE /Extract:REGEDIT.CAB %windir%
   (yes, this needs administrative privileges, but that's NOT the
   point here).

   The 32-bit DLLs in REGEDIT.CAB are transparent proxies: they
   export all symbols and ordinals of their counterparts found in
   the "system directory" and forward them to these counterparts.

--- FORWARD.C ---
#pragma comment(linker, "/DLL")
#pragma comment(linker, "/ENTRY:_DllMainCRTStartup")
#pragma comment(linker, "/EXPORT:<symbol>=System32\\<filename>.<symbol>,@<ordinal>")
#pragma comment(linker, "/EXPORT:<ordinal>=System32\\<filename>.#<ordinal>,@<ordinal>,NONAME")
#pragma comment(linker, "/SUBSYSTEM:Windows")

#include <windows.h>

BOOL WINAPI _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

    return TRUE;
--- EOF ---

   See <http://home.arcor.de/skanthak/sentinel.html> for details.

3. run the program compiled in step 1: notice the message boxes
   displayed from the DLLs extracted to %windir% in step 2 and
   loaded by %windir%\SysWOW64\regedit.exe: the "application
   directory" of %windir%\SysWOW64\regedit.exe is %windir%\, NOT

   Or use the 32-bit NTSD.EXE run %windir%\regedit.exe: you'll see
   the message boxes too plus the debugger output as shown in

4. finally use the 64-bit NTSD.EXE to run %windir%\regedit.exe:
   see <http://home.arcor.de/skanthak/temp/REGEDIT.LOG> for the
   debugger output.

   Notice that the 32-bit forwarder DLLs are loaded in the 64-bit
   process and that their exports/forwards are processed properly!

   Their DllMain() extry points are but NOT called (if they were
   you'd see some message boxes)!

stay tuned
Stefan Kanthak

PS: the test whether 64-bit forwarder DLLs placed in %windir% are
    loaded in the 32-bit process %windir%\SysWOW64\regedit.exe is
    left as an exercise to the reader.