Search code examples
winapi64-bitsyswow64

How can a 64-bit process have a 32-bit view of file system and registry?


For backwards compatibility, my 64 process needs to see the the 32-bit view of the file system and registry.

I know how to make a 32-bit process see a 64-bit view of the file system and registry (using Wow64DisableWow64FsRedirection and Wow64RevertWow64FsRedirection)

But how do I make a 64 bit process have a 32 bit view of the file system and registry?


Solution

  • KEY_WOW64_32KEY works for 64 bit and 32 bit processes.

    From experiment, Wow64EnableWow64FsRedirection/Wow64DisableWow64FsRedirection doesn't seem to work in a 64 bit process - and the name suggests it only seems to work in an WOW64 process.

    So in order to have a 32 bit "view" of the file system from a 64 bit process the paths will need to be be altered to point to the correct locations

    This is really ugly, but here is a c++ code sample of how to perform the file system redirection according to Microsoft. Requires Boost.

    #include"boost/filesystem.hpp"
    #include"wstring"
    #include"shfolder.h"
    #include"Shlobj.h"
    bool redirectPathRoot( boost::filesystem::wpath pathFromRoot, boost::filesystem::wpath pathToRoot, boost::filesystem::wpath & pathToRedirect )
    {
    bool bPathWasRedirected = false;
    boost::filesystem::wpath theNewPath;
    boost::filesystem::wpath::iterator iPathToRedirect = pathToRedirect.begin();
    boost::filesystem::wpath::iterator iFromRoot = pathFromRoot.begin();
    bool bMatch = true;
    while( iPathToRedirect != pathToRedirect.end() && iFromRoot != pathFromRoot.end() && bMatch )
    {
        //
        // see if the root of the path we are checking matches 
        //
        bMatch = ( std::wstring(*iPathToRedirect++) == std::wstring(*iFromRoot++) );
    }
    if( bMatch && iFromRoot == pathFromRoot.end() )
    {
        theNewPath = pathToRoot;
        //
        // these guys need to be redirected
        //
        while( iPathToRedirect != pathToRedirect.end() )
        {
            theNewPath /= *iPathToRedirect++;
        }
        bPathWasRedirected = true;
        pathToRedirect = theNewPath;
    }
    return bPathWasRedirected;
    }
    std::wstring adjustPathFor32BitOn64BitProcess( LPCWSTR thePath )
    {
    std::wstring strPath(thePath);
    boost::to_lower(strPath);
    //
    // default to the original path
    //
    boost::filesystem::wpath theNewPath(strPath.c_str());
    theNewPath.normalize();
    //
    // init the supplied path
    //
    boost::filesystem::wpath pathToCheck( strPath.c_str() );
    pathToCheck.normalize();
    //
    // get the path for the 32 bit folder on a 64 bit system
    //
    wchar_t strTemp[MAX_PATH] = L"\0";
    GetSystemWow64Directory( strTemp, MAX_PATH );
    std::wstring strSysWow64 = strTemp;
    boost::to_lower( strSysWow64 );
    boost::filesystem::wpath pathSysWow64( strSysWow64.c_str() );
    pathSysWow64.normalize();
    
    //
    // get the path for the system directory
    //
    GetSystemDirectory( strTemp, MAX_PATH );
    std::wstring strSys = strTemp;
    boost::to_lower( strSys );
    boost::filesystem::wpath pathSys( strSys.c_str() );
    pathSys.normalize();
    
    //
    // get the path for the Program Files directory
    //
    SHGetFolderPath( NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_DEFAULT, strTemp);
    std::wstring strPrograms = strTemp;
    boost::to_lower( strPrograms );
    boost::filesystem::wpath pathPrograms( strPrograms.c_str() );
    pathPrograms.normalize();
    
    //
    // get the path for the Program Files x86 directory
    //
    SHGetFolderPath( NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_DEFAULT, strTemp);
    std::wstring strProgramsX86 = strTemp;
    boost::to_lower( strProgramsX86 );
    boost::filesystem::wpath pathProgramsX86( strProgramsX86.c_str() );
    pathProgramsX86.normalize();
    
    //
    // get the path for the Windows\lastgood\system32 directory
    //
    SHGetFolderPath( NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_DEFAULT, strTemp);
    std::wstring strWindows = strTemp;
    boost::to_lower( strWindows );
    boost::filesystem::wpath pathWindows( strWindows.c_str() );
    pathWindows.normalize();
    
    boost::filesystem::wpath pathWindowsLastGoodSystem32( strWindows.c_str() );
    pathWindowsLastGoodSystem32 /= L"lastgood";
    pathWindowsLastGoodSystem32 /= L"system32";
    pathWindowsLastGoodSystem32.normalize();
    
    boost::filesystem::wpath pathWindowsLastGoodSysWOW64( strWindows.c_str() );
    pathWindowsLastGoodSysWOW64 /= L"lastgood";
    pathWindowsLastGoodSysWOW64 /= L"syswow64";
    pathWindowsLastGoodSysWOW64.normalize();
    
    
    //
    // finally, regedit...
    //
    boost::filesystem::wpath pathRegedit( strWindows.c_str() );
    pathRegedit /= L"regedit.exe";
    pathRegedit.normalize();
    
    boost::filesystem::wpath pathRegeditSysWOW64( pathSysWow64 );
    pathRegeditSysWOW64 /= L"regedit.exe";
    pathRegeditSysWOW64.normalize();
    
    //
    // now see if the supplied path matches system directoy
    //
    boost::filesystem::wpath::iterator iPathToCheck = pathToCheck.begin();
    boost::filesystem::wpath::iterator iSys = pathSys.begin();
    bool bMatch = true;
    while( iPathToCheck != pathToCheck.end() && iSys != pathSys.end() && bMatch )
    {
        //
        // see if the beginning of the path we are checking matches the system path
        //
        bMatch = ( std::wstring(*iPathToCheck++) == std::wstring(*iSys++) );
    }
    if( bMatch && iSys == pathSys.end() )
    {
        //
        // the supplied path matches at least as far as the system dir...
        //
        if( iPathToCheck == pathToCheck.end() )
        {
            //
            // ...actually its an exact match, so redirect it
            //
            theNewPath = pathSysWow64;
        }
        else
        {
            //
            // ...however, there are a few exceptions....
            //
            boost::filesystem::wpath::iterator iTemp = iPathToCheck;
            if( 
                    !(
                        std::wstring(*iTemp) == L"drivers" && 
                        ( 
                            (++iTemp) != pathToCheck.end()  && 
                            std::wstring(*(iTemp)) == L"etc" 
                            )
                        ) 
                    &&
                    (std::wstring(*iPathToCheck) != L"catroot") &&
                    (std::wstring(*iPathToCheck) != L"catroot2") &&
                    (std::wstring(*iPathToCheck) != L"logfiles") &&
                    (std::wstring(*iPathToCheck) != L"spool")
                    )
            {
                //
                // all but the above dirs should be redirected
                //
                theNewPath = pathSysWow64;
                while( iPathToCheck != pathToCheck.end() )
                {
                    theNewPath /= *iPathToCheck++;
                }
            }
        }
    }
    else
    {
        //
        // didn't match the system dir... see if it matches the Program Files dir
        //
        if(!redirectPathRoot(  pathPrograms, pathProgramsX86, theNewPath ))
        {
            //
            // now try %windir%/lastgood/system32
            //
            if(!redirectPathRoot(  pathWindowsLastGoodSystem32, pathWindowsLastGoodSysWOW64, theNewPath ))
            {
                //
                // finally, regedit
                //
                redirectPathRoot(  pathRegedit, pathRegeditSysWOW64, theNewPath );
            }
        }
    
    }
    return theNewPath.file_string();}