如何欺骗程序让它们认为它们在 32 位系统下运行?

如何欺骗程序让它们认为它们在 32 位系统下运行?

基本上,我的 Windows 7 64 位中有 3 个可执行文件,它们是:

加载程序-> 这是一个 32 位 exe 

执行文件-> 这是一个 32 位 exe

64 位版本-> 这是一个 64 位 exe

什么时候加载程序启动时,它会确定系统是 32 位还是 64 位,并加载相应的文件(执行文件或者64 位版本),因为我运行的是 64 位操作系统64 位版本将开始。

我想知道加载程序确定我的系统是 32 位还是 64 位?通过 API 调用最有可能是哪个Kernel32.IsWow64Process()

现在我必须让这个函数总是返回 FALSE,不仅是在全局范围内,加载程序,所以我希望出现类似“全局 api 钩子”的东西,使得函数始终返回 FALSE。

但我不知道该怎么做,我上次挂接某些东西是在 Windows 98 中,从那时起事情就发生了变化。

那么你知道如何 Hook 吗IsWow64Process()从而使该进程相信它正在 32 位环境中运行?

答案1

经过几个小时的思考,我终于搞清楚了 Windows API(以及未记录的 API)以及指针等,终于找到了解决办法。这有点棘手,因为IsWow64Process()在程序到达入口点之前,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 位。

他们这样做的方式是通过调用获取进程地址()

很遗憾,获取进程地址()在我的源代码中用于查找函数地址,挂钩该函数当然会导致不良行为,因此我们深入研究了未记录的 API,我们发现Kernel32.获取进程地址()调用ntdll.LdrGetProcedureAddress()

在网上读了一些内容后,我现在确信挂钩是安全的LdrGetProcedureAddress()

在我们的上钩LdrGetProcedureAddress()函数中我们检查调用者是否要求IsWow64Process并告诉调用者该函数的作用不是存在!

现在,我们需要将钩子注入到每个(新)进程中,我决定使用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\Software\哇6432节点\Microsoft\Windows NT\当前版本\Windows

我们设置加载应用程序初始化_DLL为 0x1 和AppInit_DLL 库到我们的 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;
}

答案2

您永远无法强制 64 位程序以 32 位运行。因为 64 位程序每次都汇编为 64 位指令。但是当您在 64 位处理器上运行 32 位程序时,操作系统会将 32 位系统调用转换为 64 位格式。此处已回答了相同的问题,请查看此内容。 强制应用程序在 64 位 Windows 上以 32 位进程运行

相关内容