How to trick programs into thinking they’re running under 32-bit

32-bit64-bitapibypasshook

Basically I have 3 executables in my Windows 7 64-bit, those are:

Loader.exe -> This is a 32-bit exe 

x86.exe -> This is a 32-bit exe

x64.exe -> This is a 64-bit exe

When Loader.exe starts it determines if the system is 32-bit or 64-bit and loads the appropriate file (either x86.exe or x64.exe), since I'm running a 64-bit operating system the x64.exe will start.

I'd like to know how Loader.exe determines if my system 32 or 64? Which is most likely through the API call Kernel32.IsWow64Process()

Now I have to make that function always return FALSE, on a global scale and not just for Loader.exe,
So I was hoping something along the lines of a "global api hook" which makes the function always return FALSE.

But I do not know how to do this, the last time I ever hooked something was in Windows 98 and things have changed since then.

So do you happen to know how to Hook IsWow64Process() and thereby making the process believe it is running in a 32bit environment?

Best Answer

After hours of wrapping my head around the Windows API (and undocumented API), as well as pointers and what not, I finally found out how to do it. It was kinda tricky, because IsWow64Process() is called by Windows on every executable even before the program reaches it's EntryPoint, if you just reflect FALSE it is going to crash.

But I noticed that the Window's calls are coming from loaded modules, and in this way I can restrict my hook to only reflect FALSE if the caller is an executable.

Here is a small guide on how it was done:

  1. Get the return address of my hook, and find out which module called my hooked function:

    wchar_t RetAdr[256];
    wsprintf(RetAdr, L"%p", _ReturnAddress());
    
    HMODULE hModule;
    GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, RetAdr , &hModule);
    
  2. Take the ModuleFileName, check if it contains ".exe" and put "Wow64Process" variable to FALSE if it is an executable:

    wchar_t mName[MAX_PATH];
    GetModuleFileName(hModule, mName, sizeof(mName));
    
    const wchar_t *shortName = L".exe";
    BOOL res = TRUE;
    
    if(wcsstr(mName,shortName) == NULL)
         res = Orig_IsWow64Process(hProcess, Wow64Process);
    else
        *Wow64Process = FALSE;
    
    
    return res;
    

But here is another problem, IsWow64Process() does only exist on Windows 64-bit operating systems, so most programs that actually check if the operating system is 64-bit do not run that function, instead they ask if the function is available and thereby determine if the system is 32-bit or 64-bit.

The way they do this is by calling GetProcAddress().

Unfortunately, GetProcAddress() is used in my source code to find function addresses, and hooking the function will of course result in undesired behaviour, so we delve a little deeper into the undocumented API and we find out that Kernel32.GetProcAddress() calls ntdll.LdrGetProcedureAddress().

After reading abit on the net, I am now sure that it is safe to hook LdrGetProcedureAddress().

In our hooked LdrGetProcedureAddress() function we check if the caller is asking for IsWow64Process and tell the caller that the function does NOT exist!

Now, we need to inject our hook into every (new) process, I decided to use the AppInit_DLLs method because I am already familiar with it and it does the job very well.

Theres alot of information about AppInit_DLLs on the web, but all of them refer to 32bit and their solution does not really work on my Windows 7 64-bit OS. To make it easier for you, here are the correct registry paths for 32-bit and 64-bit AppInit_DLLs:

32-bit: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows

64-bit: HKEY_LOCAL_MACHINE\Software\ Wow6432Node \Microsoft\Windows NT\CurrentVersion\Windows

We set LoadAppInit_DLLs to 0x1 and AppInit_DLLs to our DLL path.

Here is the final source code, it uses mhook library :

#include "stdafx.h"
#include "mhook/mhook-lib/mhook.h"

#include <intrin.h>

#ifdef __cplusplus
extern "C"
#endif
void * _ReturnAddress(void);

#pragma intrinsic(_ReturnAddress)

//////////////////////////////////////////////////////////////////////////
// Defines and typedefs
typedef NTSTATUS (NTAPI* _ldrGPA)(IN HMODULE ModuleHandle, IN PANSI_STRING FunctionName                 
OPTIONAL, IN WORD Oridinal OPTIONAL, OUT PVOID *FunctionAddress ); 

typedef BOOL (WINAPI *_IsWow64Process)(
  __in   HANDLE hProcess,
  __out  PBOOL Wow64Process
);


//////////////////////////////////////////////////////////////////////////
// Original function

PVOID HookWow, OrigWow; 

_IsWow64Process Orig_IsWow64Process = (_IsWow64Process)
GetProcAddress(GetModuleHandle(L"Kernel32"), "IsWow64Process");

_ldrGPA Orig_ldrGPA = (_ldrGPA)
GetProcAddress(GetModuleHandle(L"ntdll"), "LdrGetProcedureAddress");

//////////////////////////////////////////////////////////////////////////
// Hooked function
NTSTATUS NTAPI Hooked_ldrGPA(IN HMODULE ModuleHandle, IN PANSI_STRING FunctionName 
OPTIONAL, IN WORD Oridinal OPTIONAL, OUT PVOID *FunctionAddress)
{
//16:00 check if FunctionName equals IsWow64Process then return NULL

return Orig_ldrGPA(ModuleHandle,OPTIONAL FunctionName, OPTIONAL Oridinal,      
                        FunctionAddress); 
}



BOOL WINAPI HookIsWow64Process(
  __in   HANDLE hProcess,
  __out  PBOOL Wow64Process
)
{
HMODULE hModule;

wchar_t RetAdr[256];
wsprintf(RetAdr, L"%p", _ReturnAddress());

GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, RetAdr , &hModule);

wchar_t mName[MAX_PATH];
GetModuleFileName(hModule, mName, sizeof(mName));

const wchar_t *shortName = L".exe";
BOOL res = TRUE;

if(wcsstr(mName,shortName) == NULL)
     res = Orig_IsWow64Process(hProcess, Wow64Process);
else
    *Wow64Process = FALSE;


return res;
}



//////////////////////////////////////////////////////////////////////////
// Entry point

BOOL WINAPI DllMain(
__in HINSTANCE  hInstance,
__in DWORD      Reason,
__in LPVOID     Reserved
)
{        
switch (Reason)
{
case DLL_PROCESS_ATTACH:
    OrigWow = Orig_IsWow64Process;
    HookWow = HookIsWow64Process;
    Mhook_SetHook((PVOID*)&Orig_IsWow64Process, HookIsWow64Process);
    Mhook_SetHook((PVOID*)&Orig_ldrGPA, Hooked_ldrGPA);
    break;

case DLL_PROCESS_DETACH:
    Mhook_Unhook((PVOID*)&Orig_IsWow64Process);
    Mhook_Unhook((PVOID*)&Orig_ldrGPA);
    break;
}

return TRUE;
}