如何诱使程序认为它们在 32 位下运行?

Æle*_*orm 7 64-bit 32-bit api hook bypass

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

Loader.exe -> 这是一个 32 位的 exe 

x86.exe -> 这是一个 32 位的 exe

x64.exe -> 这是一个 64 位的 exe

Loader.exe启动时,它会确定系统是 32 位还是 64 位并加载适当的文件(x86.exex64.exe),因为我运行的是 64 位操作系统x64.exe将开始。

我想知道Loader.exe如何确定我的系统是 32 还是 64?最有可能通过 API 调用Kernel32.IsWow64Process()

现在我必须让该函数在全球范围内始终返回 FALSE,而不仅仅是对于Loader.exe,所以我希望能够使该函数始终返回 FALSE 的“全局 api 挂钩”。

但我不知道如何做到这一点,我最后一次在 Windows 98 中迷上了某些东西,从那时起事情发生了变化。

那么您是否碰巧知道如何挂钩IsWow64Process()从而使该进程相信它是在 32 位环境中运行的?

Æle*_*orm 8

经过几个小时的围绕 Windows API(和未记录的 API)以及指针和其他内容的思考,我终于找到了如何去做。这有点棘手,因为即使在程序到达它的 EntryPoint 之前,Windows 在每个可执行文件上都会调用IsWow64Process(),如果你只反映 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);
    
    Run Code Online (Sandbox Code Playgroud)
  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;
    
    Run Code Online (Sandbox Code Playgroud)

但这里还有一个问题,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;
}
Run Code Online (Sandbox Code Playgroud)


aru*_*vma 0

您永远不能强制 64 位程序作为 32 位运行。因为64位程序一次被汇编为64位指令。但是当您在64位处理器上运行32位程序时,操作系统会将32位系统调用转换为64位格式。同样的问题已在这里得到回答,请查看。 强制应用程序在 64 位 Windows 上以 32 位进程运行

  • 请标记重复的问题,而不是回答它们。谢谢。 (7认同)
  • @ÆlessNorm 我认为你很好地解释了自己。您**不**尝试强制 x64.exe 以 32 位运行。您试图强制 Loader.exe,它*是*一个 32 位程序,在 64 位环境中始终选择加载 x86.exe 32 位程序...我特别不明白为什么这个答案被投票赞成,当它提供指向同一问题的链接时 **YOU** 指出您的问题明确 **NOT** 重复。 (4认同)
  • 正确理解我的意思,我并不是强迫 64 位编译的程序在 32 位环境下运行。我强制 loader.exe 相信系统是 32 位,因此加载程序的 32 位版本而不是 64 位版本。 (2认同)