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

目录

前言

一、研究 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;//+0DWORD dwStringLength; //+4DWORD ReservedZero1;//+8DWORD ReservedZero2;//+CDWORD ReservedZero3;//+10DWORD ReservedZero4;//+14DWORD ReservedZero5;//+18 () +1A () //不需要!DWORD ReservedZero6;//+1CDWORD ReservedZero8;//+20DWORD test[3]; // 占位ULONG_PTR ptrDllString;//+30DWORD ReservedZero11[5];ULONG_PTR ptrApiString;//+40WCHAR szDllName[MAX_PATH];WCHAR szApiName[MAX_PATH];
}CLientLoadLibraryParam, * PCLientLoadLibraryParam;

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

反 SetWindowsHookEx DLL 注入成为可能 😀 。

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

user32.__ClientLoadLibrary(lpHook)

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

_USERHOOK structunknown_00	DWORD ?	           ; 0x00unknown_04	DWORD ?	           ; 0x04nCount	DWORD ?	           ; 0x08 numbers of pointer to fix upunknown_0C	DWORD ?	           ; 0x0CoffCbkPtrs	DWORD ?	           ; 0x10 offset to callback pointersbFixed	DWORD ?	           ; 0x14 indicates if the pointer is fixedlpDLLPath	UNICODE_STRING {}  ; 0x18 DLL pathlpfnNotify	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 structlSize 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;//+0DWORD dwStringLength; //+4DWORD ReservedZero1;//+8DWORD ReservedZero2;//+CDWORD ReservedZero3;//+10DWORD ReservedZero4;//+14DWORD ReservedZero5;//+18 () +1A () //不需要!DWORD ReservedZero6;//+1CDWORD ReservedZero8;//+20DWORD test[3]; // 占位ULONG_PTR ptrDllString;//+30DWORD ReservedZero11[5];ULONG_PTR ptrApiString;//+40WCHAR 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();// 设置弹窗处理状态为 trueisMessageBoxHandling = 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();// 恢复弹窗处理状态为 falseisMessageBoxHandling = 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;   }elsereturn 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.mzph.cn/diannao/15741.shtml

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

相关文章

【代码随想录训练营】【Day 27 and 28】【回溯1-2】| Leetcode 77, 216, 17

【代码随想录训练营】【Day 27 and 28】【回溯1-2】| Leetcode 77, 216, 17 需强化知识点 组合问题&#xff1a;感受遍历的横向和纵向 题目 77. 组合 注意path要深拷贝 class Solution:def combine(self, n: int, k: int) -> List[List[int]]:result []def backtrac…

Kubernetes(k8s) v1.30.1 本地集群部署 安装metallb 支持LoadBalancer 生产环境 推荐 BGP模式部署

1 metallb 安装参考:Kubernetes(k8s) v1.30.1 本地集群部署 默认不支持LoadBalancer metallb来解决-CSDN博客 2 删除 Layer 2 模式 配置 kubectl delete -f IPAddressPool.yaml kubectl delete -f L2Advertisement.yaml kubectl delete -f discuz-srv.yaml 3 配置 k8s Metal…

nacos-opera(k8s)安装问题解决

整理一些关于k8s部署nacos出现的一些恶心的问题 网上说其他说的更改数据库连接都未解决。 在用nacos-opera想安装高可用nacos时连接mysql数据库报错: 报错具体项: No DataSource set 具体就是说没找到数据源。 第一个 检查一下nacos连接数据库配置 : 第二个 检查一下数据库…

[笔试训练](三十三)097:跳台台阶扩展问题098:包含不超过两种字符的最长子串099:字符串的排列

目录 097:跳台台阶扩展问题 098:包含不超过两种字符的最长子串 099:字符串的排列 097:跳台台阶扩展问题 题目链接:跳台阶扩展问题_牛客题霸_牛客网 (nowcoder.com) 题目&#xff1a; 题解&#xff1a; 规律题: 1.跳上n级台阶的跳法等于前面1~(n-1)级台阶跳法的总和1。 2.跳…

一、机器学习概述

1.课程目的 学习机器学习算法、提高算法性能的技巧 2.算法分类 有监督学习supervised learning、无监督学习unsupervised learning (1).有监督学习 在这种学习方式中&#xff0c;算法需要一个带有标签的训练数据集&#xff0c;这些标签通常是每个样本的真实输出或类别。 在有…

NDIS小端口驱动(九)

PCIe设备难免会遇到一些重置设备的请求&#xff0c;例如重置总线的时候&#xff0c;但是由于NIC网卡的多样性&#xff0c;重置设备确实也有许多要注意的地方&#xff0c;另外还有一些包含WDM的NDIS驱动 微型端口驱动程序硬件重置 微型端口驱动程序必须向 NdisMRegisterMinipo…

C++技能进阶指南——多态语法剖析

前言&#xff1a;多态是面向对象的三大特性之一。顾名思义&#xff0c; 多态就是多种状态。 那么是什么的多种状态呢&#xff1f; 这里的可能有很多。比如我们去买火车票&#xff0c; 有普通票&#xff0c; 学生票&#xff1b; 又比如我们去旅游&#xff0c; 有儿童票&#xff…

