【问题标题】:HeapAlloc hooking with miniHook, deadlock on Windows 10, works on Windows 7HeapAlloc 与 miniHook 挂钩,Windows 10 上的死锁,适用于 Windows 7
【发布时间】:2021-12-18 15:06:48
【问题描述】:

我有一个最奇特的错误...我正在挂钩 HeapAlloc 以记录所有调用并获取调用 API 的 DLL 的名称。该代码适用于 Windows 7,但不适用于 Windows 10。我使用 miniHook 进行挂钩。使用 Visual Studio 2019 v142 编译的所有内容。

// BasicTest.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <windows.h>
#include <iostream>
#include <intrin.h>
#include <psapi.h>
#include "minihook.h"

#pragma intrinsic(_ReturnAddress)
#pragma comment(lib, "libMinHook.x64.lib") //v142

LPVOID(WINAPI* OldHeapAlloc)(HANDLE, DWORD, SIZE_T);

template <typename T>
inline MH_STATUS MH_CreateHookApiEx(
    LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, T** ppOriginal)
{
    return MH_CreateHookApi(
        pszModule, pszProcName, pDetour, reinterpret_cast<LPVOID*>(ppOriginal));
}

BOOL intercept = FALSE;
int iMbox = 0;
int iTotal = 0;

LPVOID HookedHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) {
    iTotal++;
    LPVOID ptr = OldHeapAlloc(hHeap, dwFlags, dwBytes);
    if (intercept) {
        return ptr;
    }

    intercept = TRUE;
    iMbox++;

    HMODULE hModule;
    char lpBaseName[32];

    if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)_ReturnAddress(), &hModule) != 0) {
        if (GetModuleBaseNameA(GetCurrentProcess(), hModule, lpBaseName, sizeof(lpBaseName)) != 0) {
            printf("Reserved %d at %08x from %s\n", dwBytes, ptr, lpBaseName);
        }
    }
    intercept = FALSE;

    return ptr;
}

int main()
{
    if (MH_Initialize() != MH_OK)
    {
        return 1;
    }

    if (MH_CreateHookApiEx(
        L"ntdll.dll", "RtlAllocateHeap", &HookedHeapAlloc, &OldHeapAlloc) != MH_OK)
    {
        return 1;
    }

    if (MH_EnableHook(MH_ALL_HOOKS) != MH_OK)
    {
        return 1;
    }

    MessageBoxA(NULL, "This is a test", "Test", MB_OK);

    MH_DisableHook(MH_ALL_HOOKS);
    printf("RtlAllocateHeap calls for MessageBoxA = %d\n", iMbox);
    printf("RtlAllocateHeap total calls  = %d\n", iTotal);

    return 0;
}

intercept是防止HookedHeapAlloc内部再次发生。因为GetModule* 喜欢函数调用HeapAlloc。重要的是要注意,如果您自己调用 HeapAlloc,即使重复(HeapAlloc -> HeapAlloc -> HeapAlloc),代码也可以工作。您可以调用HeapAlloc 5000 次,并在HookedHeapAlloc 中放入深度为5 的递归(拦截可防止任何崩溃)。

但是当使用MessageBoxA时,程序在Windows 10上挂了(在20H2和21H1测试)。

Windows 7 上的输出是这样的

[.......]
Reserved 24 at 004528f0 from KERNELBASE.dll
Reserved 40 at 0046afb0 from KERNELBASE.dll
Reserved 520 at 02aae4f0 from uxtheme.dll
Reserved 512 at 0046dd90 from IMM32.DLL
Reserved 48 at 00468960 from ntdll.dll
Reserved 48 at 004689a0 from ntdll.dll
Reserved 512 at 004612a0 from USER32.dll
Reserved 48 at 004689e0 from ntdll.dll
Reserved 48 at 00468a20 from ntdll.dll
Reserved 48 at 00468a60 from ntdll.dll
RtlAllocateHeap calls for MessageBoxA = 828
RtlAllocateHeap total calls  = 1657

在 Windows 10 上,程序在几次输出后挂起。在调试器中时,它会挂在ZwWaitForAlertByThreadId

感谢您的帮助:)

【问题讨论】:

  • 值得注意的是,挂钩在 x64 Windows 上明确支持。因此,不仅不支持,而且 MS 已明确表示他们将尽其所能阻止它。
  • 哼,我不知道。谢谢(你的)信息。但即使 Windows 不想要它,我也会让它工作 xD
  • 请注意 MS 系统 DLL 利用hardware features to prevent this 我已经在我自己的硬件上验证了这对这两个版本上的所有 Windows 二进制文件都启用了。 More info on them blocking this。它们也是在启用Control flow guard 的情况下构建的。

标签: c++ windows hook


【解决方案1】:

所以,回答我自己的问题。我发现了这个问题。 GetModuleHandleExA 增加模块的引用计数。事实证明,如果将引用计数增加太多,就会出现死锁。我不知道为什么...添加标志GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 解决了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2011-08-03
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多