
基本上我的 Windows 7 64 位元中有 3 個可執行文件,它們是:
載入程式-> 這是一個 32 位元 exe
x86.exe-> 這是一個 32 位元 exe
x64.exe-> 這是一個 64 位元 exe
什麼時候載入程式啟動時它會確定係統是 32 位元還是 64 位元並載入適當的檔案(x86.exe或者x64.exe),因為我運行的是 64 位元作業系統x64.exe將開始。
我想知道如何載入程式確定我的系統是 32 還是 64?這最有可能是透過 API 呼叫Kernel32.IsWow64Process()
現在我必須讓該函數在全球範圍內始終返回 FALSE,而不僅僅是為了載入程式,所以我希望有一些類似“全局 api 掛鉤”的東西,使該函數始終返回 FALSE。
但我不知道如何做到這一點,我上次掛鉤某些東西是在 Windows 98 中,從那時起事情就發生了變化。
那你知道如何 HookIsWow64Process()從而使進程相信它正在 32 位元環境中運行?
答案1
經過幾個小時的研究 Windows API(和未記錄的 API)以及指標等等,我終於找到如何做到這一點。這有點棘手,因為IsWow64Process()即使在程式到達其入口點之前,Windows也會在每個可執行檔上呼叫它,如果您只是反映FALSE,它就會崩潰。
但我注意到 Window 的呼叫來自加載的模組,透過這種方式,我可以限制我的鉤子僅在呼叫者是可執行檔時反映 FALSE。
以下是有關如何完成此操作的小指南:
取得我的鉤子的返回地址,並找出哪個模組呼叫了我的鉤子函數:
wchar_t RetAdr[256]; wsprintf(RetAdr, L"%p", _ReturnAddress()); HMODULE hModule; GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, RetAdr , &hModule);
取得 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 位元。
他們這樣做的方式是透過調用取得過程地址()。
很遺憾,取得過程地址()在我的原始程式碼中用於查找函數地址,掛鉤該函數當然會導致不良行為,因此我們更深入地研究了未記錄的 API,我們發現Kernel32.GetProcAddress()來電ntdll.LdrGetProcedureAddress()。
在網上閱讀了 abit 後,我現在確信掛鉤是安全的LdrGetProcedureAddress()。
在我們著迷的LdrGetProcedureAddress()我們檢查呼叫者是否要求的函數是Wow64進程並告訴呼叫者該函數的作用不是存在!
現在,我們需要將我們的鉤子注入到每個(新)進程中,我決定使用AppInit_DLL方法,因為我已經熟悉它並且它做得很好。
有很多關於AppInit_DLL在網路上,但它們都指的是 32 位,而且他們的解決方案在我的 Windows 7 64 位元作業系統上並不真正有效。為了讓您更輕鬆,以下是 32 位元和 64 位元 AppInit_DLL 的正確登錄路徑:
32位: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows
64位:HKEY_LOCAL_MACHINE\軟體\Wow6432節點\Microsoft\Windows NT\CurrentVersion\Windows
我們設定LoadAppInit_DLLs到 0x1 和AppInit_DLL到我們的 DLL 路徑。
這是最終的源代碼,它使用姆胡克庫:
#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;
}
答案2
您永遠不能強制 64 位元程式作為 32 位元運行。因為 64 位元程式一次被彙編為 64 位元指令。同樣的問題已在這裡得到回答,請查看。 強制應用程式在 64 位元 Windows 上以 32 位元進程運行