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

Solution 1:

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;
}