视觉与数据的和谐:数字孪生技术在UI设计中的艺术

视觉与数据的和谐&#xff1a;数字孪生技术在UI设计中的艺术 引言 在UI设计的世界里&#xff0c;视觉艺术与数据科学似乎相隔甚远&#xff0c;然而随着数字孪生技术的出现&#xff0c;这两者之间的界限变得模糊。数字孪生技术不仅是一种技术革新&#xff0c;更是一种艺术形式…

LabviewCarla仿真平台搭建一:平台设计及仿真视频可视化实现

文章目录 背景一、平台设计二、视频显示模块实现1、视频模块实现框架2、python-camera数据生成3、labview-camera数据可视化 三、效果展示 背景 在使用carla的时候&#xff0c;有平台的话可以提高效率&#xff0c;因此想结合labview和carla设计一个仿真平台-labcar。其实carla…

【DASBOOK】Mark loves cat

文章目录 一、工具下载二、Mark loves cat解题感悟 一、工具下载 克隆dirsearch仓库&#xff1a; git clone https://github.com/maurosoria/dirsearch.git下载 githack工具 git clone https://github.com/lijiejie/GitHack.git二、Mark loves cat 用dirsearch扫描目录&…

talib 安装

这里写自定义目录标题 talib 安装出错 talib 安装出错 https://github.com/cgohlke/talib-build/releases 这里找到轮子 直接装。

DatePicker日期选择框(antd-design组件库)简单使用

1.DatePicker日期选择框 输入或选择日期的控件。 2.何时使用 当用户需要输入一个日期&#xff0c;可以点击标准输入框&#xff0c;弹出日期面板进行选择。 组件代码来自&#xff1a; 日期选择框 DatePicker - Ant Design 3.本地验证前的准备 参考文章【react项目antd组件-demo:…

简单3步,ERP、OA、CRM等客户端,安全远程访问服务端

如今&#xff0c;企业员工出差远程办公和分支机构的协同工作变得越来越普遍。然而&#xff0c;如何确保在不同地点的员工都能安全、便捷地访问公司内网的C/S&#xff08;Client/Server&#xff09;架构办公系统&#xff0c;是一个亟待解决的问题。 贝锐花生壳内网穿透服务提供…

基于JAVA GUI体育馆管理系统的会员功能

Java GUI即Java图形用户界面&#xff0c;是一种使用图形化元素&#xff08;如窗口、按钮、文本框等&#xff09;来构建用户界面的技术。它基于Java的Swing框架&#xff0c;可以用于创建各种复杂的用户界面&#xff0c;包括窗口、对话框、菜单、按钮、文本框、复选框、下拉列表等…

SQL学习小记(一)

SQL学习小记&#xff08;一&#xff09; 1. 存储过程&存储函数1.1. 存储过程1.2. 存储函数 2. DEFINER3. INSERT INTO&#xff08;插入新记录&#xff09;4. REPLACE()…AS…5. SUM()函数6. CASE WHEN7. STR_TO_DATE日期时间处理函数8. SUBSTRING函数9. dateFormat函数10. …

神奇动物在哪里?斯洛文尼亚旅游之野生动物寻踪

不仅拥有优美动人的自然风光&#xff0c;斯洛文尼亚还以其丰富的生物多样性而闻名。得益于国家对大自然开展的保护工作&#xff0c;斯洛文尼亚超过三分之一的国土面积都被规划为保护区&#xff0c;拥有约1.5万种动物和6000种植物&#xff0c;其中不乏众多特有、稀有和濒危动植物…

DT浏览器有一些特点和优势,可能是人们选择使用的原因

DT浏览器有一些特点和优势&#xff0c;可能是人们选择使用的原因&#xff1a; - 好评如潮&#xff1a;DT浏览器在网络上获得了众多用户的好评&#xff0c;口碑良好。 - 使用微软搜索引擎技术&#xff1a;DT浏览器采用了微软的搜索引擎技术&#xff0c;在搜索内容上提供了国内…

Gitlab安装

配置文件&#xff1a; /etc/gitlab/gitlab.rb日志文件&#xff1a; /var/log/gitlab/数据文件&#xff1a; /var/opt/gitlab/静态文件和网页内容&#xff1a; /opt/gitlab/embedded/service/gitlab-rails/public/ # 查看当前状态 git status # 提交本地更改 git commit -m &q…

通过Wirtinger流进行相位恢复:理论与算法

文章目录 1. 简介2. 算法描述2.1 初始化(Initialization)2.2 迭代更新(Iterative Updates)2.3 学习率调整&#xff08;Learning Rate Adjustment&#xff09; 3. 代码实现3.1 一维信号测试 &#xff08;Gaussian model&#xff09;3.2 一维信号测试 &#xff08;Coded diffract…

【C++】牛客——BC157 素数回文

✨题目链接&#xff1a; BC157 素数回文 ✨题目描述 现在给出一个素数&#xff0c;这个素数满足两点&#xff1a; 只由1-9组成&#xff0c;并且每个数只出现一次&#xff0c;如13,23,1289。 位数从高到低为递减或递增&#xff0c;如2459&#xff0c;87631。 请你判断一下&…