題 如何讓程序認為它們在32位下運行?


基本上我在Windows 7 64位中有3個可執行文件,它們是:

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而不僅僅是for Loader.exe是, 所以我希望有一個“全局api鉤子”的東西,這使得函數總是返回FALSE。

但是我不知道怎麼做,上次我曾經在Windows 98中搞過一些東西,從那時起事情發生了變化。

所以你碰巧知道如何胡克 IsWow64Process() 從而使該過程相信它在32位環境中運行?


7
2017-07-04 11:20


起源


這取決於操作系統。大多數程序只為32/64位系統分配一個單獨的二進製文件,分配方法決定使用哪個(再次,因操作系統而異) - Bob
對不起,我忘了提到它是Windows 7.並且有一個“加載器”可執行文件,它決定運行哪個版本 - Æless Norm
我認為有意義的答案你需要解釋為什麼你要“欺騙程序思考... 32位” - Martin
你可以編輯你的問題並將答案移到答案部分嗎? - Sathya♦
@ÆlessNorm如果您碰巧回來,請在此留言,我們可以將答案重新歸因於您的用戶帳戶。 - nhinkle♦


答案:


經過幾個小時的圍繞Windows API(和未記錄的API),以及指針和什麼沒有,我終於找到瞭如何做到這一點。 這有點棘手,因為 IsWow64Process() 甚至在程序到達它的EntryPoint之前,Windows就會在每個可執行文件上調用它,如果你只是反映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() 僅存在於Windows 64位操作系統上,因此大多數實際檢查操作系統是否為64位的程序都不運行該功能,而是詢問該功能是否可用,從而確定係統是32位還是64位。

他們這樣做的方式是打電話 GetProcAddress的()

不幸, GetProcAddress的() 在我的源代碼中用於查找函數地址,掛鉤函數當然會導致不良行為,因此我們深入研究了未記錄的API,我們發現了 Kernel32.GetProcAddress() 電話 ntdll.LdrGetProcedureAddress()

在網上閱讀了abit之後,我現在確信它是安全的 LdrGetProcedureAddress()

在我們迷上了 LdrGetProcedureAddress() 函數我們檢查調用者是否要求 IsWow64Process 並告訴呼叫者該功能  存在!

現在,我們需要將鉤子注入每個(新)進程,我決定使用 AppInit_DLLs 方法,因為我已經熟悉它,它做得很好。

有很多關於的信息 AppInit_DLLs 在網絡上,但所有這些都是指32位,他們的解決方案並不適用於我的Windows 7 64位操作系統。 為了使您更容易,這裡是32位和64位AppInit_DLL的正確註冊表路徑:

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

7
2017-07-28 18:25





你永遠不能強迫64位程序作為32位運行。因為64位程序一次組裝為64位指令。但是當您在64位處理器上運行32位程序時,操作系統會將32位系統調用轉換為64位格式。這裡已經回答了同樣的問題。 強制應用程序在64位Windows上以32位進程運行


0
2017-07-04 11:34



確切地說,除非模仿,否則會使它變得極其緩慢...... - Tom Wijsman
請標記重複的問題,而不是回答它們。謝謝。 - ChrisF
正確理解我,我不是強迫64位編譯程序在32位環境下運行。我強迫loader.exe相信系統是32位,因此加載32位版本的程序而不是64位。 - Æless Norm
@ÆlessNorm我以為你解釋得很好。你是 不 試圖強制x64.exe以32位運行。您正在嘗試強制使用Loader.exe 是 一個32位程序總是選擇在64位環境中加載x86.exe 32位程序...我特別不明白為什麼這個答案被投票,當它提供了相同問題的鏈接時 您 指出你的問題是明確的 不 重複的。 - Bon Gart
@ÆlessNorm讓我問你一個問題,如果你想運行32位程序,為什麼不刪除x64.exe並單獨使用x32.exe。 - arundevma