用户态下屏蔽全局消息钩子 —— ClientLoadLibrary 指针覆盖

news2024/12/29 11:00:52

目录

前言

一、研究 SetWindowsHookEx 的机制

二、概念验证

三、运行效果分析

四、总结与展望

参考文献


原文出处链接:[https://blog.csdn.net/qq_59075481/article/details/139206017]

前言

SetWindowsHookEx 函数帮助其他人员注入模块到我们的进程,或者对我们的消息进行拦截处理。如何屏蔽 SetWindowsHookEx 函数是一件让人头疼的事情,长期以来,我们关注于拦截 CreateRemoteThread 和 CreateThreadEx 等函数的模块注入。通过一个名为 ClientLoadLibrary 的指针覆盖,我们将接管默认的 Win32k 钩子链处理机构,并实现我们自定义的处理模式。这本身属于一种 API HOOK。

拦截 SetWindowsHookEx 函数的官方方法是在系统或程序运行的早期,安装一个 WH_DEBUG 类型的 Win32 钩子,这将允许你捕获后面几乎所有 Win32 钩子的挂钩过程(除了WH_KEYBOARD_LL 低级键盘钩子无法拦截以外),具体可以参考这里的文章以及微软的文档。

一、研究 SetWindowsHookEx 的机制

首先是一种触发操作时的调用堆栈,可以看出间接调用了 __ClientLoadLibrary 指针指向的函数,然后依次调用钩子回调队列中的函数。

kernel32!LoadLibraryExW
USER32!__ClientLoadLibrary
ntdll!KiUserCallbackDispatcher
nt!KiCallUserMode
nt!KeUserModeCallback
win32k!ClientLoadLibrary
win32k!xxxLoadHmodIndex
win32k!xxxCallHook2
win32k!xxxCallHook

... ...

方法就是修改 user32!apfnDispatch 数组,直接替换 __ClientLoadLibrary 指向的函数指针。

这个数组其实是 PEB 的 KernelCallbackTable,而他们都没有文档化,所以偏移需要区分操作系统的版本。

获取 __ClientLoadLibrary 在数组中的 index 将稍微繁琐点,我们需要把我们关心的系统用 windbg带上符号都看一眼才能知道是多少了。我这里提供 Win11 系统中 __ClientLoadLibrary 在数组中的 index:0x258。

PEB 中 KernelCallbackTable 的偏移可以通过 WinDbg 或者 Vergilius Project | Kernels 获取。但是 __ClientLoadLibrary 在数组中的 index 则只能通过 WinDbg 或者调试符号获取。

KernelCallbackTable 结构体

KernelCallbackTable 可以在 PEB 中找到, 在 0x058 偏移处:

lkd> dt_PEB

2

lkd> dt_PEB @$peb kernelcallbacktable

2

KernelCallbackTable 是函数指针表:

lkd> dqs 0x00007ffa`29123070 L60
00007ffa`29123070  00007ffa`290c2bd0 user32!_fnCOPYDATA
00007ffa`29123078  00007ffa`2911ae70 user32!_fnCOPYGLOBALDATA
00007ffa`29123080  00007ffa`290c0420 user32!_fnDWORD
00007ffa`29123088  00007ffa`290c5680 user32!_fnNCDESTROY
00007ffa`29123090  00007ffa`290c96a0 user32!_fnDWORDOPTINLPMSG
00007ffa`29123098  00007ffa`2911b4a0 user32!_fnINOUTDRAG
//....

通过重写 ClientLoadLibrary 函数并覆盖 __ClientLoadLibrary 指针来达到挂钩调用我们的例程。

此函数仅接受 1 个参数,即指向进程堆栈中分配的未记录结构的指针。它保存 DLL 的路径、指向通知函数的指针以及一些尚不清楚的数据。

typedef struct _CLientLoadLibraryParam
{
	DWORD dwSize;//+0
	DWORD dwStringLength; //+4
	DWORD ReservedZero1;//+8
	DWORD ReservedZero2;//+C
	DWORD ReservedZero3;//+10
	DWORD ReservedZero4;//+14
	DWORD ReservedZero5;//+18 () +1A () //不需要!
	DWORD ReservedZero6;//+1C
	DWORD ReservedZero8;//+20
	DWORD test[3]; // 占位
	ULONG_PTR ptrDllString;//+30
	DWORD ReservedZero11[5];
    ULONG_PTR ptrApiString;//+40
	WCHAR szDllName[MAX_PATH];
	WCHAR szApiName[MAX_PATH];
}CLientLoadLibraryParam, * PCLientLoadLibraryParam;

关于这部分的早期的研究是这样的:

反 SetWindowsHookEx DLL 注入成为可能 😀 。

在花了一些时间逆向 user32 内部结构后,我发现了这个未记录的函数。此函数负责将 SetWindowsHookEx() 注册的 DLL 加载到您的进程中。本博客将仅关注实际 DLL 加载发生的用户模式。

user32.__ClientLoadLibrary(lpHook)

此函数仅接受 1 个参数,即指向进程堆栈中分配的未记录结构的指针。它保存 DLL 的路径、指向通知函数的指针以及一些尚不清楚的数据。

_USERHOOK struct
    unknown_00	DWORD ?	           ; 0x00
    unknown_04	DWORD ?	           ; 0x04
    nCount	DWORD ?	           ; 0x08 numbers of pointer to fix up
    unknown_0C	DWORD ?	           ; 0x0C
    offCbkPtrs	DWORD ?	           ; 0x10 offset to callback pointers
    bFixed	DWORD ?	           ; 0x14 indicates if the pointer is fixed
    lpDLLPath	UNICODE_STRING {}  ; 0x18 DLL path
    lpfnNotify	DWORD ?	           ; 0x20 offset to notification procedure
                                     (called when DLL is injected)
_USERHOOK ends

在函数的开头,它检查 _USERHOOK.nCount 和 _USERHOOK.bFixed 值。然后它调用 FixupCallbackPointers。

user32.FixupCallbackPointers(lpHook)

它只接受 1 个参数,与传递给 __ClientLoadLibrary 的参数相同。此函数以一种非常有趣的方式“修复”指针。首先,它定位回调指针的地址。

lpCbkPtrs = lpHook + offCbkPtrs

然后它循环遍历指针列表并通过解析实际地址的偏移量来修复它。

新地址 = lpHook + 偏移量

修复所有指针后,我们返回到__ClientLoadLibrary,然后调用InitUserApiHook。

user32.InitUserApiHook(hModule,lpfnNotify)

它调用 ResetUserApiHook,用参数 1 给出的函数地址填充数组。之后,它调用 (hModule + lpfnNotify) 指向的通知函数 __Unknown_DllInjected,并将地址数组作为参数 2 传递。

__Unknown_DllInjected(lpvReserved,lpFuncList)

user32.ResetUserApiHook(lpFuncList)

填充指针lpFuncList给出的数组。

__UserFuncList struct
    lSize DWORD ?    ; size of the list
    ...              ; array of function address
__UserFuncList  ends

大部分内容仍未说明。欢迎您在此处发布我未说明的任何内容。下面附上了一个示例,它挂钩 __ClientLoadLibrary,打印出试图加载到其中的 DLL,并拒绝加载它。反 SetWindowsHookEx DLL 注入,是吗?😀 需要使用 DebugView 才能查看转储。

二、概念验证

下面的 POC 代码创建一个普通窗口,只允许位于 "C:\Windows\System32" 目录下的模块加载,并构建一个模块加载白名单用于记录用户允许额外加载的模块。

#include <windows.h>
#include <string>
#include <Shlwapi.h>
#include <Softpub.h> // WinTrust.h 依赖于 Softpub.h
#include <wincrypt.h>
#include <iostream>
#include <unordered_map>
#include <mutex>

#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "Wintrust.lib")

using namespace std;

typedef VOID(WINAPI* fct_clLoadLib)(VOID*);

fct_clLoadLib _ClientLoadLibrary;
ULONG_PTR _ClientLoadLibrary_addr;
unordered_map<wstring, bool> moduleWhitelist;

// 互斥锁
mutex mtx;

// 控制弹窗处理状态的全局变量
bool isMessageBoxHandling = false;

typedef struct _KERNELCALLBACKTABLE_T {
    ULONG_PTR __fnCOPYDATA;
    ULONG_PTR __fnCOPYGLOBALDATA;
    ULONG_PTR __fnDWORD;
    ULONG_PTR __fnNCDESTROY;
    ULONG_PTR __fnDWORDOPTINLPMSG;
    ULONG_PTR __fnINOUTDRAG;
    ULONG_PTR __fnGETTEXTLENGTHS;
    ULONG_PTR __fnINCNTOUTSTRING;
    ULONG_PTR __fnPOUTLPINT;
    ULONG_PTR __fnINLPCOMPAREITEMSTRUCT;
    ULONG_PTR __fnINLPCREATESTRUCT;
    ULONG_PTR __fnINLPDELETEITEMSTRUCT;
    ULONG_PTR __fnINLPDRAWITEMSTRUCT;
    ULONG_PTR __fnPOPTINLPUINT;
    ULONG_PTR __fnPOPTINLPUINT2;
    ULONG_PTR __fnINLPMDICREATESTRUCT;
    ULONG_PTR __fnINOUTLPMEASUREITEMSTRUCT;
    ULONG_PTR __fnINLPWINDOWPOS;
    ULONG_PTR __fnINOUTLPPOINT5;
    ULONG_PTR __fnINOUTLPSCROLLINFO;
    ULONG_PTR __fnINOUTLPRECT;
    ULONG_PTR __fnINOUTNCCALCSIZE;
    ULONG_PTR __fnINOUTLPPOINT5_;
    ULONG_PTR __fnINPAINTCLIPBRD;
    ULONG_PTR __fnINSIZECLIPBRD;
    ULONG_PTR __fnINDESTROYCLIPBRD;
    ULONG_PTR __fnINSTRING;
    ULONG_PTR __fnINSTRINGNULL;
    ULONG_PTR __fnINDEVICECHANGE;
    ULONG_PTR __fnPOWERBROADCAST;
    ULONG_PTR __fnINLPUAHDRAWMENU;
    ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD;
    ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD_;
    ULONG_PTR __fnOUTDWORDINDWORD;
    ULONG_PTR __fnOUTLPRECT;
    ULONG_PTR __fnOUTSTRING;
    ULONG_PTR __fnPOPTINLPUINT3;
    ULONG_PTR __fnPOUTLPINT2;
    ULONG_PTR __fnSENTDDEMSG;
    ULONG_PTR __fnINOUTSTYLECHANGE;
    ULONG_PTR __fnHkINDWORD;
    ULONG_PTR __fnHkINLPCBTACTIVATESTRUCT;
    ULONG_PTR __fnHkINLPCBTCREATESTRUCT;
    ULONG_PTR __fnHkINLPDEBUGHOOKSTRUCT;
    ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX;
    ULONG_PTR __fnHkINLPKBDLLHOOKSTRUCT;
    ULONG_PTR __fnHkINLPMSLLHOOKSTRUCT;
    ULONG_PTR __fnHkINLPMSG;
    ULONG_PTR __fnHkINLPRECT;
    ULONG_PTR __fnHkOPTINLPEVENTMSG;
    ULONG_PTR __xxxClientCallDelegateThread;
    ULONG_PTR __ClientCallDummyCallback;
    ULONG_PTR __fnKEYBOARDCORRECTIONCALLOUT;
    ULONG_PTR __fnOUTLPCOMBOBOXINFO;
    ULONG_PTR __fnINLPCOMPAREITEMSTRUCT2;
    ULONG_PTR __xxxClientCallDevCallbackCapture;
    ULONG_PTR __xxxClientCallDitThread;
    ULONG_PTR __xxxClientEnableMMCSS;
    ULONG_PTR __xxxClientUpdateDpi;
    ULONG_PTR __xxxClientExpandStringW;
    ULONG_PTR __ClientCopyDDEIn1;
    ULONG_PTR __ClientCopyDDEIn2;
    ULONG_PTR __ClientCopyDDEOut1;
    ULONG_PTR __ClientCopyDDEOut2;
    ULONG_PTR __ClientCopyImage;
    ULONG_PTR __ClientEventCallback;
    ULONG_PTR __ClientFindMnemChar;
    ULONG_PTR __ClientFreeDDEHandle;
    ULONG_PTR __ClientFreeLibrary;
    ULONG_PTR __ClientGetCharsetInfo;
    ULONG_PTR __ClientGetDDEFlags;
    ULONG_PTR __ClientGetDDEHookData;
    ULONG_PTR __ClientGetListboxString;
    ULONG_PTR __ClientGetMessageMPH;
    ULONG_PTR __ClientLoadImage;
    ULONG_PTR __ClientLoadLibrary;
    ULONG_PTR __ClientLoadMenu;
    ULONG_PTR __ClientLoadLocalT1Fonts;
    ULONG_PTR __ClientPSMTextOut;
    ULONG_PTR __ClientLpkDrawTextEx;
    ULONG_PTR __ClientExtTextOutW;
    ULONG_PTR __ClientGetTextExtentPointW;
    ULONG_PTR __ClientCharToWchar;
    ULONG_PTR __ClientAddFontResourceW;
    ULONG_PTR __ClientThreadSetup;
    ULONG_PTR __ClientDeliverUserApc;
    ULONG_PTR __ClientNoMemoryPopup;
    ULONG_PTR __ClientMonitorEnumProc;
    ULONG_PTR __ClientCallWinEventProc;
    ULONG_PTR __ClientWaitMessageExMPH;
    ULONG_PTR __ClientWOWGetProcModule;
    ULONG_PTR __ClientWOWTask16SchedNotify;
    ULONG_PTR __ClientImmLoadLayout;
    ULONG_PTR __ClientImmProcessKey;
    ULONG_PTR __fnIMECONTROL;
    ULONG_PTR __fnINWPARAMDBCSCHAR;
    ULONG_PTR __fnGETTEXTLENGTHS2;
    ULONG_PTR __fnINLPKDRAWSWITCHWND;
    ULONG_PTR __ClientLoadStringW;
    ULONG_PTR __ClientLoadOLE;
    ULONG_PTR __ClientRegisterDragDrop;
    ULONG_PTR __ClientRevokeDragDrop;
    ULONG_PTR __fnINOUTMENUGETOBJECT;
    ULONG_PTR __ClientPrinterThunk;
    ULONG_PTR __fnOUTLPCOMBOBOXINFO2;
    ULONG_PTR __fnOUTLPSCROLLBARINFO;
    ULONG_PTR __fnINLPUAHDRAWMENU2;
    ULONG_PTR __fnINLPUAHDRAWMENUITEM;
    ULONG_PTR __fnINLPUAHDRAWMENU3;
    ULONG_PTR __fnINOUTLPUAHMEASUREMENUITEM;
    ULONG_PTR __fnINLPUAHDRAWMENU4;
    ULONG_PTR __fnOUTLPTITLEBARINFOEX;
    ULONG_PTR __fnTOUCH;
    ULONG_PTR __fnGESTURE;
    ULONG_PTR __fnPOPTINLPUINT4;
    ULONG_PTR __fnPOPTINLPUINT5;
    ULONG_PTR __xxxClientCallDefaultInputHandler;
    ULONG_PTR __fnEMPTY;
    ULONG_PTR __ClientRimDevCallback;
    ULONG_PTR __xxxClientCallMinTouchHitTestingCallback;
    ULONG_PTR __ClientCallLocalMouseHooks;
    ULONG_PTR __xxxClientBroadcastThemeChange;
    ULONG_PTR __xxxClientCallDevCallbackSimple;
    ULONG_PTR __xxxClientAllocWindowClassExtraBytes;
    ULONG_PTR __xxxClientFreeWindowClassExtraBytes;
    ULONG_PTR __fnGETWINDOWDATA;
    ULONG_PTR __fnINOUTSTYLECHANGE2;
    ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX2;
} KERNELCALLBACKTABLE;


typedef struct _CLientLoadLibraryParam
{
	DWORD dwSize;//+0
	DWORD dwStringLength; //+4
	DWORD ReservedZero1;//+8
	DWORD ReservedZero2;//+C
	DWORD ReservedZero3;//+10
	DWORD ReservedZero4;//+14
	DWORD ReservedZero5;//+18 () +1A () //不需要!
	DWORD ReservedZero6;//+1C
	DWORD ReservedZero8;//+20
	DWORD test[3]; // 占位
	ULONG_PTR ptrDllString;//+30
	DWORD ReservedZero11[5];
    ULONG_PTR ptrApiString;//+40
	WCHAR szDllName[MAX_PATH];
	WCHAR szApiName[MAX_PATH];
}CLientLoadLibraryParam, * PCLientLoadLibraryParam;

// 验证数字签名
BOOL VerifyEmbeddedSignature(LPCWSTR pwszSourceFile)
{
    LONG lStatus;
    DWORD dwLastError;

    
    WINTRUST_FILE_INFO FileData;
    memset(&FileData, 0, sizeof(FileData));
    FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
    FileData.pcwszFilePath = pwszSourceFile;
    FileData.hFile = NULL;
    FileData.pgKnownSubject = NULL;

    GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
    WINTRUST_DATA WinTrustData;

    
    memset(&WinTrustData, 0, sizeof(WinTrustData));
    WinTrustData.cbStruct = sizeof(WinTrustData);
    WinTrustData.dwUIChoice = WTD_UI_NONE;
    WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
    WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
    WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
    WinTrustData.pFile = &FileData;
    WinTrustData.dwProvFlags = WTD_SAFER_FLAG;

    
    lStatus = WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);

    if (lStatus != ERROR_SUCCESS) {
        dwLastError = GetLastError();
        return FALSE;
    }

    return TRUE;
}

// 不区分大小写的字符串比较函数
bool CaseInsensitiveStringCompare(const wstring& str1, const wstring& str2) {
    return _wcsicmp(str1.c_str(), str2.c_str()) == 0;
}

VOID Fake__ClientLoadLibrary(CLientLoadLibraryParam* lpHook)
{
    if (lpHook == nullptr || lpHook->szDllName == nullptr) return;
    wstring modulePath = lpHook->szDllName;
    wstring system32Path = L"C:\\Windows\\System32\\";
    printf("正在加载模块:%ws\n", modulePath.c_str());

    // 检查模块路径是否在 C:/Windows/System32/ 下
    if (CaseInsensitiveStringCompare(modulePath.substr(0, system32Path.size()), system32Path) == false)
    {
        // 如果弹窗处理状态为 true,则直接返回,不进行弹窗处理
        if (isMessageBoxHandling)
            return;


        // 检查白名单
        unordered_map<wstring, bool>::iterator it_find;
        it_find = moduleWhitelist.find(modulePath);
        if (it_find != moduleWhitelist.end())
        {
            // 调用原始例程加载模块
            if (it_find->second)
                _ClientLoadLibrary(lpHook);
        }
        else
        {
            // 加锁
            mtx.lock();
            // 设置弹窗处理状态为 true
            isMessageBoxHandling = true;
            // 解锁
            mtx.unlock();

            // 否则,弹出消息框询问用户是否加载模块
            int result = MessageBox(NULL, L"是否加载此模块?", L"加载模块", MB_YESNO | MB_ICONQUESTION);
            bool loadModule = (result == IDYES);
            // 加锁
            mtx.lock();

            pair<wstring, bool> new_item(modulePath, loadModule);
            moduleWhitelist.insert(new_item); // 记录用户选择

            // 解锁
            mtx.unlock();

            if (loadModule)
            {
                // 如果用户选择加载模块,调用原始例程加载模块
                _ClientLoadLibrary(lpHook);
            }
            else
            {
                printf("用户拒绝加载模块。\n");
            }

            // 加锁
            mtx.lock();
            // 恢复弹窗处理状态为 false
            isMessageBoxHandling = false;
            // 解锁
            mtx.unlock();
        }
    }
    else {
        // 调用原始例程加载模块
        _ClientLoadLibrary(lpHook);
    }
    
}


ULONG_PTR Get__ClientLoadLibrary()
{
    KERNELCALLBACKTABLE* kbl = NULL;
	kbl = (KERNELCALLBACKTABLE*)*(ULONG_PTR*)(__readgsqword(0x60) + 0x58);
    printf("Offest: 0x%I64X\n", (ULONG_PTR)&(kbl->__ClientLoadLibrary) - (ULONG_PTR)kbl);
	return (ULONG_PTR)&(kbl->__ClientLoadLibrary);
}

BOOL Hook__ClientLoadLibrary()
{
	DWORD dwOldProtect;

	if (!VirtualProtect((LPVOID)_ClientLoadLibrary_addr, 0x1000, PAGE_READWRITE, &dwOldProtect))
		return FALSE;

	*(ULONG_PTR*)_ClientLoadLibrary_addr = (ULONG_PTR)Fake__ClientLoadLibrary;

	if (!VirtualProtect((LPVOID)_ClientLoadLibrary_addr, 0x1000, dwOldProtect, &dwOldProtect))
		return FALSE;

	return TRUE;
}

BOOL UnHook__ClientLoadLibrary()
{
	DWORD dwOldProtect;

	if (!VirtualProtect((LPVOID)_ClientLoadLibrary_addr, 0x1000, PAGE_READWRITE, &dwOldProtect))
		return FALSE;

	*(ULONG_PTR*)_ClientLoadLibrary_addr = (ULONG_PTR)0;

	if (!VirtualProtect((LPVOID)_ClientLoadLibrary_addr, 0x1000, dwOldProtect, &dwOldProtect))
		return FALSE;

	return TRUE;
}

DWORD CreateWindowThread(LPVOID p) {
    // 创建窗口
    HWND hwnd;
    WNDCLASSEX wc = { 0 };

    // 初始化窗口类
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = DefWindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"ConsoleWindowClass";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    // 注册窗口类
    RegisterClassEx(&wc);

    // 创建窗口
    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"ConsoleWindowClass", L"Console Window",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 240,
        NULL, NULL, GetModuleHandle(NULL), NULL);

    // 显示窗口
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}


int main()
{
    setlocale(0, "chs");
	_ClientLoadLibrary_addr = Get__ClientLoadLibrary();
	_ClientLoadLibrary = (fct_clLoadLib) * (ULONG_PTR*)_ClientLoadLibrary_addr;
	Hook__ClientLoadLibrary();
    // 创建一个线程来运行创建窗口的函数
    CreateThread(0, 0, CreateWindowThread, 0, 0, 0);
    std::cin.get();
    UnHook__ClientLoadLibrary();
    system("pause");
	return 0;
}

下面的代码实现一个全局消息钩子,按照道理,模块将不能被受保护的进程加载。

DLL大致需要实现以下内容:

  1. 设置钩子
  2. 取消钩子
  3. 钩子过程函数
  4. 导出相关函数

DLL的主要实现代码如下:

#include "pch.h"

HHOOK g_hHook;
HMODULE g_hModule;

LRESULT CALLBACK GetMsgProc(
     _In_ int    code,
     _In_ WPARAM wParam,
     _In_ LPARAM lParam
)
{
     return CallNextHookEx(g_hHook, code, wParam, lParam);
}

BOOL LoadHook(void)
{
     g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hModule, 0);
     if (g_hHook){
         MessageBox(NULL, TEXT("钩子加载成功!"), TEXT("提示"), MB_OK);
         return TRUE;   
     }
     else
         return FALSE;
}

VOID UnloadHook(void)
{
     if(g_hHook)
         UnhookWindowsHookEx(g_hHook);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                        DWORD  ul_reason_for_call,
                        LPVOID lpReserved
                      )
{
     switch (ul_reason_for_call)
     {
     case DLL_PROCESS_ATTACH:
         g_hModule = hModule;
         MessageBox(NULL, TEXT("加载DLL!"), TEXT("提示"), MB_OK);
         break;
     case DLL_THREAD_ATTACH:
     case DLL_THREAD_DETACH:
     case DLL_PROCESS_DETACH:
         break;
     }
     return TRUE;
}

新建def文件导出相关函数:

LIBRARY


EXPORTS
LoadHook
UnloadHook

编译生成 TestDLL.dll 文件

编写调用程序:DLL不能主动执行,因此需要编写调用程序:

#include <windows.h>
#include <stdio.h>

#define  DLL_NAME    "TestDLL.dll"

int main(int argc, char* argv[])
{
     do{
         HMODULE hModule = LoadLibraryA(DLL_NAME);
         if(hModule == NULL)
             break;
         FARPROC pfnLoadHook = GetProcAddress(hModule, "LoadHook");
         FARPROC pfnUnloadHook = GetProcAddress(hModule, "UnloadHook");
         if(pfnLoadHook==NULL || pfnUnloadHook==NULL)
             break;
         if (pfnLoadHook())
             printf("全局钩子加载成功!\r\n");
         else{
             printf("全局钩子加载失败!\r\n");
             break;
         }
         printf("按任意键卸载全局钩子!\r\n");
         getchar();
         pfnUnloadHook();
         printf("全局钩子卸载完成!\r\n");
     }while(FALSE);

    getchar();
     return 0;
}

注:为了简化出错处理,使用了 do-while(0) 结构。

三、运行效果分析

全局钩子启用前:

启用全局钩子注入器时:

检查一下:

他本身进程没有注入,但是他的子进程 conhost.exe 还是被注入了:

四、总结与展望

本文从角度分析讲解了用户态下屏蔽 SetWindowsHookEx 函数注入模块的方法。此外,还可以通过 win32k.sys 中的内核结构来卸载进程的 Windows 钩子以及阻止消息模块注入,这涉及到内核补丁相关知识。具体可以参考:Windows hooks detector | Prekageo's Blog。

参考文献

  • user32.__ClientLoadLibrary(x) | Opcode0x90's Blog
  • CVE-2015-0057 POC · GitHub
  • 防止Global Windows Hooks注入的一个方法 | 0CCh Blog
  • Win7x64通过ClientLoadLibrary注入DLL-CSDN博客
  • ring3-USER32!__ClientLoadLibrary定位-CSDN博客
  • Windows hooks detector | Prekageo's Blog
  • 利用WH_DEBUG消息进行反HOOK-看雪|kanxue.com
  • Windows DebugProc 函数 - Win32 apps | Microsoft Learn

原文出处链接:[https://blog.csdn.net/qq_59075481/article/details/139206017]。

本文发布于:2024.05.26,更新于:2024.05.26。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1695502.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java后端开发一年经验,跳槽如何准备?

跳槽是一项重要的决定&#xff0c;需要慎重考虑并做好充分的准备。我这里有一套编程入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习编程&#xff0c;不妨点个关注&#xff0c;给个评论222&#xff0c;私信22&#xff0c;我在后台发给你。 …

SpringCloud(3)-OpenFeign相关配置

OpenFeign 是个声明式 WebService 客户端&#xff0c;使用 OpenFeign 让编写 Web Service 客户端更简单。Spring Cloud 对 OpenFeign 进 行 了 封 装 使 其 支 持 了 Spring MVC 标 准 注 解 和 HttpMessageConverters。OpenFeign 可以与 Eureka 和 Ribbon 组合使用以支持负载均…

Tensorflow2.0笔记 - AutoEncoder做FashionMnist数据集训练

本笔记记录自编码器做FashionMnist数据集训练&#xff0c;关于autoencoder的原理&#xff0c;请自行百度。 import os import time import tensorflow as tf from tensorflow import keras from tensorflow.keras import datasets, layers, optimizers, Sequential, metrics, …

17.7K星开源产品分析平台:Posthog

Posthog&#xff1a;开源洞察&#xff0c;产品优化的得力助手 - 精选真开源&#xff0c;释放新价值。 概览 PostHog是一个全面开源的平台&#xff0c;旨在帮助团队构建更好的产品。它提供了从产品分析到会话回放、功能标志和A/B测试等一系列工具&#xff0c;支持自托管&#x…

Keras深度学习框架第二十讲:使用KerasCV中的Stable Diffusion进行高性能图像生成

1、绪论 1.1 概念 为便于后文讨论&#xff0c;首先进行相关概念的陈述。 Stable Diffusion&#xff1a;Stable Diffusion 是一个在图像生成领域广泛使用的技术&#xff0c;尤其是用于文本到图像的转换。它基于扩散模型&#xff08;Diffusion Models&#xff09;&#xff0c;这…

Springboot017学生读书笔记共享

springboot005学生心理咨询评估系统 亲测完美运行带论文&#xff1a;获取源码&#xff0c;私信评论或者v:niliuapp 运行视频 Springboot017学生读书笔记共享 包含的文件列表&#xff08;含论文&#xff09; 数据库脚本&#xff1a;db.sql其他文件&#xff1a;ppt.ppt论文&am…

Java+Swing+Mysql实现飞机订票系统

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;Eclipse2021 JDK版本&#xff1a;jdk1.8 数据库&#xff1a;Mysql8.0 2.技术选型 JavaSwingMysql 3.功能模块 4.数据库设计 1.用户表&#xff08;users&#xff09; 字段名称 类型 记录内容…

【Linux】Linux的安装

文章目录 一、Linux环境的安装虚拟机 镜像文件云服务器&#xff08;可能需要花钱&#xff09; 未完待续 一、Linux环境的安装 我们往后的学习用的Linux版本为——CentOs 7 &#xff0c;使用 Ubuntu 也可以 。这里提供几个安装方法&#xff1a; 电脑安装双系统&#xff08;不…

OpenWrt 安装Quagga 支持ospf Bgp等动态路由协议 软路由实测 系列四

1 Quagga 是一个路由软件套件, 提供 OSPFv2,OSPFv3,RIP v1 和 v2,RIPng 和 BGP-4 的实现. 2 web 登录安装 #或者ssh登录安装 opkg install quagga quagga-zebra quagga-bgpd quagga-watchquagga quagga-vtysh # reboot 3 ssh 登录 #重启服务 /etc/init.d/quagga restart #…

Linux下Vision Mamba环境配置+多CUDA版本切换

上篇文章大致讲了下Vision Mamba的相关知识&#xff0c;网上关于Vision Mamba的配置博客太多&#xff0c;笔者主要用来整合下。 笔者在Win10和Linux下分别尝试配置相关环境。 Win10下配置 失败 \textcolor{red}{失败} 失败&#xff0c;最后出现的问题如下&#xff1a; https://…

ps进程查看命令详解

1、PS 命令是什么 查看它的man手册可以看到&#xff0c;ps命令能够给出当前系统中进程的快照。它能捕获系统在某一事件的进程状态。如果你想不断更新查看的这个状态&#xff0c;可以使用top命令。 2、ps命令支持三种使用的语法格式 UNIX 风格&#xff0c;选项可以组合在一起…

flutter 实现旋转星球

先看效果 planet_widget.dart import dart:math; import package:flutter/material.dart; import package:vector_math/vector_math_64.dart show Vector3; import package:flutter/gestures.dart; import package:flutter/physics.dart;class PlanetWidget extends StatefulW…

Android14 - 绘制系统 - 概览

从Android 12开始&#xff0c;Android的绘制系统有结构性变化&#xff0c; 在绘制的生产消费者模式中&#xff0c;新增BLASTBufferQueue&#xff0c;客户端进程自行进行queue的生产和消费&#xff0c;随后通过Transation提交到SurfaceFlinger&#xff0c;如此可以使得各进程将缓…

Altium Designer 中键拖动,滚轮缩放,并修改缩放速度

我的版本是AD19&#xff0c;其他版本应该都一样。 滚轮缩放 首先&#xff0c;要用滚轮缩放&#xff0c;先要调整一下AD 设置&#xff0c;打开Preferences&#xff0c;在Mouse Wheel Configuration 里&#xff0c;把Zoom Main Window 后面Ctrl 上的对勾取消掉&#xff0c;再把…

翻译《The Old New Thing》- What‘s the deal with the EM_SETHILITE message?

Whats the deal with the EM_SETHILITE message? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071025-00/?p24693 Raymond Chen 2007年10月25日 简要 文章讨论了EM_SETHILITE和EM_GETHILITE消息在文档中显示为“未实现”的原因。这些…

C语言 | Leetcode C语言题解之第112题路径总和

题目&#xff1a; 题解&#xff1a; bool hasPathSum(struct TreeNode *root, int sum) {if (root NULL) {return false;}if (root->left NULL && root->right NULL) {return sum root->val;}return hasPathSum(root->left, sum - root->val) ||ha…

与用户沟通获取需求的方法

1 访谈 访谈是最早开始使用的获取用户需求的技术&#xff0c;也是迄今为止仍然广泛使用的需求分析技术。 访谈有两种基本形式&#xff0c;分别是正式的和非正式的访谈。正式访谈时&#xff0c;系统分析员将提出一些事先准备好的具体问题&#xff0c;例如&#xff0…

C++_string简单源码剖析:模拟实现string

文章目录 &#x1f680;1.构造与析构函数&#x1f680;2.迭代器&#x1f680;3.获取&#x1f680; 4.内存修改&#x1f680;5. 插入&#x1f680;6. 删除&#x1f680;7. 查找&#x1f680;8. 交换swap&#x1f680;9. 截取substr&#x1f680;10. 比较符号重载&#x1f680;11…

pod install 报错 ‘SDK does not contain ‘libarclite‘ at the path...‘

报错内容&#xff1a; SDK does not contain ‘libarclite’ at the path ‘/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a’; 这是报错已经很明确告诉我们&#xff0c;Xcode默认的工具链中缺少一个工具…