Как заставить программы думать, что они работают под 32-битной версией?

В основном у меня есть 3 исполняемых файла в моей Windows 7 64-битных, это:

Loader.exe -> Это 32-битный exe

x86.exe -> Это 32-битный exe

x64.exe -> Это 64-битный exe

Когда запускается Loader.exe, он определяет, является ли система 32-битной или 64-битной, и загружает соответствующий файл (x86.exe или x64.exe), так как я использую 64-битную операционную систему, x64.exe будет Начните.

Я хотел бы знать, как Loader.exe определяет, является ли моя система 32 или 64? Что, скорее всего, через вызов API Kernel32.IsWow64Process()

Теперь я должен заставить эту функцию всегда возвращать FALSE, в глобальном масштабе, а не только для Loader.exe, поэтому я надеялся, что что-то будет в духе "глобального API-хука", который заставит функцию всегда возвращать FALSE.

Но я не знаю, как это сделать, последний раз, когда я что-то подключал, был в Windows 98, и с тех пор все изменилось.

Так вы случайно не знаете, как подключить IsWow64Process () и тем самым заставить процесс поверить, что он работает в 32-битной среде?

2 ответа

После нескольких часов работы над Windows API (и недокументированным API), а также указателями и прочим, я наконец-то узнал, как это сделать. Это было довольно сложно, потому что IsWow64Process() вызывается Windows на каждом исполняемом файле еще до того, как программа достигает ее EntryPoint, если вы просто отразите FALSE, то произойдет сбой.

Но я заметил, что вызовы Window поступают из загруженных модулей, и таким образом я могу ограничить свой хук только отражением FALSE, если вызывающий является исполняемым файлом.

Вот небольшое руководство о том, как это было сделано:

  1. Получить адрес возврата моего хука и выяснить, какой модуль вызвал мою перехваченную функцию:

    wchar_t RetAdr[256];
    wsprintf(RetAdr, L"%p", _ReturnAddress());
    
    HMODULE hModule;
    GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, RetAdr , &hModule);
    
  2. Возьмите ModuleFileName, проверьте, содержит ли он ".exe" и поместите переменную "Wow64Process" в FALSE, если это исполняемый файл:

    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;
    

Но есть и другая проблема: IsWow64Process() существует только в 64-битных операционных системах Windows, поэтому большинство программ, которые фактически проверяют, является ли операционная система 64-битной, не запускают эту функцию, вместо этого они спрашивают, доступна ли эта функция, и тем самым определить, является ли система 32-битной или 64-битной.

Они делают это путем вызова GetProcAddress ().

К сожалению, GetProcAddress () используется в моем исходном коде для поиска адресов функций, и перехват функции, конечно, приведет к нежелательному поведению, поэтому мы углубимся в недокументированный API и выясним, что Kernel32.GetProcAddress() вызывает ntdll..LdrGetProcedureAddress().

После прочтения abit в сети я теперь уверен, что перехватывать LdrGetProcedureAddress() безопасно.

В нашей перехваченной функции LdrGetProcedureAddress() мы проверяем, запрашивает ли вызывающий объект IsWow64Process, и сообщаем вызывающему, что функция НЕ существует!

Теперь нам нужно внедрить наш хук в каждый (новый) процесс, я решил использовать метод AppInit_DLLs, потому что я уже знаком с ним, и он отлично справляется со своей задачей.

В Интернете много информации о AppInit_DLL, но все они относятся к 32-битной версии, и их решение не работает на моей 64-битной ОС Windows 7. Чтобы вам было проще, вот правильные пути реестра для 32-битных и 64-битных AppInit_DLLs:

32-разрядная версия: HKEY_LOCAL_MACHINE \ Software \ Microsoft \ Windows NT \ CurrentVersion \ Windows

64-разрядная версия: HKEY_LOCAL_MACHINE \ Software \ Wow6432Node \ Microsoft \ Windows NT \ CurrentVersion \ Windows

Мы устанавливаем LoadAppInit_DLLs в 0x1 и AppInit_DLLs в наш путь к DLL.

Вот окончательный исходный код, он использует библиотеку mhook:

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

Вы никогда не сможете принудительно запустить 64-битную программу как 32-битную. Потому что 64-битные программы собираются как 64-битные инструкции за раз. Но когда вы запускаете 32-битную программу на 64-битном процессоре, ОС конвертирует 32-битные системные вызовы в 64-битный формат. Здесь ответили на тот же вопрос. Принудительно запустить приложение в 32-битном процессе в 64-битной Windows

Другие вопросы по тегам