Windows 下 API hook 和 Windows hook 应用区别
详解易语言的钩子(钩子HOOK与APIHOOK区别)

详解易语⾔的钩⼦(钩⼦HOOK与APIHOOK区别)在本篇内容⾥我们给⼤家详细分析了易语⾔中间的钩⼦概念以及HOOK与APIHOOK区别钩⼦原英⽂名称 Hook ,钩⼦的意思是指拦截或截获。
作⽤就是拦截程序中交互的数据,先经过我们预定的钩⼦处理接⼝程序,处理过后,再交还给原处理程序,或者⼲脆阻⽌,吃掉这些数据,让原处理程序什么也得不到。
钩⼦原来是Windows操作系统常⽤来检查系统与程序间通信的⼀些数据是否到达⽬标时⽤的,为不传之密,后来随着⼀些⾼⼿们的研究,逐渐的发现了这些秘密的技术并且公布了出来。
同时还有更多的⼈在掌握了这些技术后,⽤在⾃已的软件开发中,实现出奇招⽽超过其它同类软件的功能⽽赢得市场。
钩⼦技术的种类上很多.HOOK API和HOOK技术完全不同。
尽管它们都是钩⼦。
HOOK钩的是消息,它在系统将消息传递给应⽤程序之前截获它,然后进⾏操作、或修改消息、或停⽌消息的传递;⽽HOOK API截获的是应⽤程序对系统API的调⽤,它在应⽤程序对系统API的调⽤之前截获此调⽤动作,让其转⽽调⽤我们所定义的函数(内容可能是进⾏⼀些操作后再调⽤原系统API)。
关于HOOK技术,微软为我们提供了现成的API,有固定的使⽤步骤。
⽽对于HOOK API技术,微软并没有向我们提供类似的API,没有那么简洁的步骤可供我们参考,也许是因为微软并不希望我们⽤这样的⼿段编程,所以相对要⿇烦⼀些。
WINDOWS的钩⼦函数可以认为是WINDOWS的主要特性之⼀。
利⽤它们,您可以捕捉您⾃⼰进程或其它进程发⽣的事件。
通过“钩挂”,您可以给WINDOWS⼀个处理或过滤事件的回调函数,该函数也叫做“钩⼦函数”,当每次发⽣您感兴趣的事件时,WINDOWS都将调⽤该函数。
⼀共有两种类型的钩⼦:局部的和远程的。
局部钩⼦仅钩挂您⾃⼰进程的事件。
远程的钩⼦还可以将钩挂其它进程发⽣的事件。
远程的钩⼦⼜有两种:基于线程的它将捕获其它进程中某⼀特定线程的事件。
APIHOOK的实现原理

APIHOOK的实现原理API Hooking(API挂钩)是一种常见的软件技术,用于修改或者扩展应用程序的行为,它通过“操纵”应用程序的API调用过程来实现这一目标。
API Hooking通常用于各种目的,例如:监视应用程序的行为、修复漏洞、收集数据等。
本文将介绍API Hook的实现原理及其相关概念。
1. API Hook概述API Hooking通过劫持和修改应用程序对动态链接库(DLL)中导出函数的调用来实现目标功能。
在Windows操作系统中,每个可执行文件都会使用一些API函数,这些函数由系统提供并存储在动态链接库中。
当应用程序调用这些函数时,操作系统会在库文件中查找并执行相应的函数代码。
API Hooking就是在应用程序和DLL之间插入一个中间层,通过改变函数调用的目标,来控制和改变应用程序的行为。
API Hooking的实现原理可以归纳为以下几个步骤:(1)定位目标函数:首先,需要确定要Hook的目标函数。
可以通过静态分析程序源代码、反汇编可执行文件、监视应用程序行为等方法来获取目标函数的地址或名称。
(2)获取目标函数的原始地址:通过动态链接库(DLL)中的导入表,可以获取到目标函数的原始地址。
导入表中保存了DLL中导出函数地址的引用。
(3)Hook目标函数:Hook目标函数的方式有多种,这里介绍两种常见的方式。
a. 钩子函数(Hook Function):通过将Hook函数替换为目标函数的调用,可以劫持目标函数的执行。
Hook函数在执行之前、中间或者之后可以执行额外的逻辑操作,并返回结果给应用程序。
b. IAT Hooking(Import Address Table Hooking):IAT是动态链接库中的导入表,包含了动态链接库中导出函数的地址。
通过修改IAT中目标函数的地址,将其指向Hook函数,即可实现Hook效果。
(4)重定向函数调用:Hook目标函数后,需要将应用程序中对目标函数的调用重定向到Hook函数。
windows-API劫持(API-HOOK)

windows-API劫持(API-HOOK)API HookApiHook⼜叫做API劫持,也就是如果A程序调⽤了B.cll⾥⾯的C函数,我们可以做到当A调⽤C函数执⾏的时候,直接执⾏我们⾃⼰事先准备好的函数,之后我们在执⾏真正的C,当然我们可以不执⾏C或者更改C的参数等等,实现的核⼼思路就是:mov eax, pNewAddr[/size][size=3] jmp eaxAdHookApi.h#ifndef __ADHOOKAPI_H__#define __ADHOOKAPI_H__#include <windows.h>#include <tchar.h>#include <vector>using namespace std;// class CAdAutoHookApiclass CAdHookApi;class CAdAutoHookApi{public:CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr);virtual ~CAdAutoHookApi();private:CAdHookApi *m_pHookApi;void *m_pAddr;};// class CAdAutoHookclass CAdHookApi{public:CAdHookApi();virtual ~CAdHookApi();protected:struct HookMap{HANDLE hProcess;void *pOldAddr;void *pNewAddr;BYTE chOldCode[8];BYTE chNewCode[8];BOOL bHooked;DWORD dwData;};public:HANDLE Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData = 0);HANDLE Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData = NULL, DWORD verifySize = 0, DWORD dwData = 0);BOOL Remove(HANDLE hHook);BOOL Begin(HANDLE hHook);BOOL End(HANDLE hHook);BOOL Begin2(void *pNewAddr);BOOL End2(void *pNewAddr);int BeginAll();int EndAll();int GetCount();void *OldAddr2NewAddr(void *pOldAddr);void *NewAddr2OldAddr(void *pNewAddr);public:static BOOL VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize);static BOOL PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode,const BYTE *verifyData = NULL, DWORD verifySize = 0);protected:CAdHookApi::HookMap *FromNewAddr(void *pNewAddr);CAdHookApi::HookMap *FromOldAddr(void *pOldAddr);BOOL HasHook(HANDLE hHook);protected:vector<HookMap *> m_obHooks;};AdHookApi.cpp//#include "stdafx.h"#include "AdHookApi.h"#include <stdio.h>#include <string.h>#include <assert.h>#include <Windows.h>#include "Common.h"static BOOL gUseAPI = TRUE;static BOOL WINAPI myReadMemory(HANDLE hProcess, LPVOID lpAddress, LPVOID lpBuffer, SIZE_T nSize) {BOOL bRet = FALSE;DWORD dwOldProtect = 0;bRet = VirtualProtect(lpAddress, nSize, PAGE_READONLY, &dwOldProtect);if(gUseAPI){DWORD dwRead = 0;bRet = ReadProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwRead);}else{memcpy(lpBuffer, lpAddress, nSize);}VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);assert(bRet);return bRet;}static BOOL WINAPI myWriteMemory(HANDLE hProcess, LPVOID lpAddress, LPCVOID lpBuffer, SIZE_T nSize) {BOOL bRet = FALSE;DWORD dwOldProtect = 0;bRet = VirtualProtect(lpAddress, nSize, PAGE_READWRITE, &dwOldProtect);if(gUseAPI){DWORD dwWrite = 0;bRet = WriteProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwWrite);}else{memcpy(lpAddress, lpBuffer, nSize);}VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);assert(bRet);return bRet;}// class CAdAutoHookApiCAdAutoHookApi::CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr){m_pHookApi = pHookApi;m_pAddr = pAddr;assert(m_pHookApi != NULL);if(m_pHookApi != NULL){m_pHookApi->End2(m_pAddr);}}CAdAutoHookApi::~CAdAutoHookApi(){if(m_pHookApi != NULL){m_pHookApi->Begin2(m_pAddr);}}// class CAdHookApiCAdHookApi::CAdHookApi(){}CAdHookApi::~CAdHookApi(){EndAll();}BOOL CAdHookApi::VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize){BOOL isPassed = FALSE;if((verifyData != NULL) && (verifySize > 0)){BYTE *addrData = new BYTE[verifySize];if(myReadMemory(GetCurrentProcess(), pAddr, addrData, verifySize)){if(memcmp(addrData, verifyData, verifySize) == 0){isPassed = TRUE;}}delete []addrData;}else{isPassed = TRUE;}return isPassed;}BOOL CAdHookApi::PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode,const BYTE *verifyData, DWORD verifySize){if(!VerifyAddress(pAddr, verifyData, verifySize)){return FALSE;}BOOL bRet = myWriteMemory(GetCurrentProcess(), pAddr, pCode, dwCode);return bRet;}HANDLE CAdHookApi::Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData){HMODULE hModule = LoadLibrary(lpszModule);if(hModule == NULL){return NULL;}void *pOldAddr = (void *)GetProcAddress(hModule, lpcFuncName);if(pOldAddr == NULL){return NULL;}return Add(pOldAddr, pNewAddr, NULL, 0, dwData);}HANDLE CAdHookApi::Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData, DWORD verifySize, DWORD dwData) {BOOL bRet = FALSE;HookMap *pHook = new HookMap;do{ZeroMemory(pHook, sizeof(HookMap));pHook->hProcess = GetCurrentProcess();pHook->pOldAddr = pOldAddr;if(pHook->pOldAddr == NULL){break ;}DWORD dwRead = 8;if((verifyData != NULL) && (verifySize > 0) && (verifySize > dwRead)){dwRead = verifySize;}BYTE *addrData = new BYTE[dwRead];if(!myReadMemory(pHook->hProcess, pHook->pOldAddr, addrData, dwRead)){delete []addrData;break ;}if((verifyData != NULL) && (verifySize > 0) && (memcmp(addrData, verifyData, verifySize) != 0)){delete []addrData;break ;}memcpy(pHook->chOldCode, addrData, 8);DWORD dwTemp = (DWORD)pNewAddr;pHook->pNewAddr = pNewAddr;// mov eax, pNewAddr// jmp eaxpHook->chNewCode[0] = 0xB8;memcpy(pHook->chNewCode + 1, &dwTemp, sizeof(DWORD));pHook->chNewCode[5] = 0xFF;pHook->chNewCode[6] = 0xE0;pHook->bHooked = FALSE;pHook->dwData = dwData;m_obHooks.push_back(pHook);bRet = TRUE;}while(0);if(!bRet){delete pHook;pHook = NULL;}return (HANDLE)pHook;}BOOL CAdHookApi::Remove(HANDLE hHook){BOOL bRet = FALSE;HookMap *pHook = (HookMap *)hHook;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp == pHook){End((HANDLE)pTemp);delete pHook;m_obHooks.erase(m_obHooks.begin() + i);bRet = TRUE;break ;}}return bRet;}BOOL CAdHookApi::Begin(HANDLE hHook){if(!HasHook(hHook)){return FALSE;}HookMap *pHook = (HookMap *)hHook;if(pHook->bHooked){return TRUE;}DWORD dwWrite = 8;BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chNewCode, dwWrite); if(bRet){pHook->bHooked = TRUE;}return bRet;}BOOL CAdHookApi::End(HANDLE hHook){if(!HasHook(hHook)){return FALSE;}HookMap *pHook = (HookMap *)hHook;if(!pHook->bHooked){return FALSE;}DWORD dwWrite = 8;BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chOldCode, dwWrite); if(bRet){}return bRet;}BOOL CAdHookApi::Begin2(void *pNewAddr){HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return FALSE;}return Begin((HANDLE)pHook);}BOOL CAdHookApi::End2(void *pNewAddr){HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return FALSE;}return End((HANDLE)pHook);}void *CAdHookApi::OldAddr2NewAddr(void *pOldAddr){HookMap *pHook = FromOldAddr(pOldAddr);if(pHook == NULL){return NULL;}return pHook->pNewAddr;}void *CAdHookApi::NewAddr2OldAddr(void *pNewAddr){HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return NULL;}return pHook->pOldAddr;}CAdHookApi::HookMap *CAdHookApi::FromNewAddr(void *pNewAddr) {HookMap *pHook = NULL;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp->pNewAddr == pNewAddr){pHook = pTemp;break ;}}return pHook;}CAdHookApi::HookMap *CAdHookApi::FromOldAddr(void *pOldAddr) {HookMap *pHook = NULL;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp->pOldAddr == pOldAddr){pHook = pTemp;break ;}}return pHook;}BOOL CAdHookApi::HasHook(HANDLE hHook){BOOL bRet = FALSE;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp == pHook){bRet = TRUE;break ;}}return bRet;}int CAdHookApi::BeginAll(){int nRet = 0;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];BOOL bRet = Begin((HANDLE)pTemp);if(bRet){nRet ++;}}return nRet;}int CAdHookApi::EndAll(){int nRet = 0;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];BOOL bRet = End((HANDLE)pTemp);delete pTemp;if(bRet){nRet ++;}}m_obHooks.clear();return nRet;}int CAdHookApi::GetCount(){return (int)m_obHooks.size();}User1 ⾃⼰注⼊⾃⼰(测试⽤)#include "stdafx.h"#include "AdHookApi.h"#include <windows.h>using namespace std;static CAdHookApi AdHookApi;int WINAPI mYMessageBoxW( __in_opt HWND hWnd, __in_opt LPCWSTR lpText, __in_opt LPCWSTR lpCaption, __in UINT uType) {//如果是做过滤,记得先关闭掉当前的劫持,然后调⽤原API(给调⽤者看,当然这个地⽅也可以进⾏参数修改),//然后再改成劫持的地址也就是 end(a) do happythings begin(a)MessageBoxA(NULL ,"B" ,"B" ,MB_OK);return 0;}int main(){AdHookApi.Add(_T("User32.dll") ,"MessageBoxW" ,mYMessageBoxW);::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);AdHookApi.BeginAll();::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);AdHookApi.EndAll();::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);return 0;}User2 DLL#include "stdafx.h"#include "ApiDebugger.h"#include <tlhelp32.h>#include <wincrypt.h>#include "Common.h"static const char * gCopyright = "ApiDebugger by CodeLive, email : dongfa@";static CAdHookApi gHooks;bool gEnableLogOutput = true;extern "C" APIDEBUGGER const char * ApiDebugger(){return gCopyright;}///////////////////////////////////////////////////////////////////////////////BOOL WINAPI my_IsDebuggerPresent(VOID){return FALSE;}int WINAPI my_CompareStringW(LCID Locale, DWORD dwCmpFlags, PCNZWCH lpString1, int cchCount1,PCNZWCH lpString2,int cchCount2){CAdAutoHookApi autoHook(&gHooks, my_CompareStringW);logOutput(formatString("ApiDebugger - CompareStringW.\r\n"));int ret = CompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2);logOutput(formatString("ApiDebugger - CompareStringW(%S, %S).\r\n", lpString1, lpString2));return ret;}BOOL WINAPI my_CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR szContainer, LPCWSTR szProvider,DWORD dwProvType, DWORD dwFlags){CAdAutoHookApi autoHook(&gHooks, my_CryptAcquireContextW);BOOL ret = CryptAcquireContextW(phProv, szContainer, szProvider, dwProvType, dwFlags);logOutput(formatString("ApiDebugger - CryptAcquireContextW(0x%08X, %S, %S, 0x%08X, 0x%08X) : %S.\r\n",(int)(*phProv),(szContainer != NULL) ? szContainer : L"NULL",(szProvider != NULL) ? szProvider : L"NULL",dwProvType, dwFlags,ret ? L"TRUE" : L"FALSE"));return ret;}BOOL WINAPI my_CryptImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey,DWORD dwFlags, HCRYPTKEY *phKey){CAdAutoHookApi autoHook(&gHooks, my_CryptImportKey);BOOL ret = CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);string hexData = toHexString((const char *)pbData, dwDataLen);logOutput(formatString("ApiDebugger - CryptImportKey(0x%08X, %s, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",(int)hProv, hexData.c_str(), (int)hPubKey, dwFlags, (int)(*phKey),ret ? L"TRUE" : L"FALSE"));return ret;}BOOL WINAPI my_CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) {CAdAutoHookApi autoHook(&gHooks, my_CryptCreateHash);BOOL ret = CryptCreateHash(hProv, Algid, hKey, dwFlags, phHash);logOutput(formatString("ApiDebugger - CryptCreateHash(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",(int)hProv, (int)Algid, (int)hKey, dwFlags, (int)phHash,ret ? L"TRUE" : L"FALSE"));return ret;}BOOL WINAPI my_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags){CAdAutoHookApi autoHook(&gHooks, my_CryptHashData);BOOL ret = CryptHashData(hHash, pbData, dwDataLen, dwFlags);string hexData = toHexString((const char *)pbData, dwDataLen);logOutput(formatString("ApiDebugger - CryptHashData(0x%08X, %s, 0x%08X) : %S.\r\n",(int)hHash, hexData.c_str(), dwFlags,ret ? L"TRUE" : L"FALSE"));BOOL WINAPI my_CryptDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey) {CAdAutoHookApi autoHook(&gHooks, my_CryptDeriveKey);BOOL ret = CryptDeriveKey(hProv, Algid, hBaseData, dwFlags, phKey);logOutput(formatString("ApiDebugger - CryptDeriveKey(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",(int)hProv, (int)Algid, (int)hBaseData, dwFlags, (int)phKey,ret ? L"TRUE" : L"FALSE"));return ret;}BOOL WINAPI my_CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags,BYTE *pbData, DWORD *pdwDataLen){CAdAutoHookApi autoHook(&gHooks, my_CryptDecrypt);string hexData1 = toHexString((const char *)pbData, *pdwDataLen);writeDataToFile("CryptDec_IN.bin", pbData, *pdwDataLen);BOOL ret = CryptDecrypt(hKey, hHash, Final, dwFlags, pbData, pdwDataLen);string hexData2 = toHexString((const char *)pbData, *pdwDataLen);writeDataToFile("CryptDec_OUT.bin", pbData, *pdwDataLen);logOutput(formatString("ApiDebugger - CryptDecrypt(0x%08X, 0x%08X, %S, 0x%08X, %s=>%s) : %S.\r\n",(int)hKey, (int)hHash, Final ? L"TRUE" : L"FALSE",dwFlags, hexData1.c_str(), hexData2.c_str(),ret ? L"TRUE" : L"FALSE"));return ret;}typedef int (__cdecl *sub_4026B0_func)(BYTE *pbData);// 004026B0 ;static int my_sub_4026B0(BYTE *pbData){CAdAutoHookApi autoHook(&gHooks, my_sub_4026B0);sub_4026B0_func sub_4026B0 = (sub_4026B0_func)(0x004026B0);string hexData1 = toHexString((const char *)pbData, strlen((const char *)pbData));int ret = sub_4026B0(pbData);string hexData2 = toHexString((const char *)pbData, strlen((const char *)pbData));logOutput(formatString("ApiDebugger - sub_4026B0(%s=>%s)",hexData1.c_str(), hexData2.c_str()));return ret;}///////////////////////////////////////////////////////////////////////////////void ApiDebugferShutdown(){gHooks.EndAll();logOutput("ApiDebugger Shutdown.\r\n");}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:{// gHooks.Add(_T("KERNEL32.DLL"), "IsDebuggerPresent", my_IsDebuggerPresent);// gHooks.Add(_T("KERNEL32.DLL"), "CompareStringW", my_CompareStringW);gHooks.Add(_T("ADVAPI32.DLL"), "CryptAcquireContextW", my_CryptAcquireContextW);gHooks.Add(_T("ADVAPI32.DLL"), "CryptImportKey", my_CryptImportKey);gHooks.Add(_T("ADVAPI32.DLL"), "CryptCreateHash", my_CryptCreateHash);gHooks.Add(_T("ADVAPI32.DLL"), "CryptHashData", my_CryptHashData);gHooks.Add(_T("ADVAPI32.DLL"), "CryptDeriveKey", my_CryptDeriveKey);gHooks.Add(_T("ADVAPI32.DLL"), "CryptDecrypt", my_CryptDecrypt);/*const BYTE verifyData[] = { 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0x2C, 0x01, 0x00, 0x00 };void *addr = (void *)0x004026B0;if(gHooks.Add(addr, my_sub_4026B0, verifyData, sizeof(verifyData), 0) != NULL){logOutput(formatString("ApiDebugger - hook sub_4026B0 ok.\r\n"));}else{logOutput(formatString("ApiDebugger - hook sub_4026B0 failed.\r\n"));gHooks.BeginAll();logOutput(formatString("ApiDebugger - %s.\r\n", gCopyright)); logOutput("ApiDebugger Loaded.\r\n");}break ;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:{}break ;case DLL_PROCESS_DETACH:{ApiDebugferShutdown();logOutput("ApiDebugger Unloaded.\r\n");}break;}return TRUE;}。
Windows Hook

HOOK简介HOOK钩子程序是在内存中可以不断的在内存中拦截你要控制设备的消息并且可以对该消息进行处理过滤。
钩子是WINDOWS留给我们的后门,比如你想控制键盘,在DOS时代很简单通过INT即可,而WINDOWS时代不允许我们直接操作硬件;由于WINDOWS 是消息驱动,所以我们可以拦截键盘消息以达到控制键盘的目的。
但是控制自己进程的消息固然很简单,要控制所有进程消息要利用钩子了。
将钩子函数放在DLL中,所有的有关键盘的消息都必须经过钩子函数过滤,这样你就可以为所欲为了。
WINDOWS下的钩子程序就像DOS下的TSR(内存驻留程序)一样,用来截获WINDOWS下的特定的消息,进行相应的处理。
比如可以截获键盘输入的消息,来获得键盘输入的信息等。
钩子程序可以通过API 调用来驻留和脱钩。
钩子的类型按事件分类,有如下的几种常用类型(1)键盘钩子和低级键盘钩子可以监视各种键盘消息。
(2)鼠标钩子和低级鼠标钩子可以监视各种鼠标消息。
(3)外壳钩子可以监视各种Shell事件消息。
比如启动和关闭应用程序。
(4)日志钩子可以记录从系统消息队列中取出的各种事件消息。
(5)窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。
此外,还有一些特定事件的钩子提供给我们使用,不一一列举。
常用的Hook类型:1、WH_CALLWNDPROC和WH_CALLWNDPROCRET HooksWH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你可以监视发送到窗口过程的消息。
系统在消息发送到接收窗口过程之前调用WH_CALLWNDPROC Hook子程,并且在窗口过程处理完消息之后调用WH_CALLWNDPROCRET Hook子程。
WH_CALLWNDPROCRET Hook传递指针到CWPRETSTRUCT结构,再传递到Hook子程。
CWPRETSTRUCT结构包含了来自处理消息的窗口过程的返回值,同样也包括了与这个消息关联的消息参数。
常用hook框架

常用hook框架什么是常用的hook框架?为什么要使用hook框架?有哪些常用的hook框架?这些hook框架各有什么特点和优势?如何使用这些常用的hook框架?接下来,我将逐一回答这些问题,并为你提供相关的详细信息。
首先,我们来了解一下什么是常用的hook框架。
Hook框架是一种软件工程技术,用于在软件系统的运行时动态地修改、扩展或增强其功能。
它允许开发者在不改变原有代码的情况下,通过拦截和修改函数调用或事件的方式,对系统行为进行定制和控制。
常用的hook框架提供了一组API,开发者可以使用这些API来定义自己的拦截逻辑,实现特定的功能扩展或改进。
为什么要使用hook框架?使用hook框架的好处在于它能够帮助我们快速、灵活地定制系统功能。
使用hook框架,我们不必修改系统源代码,而是通过动态拦截和修改代码执行流程,达到自己想要的效果。
这种方式具有一定的安全性,不会破坏原有功能,也不会引入潜在的风险。
另外,使用hook框架还可以提高代码的可维护性,因为我们只需关注自己添加的代码逻辑,而不必关心系统的底层实现。
接下来,让我们看一下一些常用的hook框架。
1. Xposed Framework:Xposed Framework是一个非常著名的hook 框架,广泛应用于Android系统。
它通过修改Android系统的ART或Dalvik虚拟机运行时环境,在应用程序加载过程中动态地替换、修改Java类的方法。
Xposed Framework具有灵活、易用、无需重启设备等优势,非常适合进行Android应用的定制和扩展。
2. Frida:Frida是一款功能强大的跨平台hook框架,支持Windows、macOS、Linux、iOS和Android等多个操作系统。
Frida提供了JavaScript API,可以通过动态注入和执行JavaScript代码来拦截和修改目标进程的函数调用、日志输出等,实现各种功能扩展和调试操作。
API Hook应用简述

API Hook应用简述东软移动互联网事业部卜少峰1.概述windows系统下的编程,消息message的传递是贯穿其始终的。
hook与消息有着非常密切的联系,它的中文含义是“钩子”,这样理解起来我们不难得出“hook是消息处理中的一个环节,用于监控消息在系统中的传递,并在这些消息到达最终的消息处理过程前,处理某些特定的消息”。
这也是hook分为不同种类的原因。
hook的这个本领,使它能够将自身的代码“融入”被hook住的程序的进程中,成为目标进程的一个部分。
在windows2000以后的系统中,普通用户程序的进程空间都是独立的,程序的运行彼此间都不受干扰。
这就使我们希望通过一个程序改变其他程序的某些行为的想法不能直接实现,但是hook的出现给我们开拓了解决此类问题的道路。
在windows系统下编程,会接触到api函数的使用,常用的api函数大概有2000个左右。
最初有些人对某些api函数的功能不太满意,就产生了如何修改这些api,使之更好的服务于程序的想法,这样API Hook就自然而然的出现了。
我们可以通过API Hook,改变一个系统api的原有功能。
基本的方法就是通过hook“接触”到需要修改的api函数入口点,改变它的地址指向新的自定义的函数。
2.API Hook的基本方法如何进行API Hook,常用的方法有如下四种:1、使用注册表HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs2、调用SetWindowsHookEx(WH_GETMESSAGE, …, 0)设置全局的消息钩子;3、使用CreateRemoteThread函数在目标进程中创建远程线程4、如果你只是要挂接某个特定进程的并且情况允许你自己来创建此进程,你可以调用CreateProcess(…, CREATE_SUSPENDED)创建子进程并暂停运行,然后修改入口代码使之调用LoadLibrary加载自己的DLL。
windows下hook第三方库函数的方法

windows下hook第三方库函数的方法在Windows下,要hook第三方库函数,你可以使用一种称为API hooking的技术。
API hooking允许你拦截和修改系统库函数的调用,以便在需要时注入自定义代码。
以下是一种常用的方法,用于在Windows上hook第三方库函数:1. 导入所需函数:首先,在你的代码中导入`windows.h`头文件,并使用`GetProcAddress`函数获取你想要hook的库函数的地址。
2. 创建hook函数:创建一个自定义的hook函数,该函数将代替原始库函数的调用。
该函数应该与原始库函数拥有相同的参数和返回值。
3. 修改函数指针:使用`DetourTransactionBegin`、`DetourUpdateThread`和`DetourAttach`等函数修改目标库函数的指针,将其指向你的自定义hook函数。
4. 启用hook:使用`DetourTransactionCommit`函数启用hook,使得目标函数调用时会转向你的hook函数。
以下是一个简单的示例代码,演示了如何hook第三方库函数:```c++#include <windows.h>#include <detours.h>// 定义原始库函数的指针类型typedef BOOL(WINAPI* OriginalFunc)(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName);// 声明自定义的hook函数BOOL WINAPI MyCustomFunc(LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName){// 在这里可以添加你的自定义代码// 例如:记录日志、修改参数、以及其他操作// 调用原始库函数return ((OriginalFunc)RealFunc)(lpAppName, lpKeyName, lpString, lpFileName);}int main(){// 获取原始库函数的地址OriginalFunc RealFunc =(OriginalFunc)GetProcAddress(GetModuleHandle(L"user32.dll"), "WritePrivateProfileStringA");// 开始hook过程DetourTransactionBegin();DetourUpdateThread(GetCurrentThread());DetourAttach(&(PVOID&)RealFunc, MyCustomFunc);DetourTransactionCommit();// 调用原始库函数WritePrivateProfileStringA("Section", "Key", "Value", "config.ini");// 卸载hookDetourTransactionBegin();DetourUpdateThread(GetCurrentThread());DetourDetach(&(PVOID&)RealFunc, MyCustomFunc);DetourTransactionCommit();return 0;}```请注意,这只是一个示例,实际的hook过程可能会更加复杂。
Windows下的函数hook技术

Windows下的函数hook技术都是很成熟的东西了,这几天看了看,总结一下而已。
讨论了Windows下hook 函数的几种方法。
提供了一个hook TextOutA的完整例子。
通过CreateRemoteThread的方法把hook dll注入到一个普通的应用程序中。
Hooking Imported Functions by name调用imported functions'时的步骤/实现在程序中调用从其它模块引入的函数的方法和普通的函数调用有所不同。
对于普通的函数调用,直接使用call address来调用即可,但是对于imported functions ,在编译的时候compiler/link 并不知道实际的函数实现会被加载到那个地址,函数实现在那个地址在运行的时候才会确定。
对于imported functions ,首先是call 引入表中的一个函数,在运行时再初始化引入表,使用jmp 跳转到真实的函数实现。
引入表:实现原理•找到PE文件的Image_Import_Descriptor 结构•找到Original LAT和Real LAT.•通过要hook 的函数的名字在Original LAT找到要hook的imported function在数组中的index.•保存并修改Real LAT在相应index的function addressHooking Imported Functions by ordinal原理和Hook Imported functions by name 一样,只是是通过要hook 的函数的ordinal 在original LAT 中找到index.Hooking a function in this dll当一个DLL 是通过LoadLibrary 载入的时候,我们无法通过hook imported function 的方法的hook它中的function。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Windows 下API hook 和Windows hook 应用区别Hook 字面的意思是钩子,但是实际上更像提供一种过滤,或者说修改消息处理,或者API的机制。
API hook什么是API的hook呢,其实就是将API调用的地方进行了转移,或者重新实现的一种技术。
这种技术不仅仅可以用在windows 上,其他OS上一样可以使用,我曾经在brew mp 上的手机开发上测试过API hook。
所以这里主要只讲windows 下的API hook。
API 的hook 基本思路都是想办法替换原来的API,使函数的调用关系,直接进行转换,典型的如下可以看到client 端要调用的FunctionA,在A进入之后,就调用了FunctionB , 在FunctionB 中回到FunctionA 做具体A应该做的事情,从A返回之后,FunctionB 然后在返回给Client,那么在FunctionB 中使用FunctionA的前后,它自己都可以干自己想要干的事情,这样就是一个API的hook, 下面我们主要讨论Windows 上最常用的两种API hook 策略。
A)IAT 替换API hook所谓的IAT (import address table ) 这个是PE文件中一个重要的部分,这里我们不详细讨论PE文件的构成,因为这个本来就可以写一张内容。
我们主要了解的是PE如何在一个已经加载在内存中的PE文件如何找到它的IAT。
(1)为什么要找IAT?一个模块,可能依赖别的API,也可能提供API,供别的模块调用,MS为了在PE文件中,分别用导入表和导出表进行描述两种关系。
导入表IAT 主要是描述了这个模块依赖那些其他模块提供的API。
而导出表EAT 是描述这个模块中都提供那些函数供别的模块调用。
如果我们在某个模块的导入表中替换它所依赖的函数,那么这样就可以实现API hook.(2)如何找IAT?要找IAT 要稍微了解一下PE文件的结构,一个PE 文件的大概长相就是这样,我们要找的IAT,就是要先找到PE文件可选头,在这个数据结构中,描述了IAT 描述的位置在那里,然后给距IAT descriptor 就可以找到IAT了。
另外要获得导入表描述符,只要使用这个API ImageDirectoryEntryToData就可以了,但是这个API是有依赖的。
我们使用Dumpbin,或者TC 都可以看到这个exe 确实使用kernel32 dll, 所以,我们下一步要替换我们的自己MyCreateProcessW. 将上面函数稍微优化一下,修改一下,就可以了,PROC install_api_hook(HMODULE hHookModule,const char * szDllName,PROC pfnHookFunAddr,PROC pfnNewFundAddr){PROC pOrigFunc = NULL;unsigned char *pBaseAddr =reinterpret_cast<unsigned char *>(hHookModule);PIMAGE_DOS_HEADER pDosHeader =reinterpret_cast<PIMAGE_DOS_HEADER>(pBaseAddr);PIMAGE_NT_HEADERS pNtHeader =reinterpret_cast<PIMAGE_NT_HEADERS>(pBaseAddr + pDosHeader->e_lfanew );PIMAGE_OPTIONAL_HEADER pPEOptionHeader =&pNtHeader->OptionalHeader;PIMAGE_DATA_DIRECTORY pIA TDataDirectory =&(pPEOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor =reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(pBaseAddr + pIA TDataDirectory->VirtualAddress );for ( ; pImportDescriptor->Name; pImportDescriptor++ ){const char* pszModName =reinterpret_cast<const char*>(pBaseAddr + pImportDescriptor->Name);if ( 0 == lstrcmpiA( pszModName, szDllName ) ){break;}}if ( 0 == pImportDescriptor->Name ){return pOrigFunc;}PIMAGE_THUNK_DATA pThunkData =reinterpret_cast<PIMAGE_THUNK_DATA>(pBaseAddr + pImportDescriptor->FirstThunk);while( pThunkData->u1.Function != 0 ){PROC *ppFunc = reinterpret_cast<PROC*>(&pThunkData->u1.Function);if ( *ppFunc == pfnHookFunAddr ){DWORD dwOldProtect = 0;VirtualProtect( ppFunc, sizeof(PROC), PAGE_READWRITE, &dwOldProtect );pOrigFunc = *ppFunc;CopyMemory(ppFunc, &pfnNewFundAddr, sizeof(PROC));// SIZE_T stMemorySize = 0;// WriteProcessMemory(// GetCurrentProcess(),// ppFunc,// &uNewFundAddr,// sizeof(*ppFunc),// &stMemorySize);VirtualProtect( ppFunc, sizeof(PROC), dwOldProtect, 0 );break;}}return pOrigFunc;}然后在看这样的使用,那么一定会在CreateProcess 的时候,先弹出一个对话框,这样,就是我们的效果,在main() 函数中,写下如下的语句这样就是我们要的结果了。
B)JMP 指令替换现在你在网上搜索一下,说JMP指令替换的,一般都说保存函数入口处5个字节,其实这是相对地址跳转,当然了,如果使用了绝对跳转,那么就不至5个字节了,如果使用相对短地址跳转,当然少于5个字节,这个部分可以参看80x86 汇编instruction set, operator code. 这里我们也采用相对地址跳转,但是最后会说明如何用短跳转实现API hook, 因为这个很有用。
至于是什么跳转,主要是他们跳转地址范围不同。
相对地址跳转-2G到2G。
跳转的hook 的原理第一种,就是进入FunctionA 就跳转到FunctionB,做完B应该做的事情之后,将FunctionA 的入口处的JMP去掉,回复到FunctionA原来的样子。
然后在Function B 中调用FunctionA,当然这个地方你也可以不调用,根据你的功能决定,然后再在FunctionA的入口布置JMP 指令。
最后就是返回Caller。
我们看看如何实现, 这里补充一下,如何计算JMP指令后的operand. 就是跳转的相对地址。
Label1:Mov EAX, EAXMov Edi, edi ...............................Label2:JMP Label1Label3:XOR EcX, EcX那么如果是相对地址跳转JMP label1 汇编机器指令的以后,label1 这个位置的值是多少呢,因为只有知道这个如何计算,那么我们就知道怎么hardcode JMP 指令。
因为计算机当执行JMP Label1 的时候,地址译码机构已经完成了这条指令的译码,并将其送到了可执行单元,在可执行单元还没有开始执行的时候,地址译码机构不能闲着,已经将地址Label3已经装载到EIP中,当可执行单元进行执行JMP Label1的时候,其实是将EIP + JMP 指令operand 合成出来的,那么就有了下面的等式:Label1 = EIP + operand;EIP 等于label3 那么label1= Lebel3+ operand,那么operand = Label1 - Label3.这个是关键。
通常我们是不知道label3 的地址的,但是我们一定能知道lable2 的地址,这个地方就是我们要放JMP 指令的位置,如果我们放相对跳转的JMP 指令,该指令占用5个byte. 那么label3 就可以通过lable2 + JMP 指令的长度计算出来。
基本上就是这个样子了,但是这个有一个致命的缺点,就是如果是多线程,那么可能hook 不到,怎么回事呢?我淫荡的笑,哈哈.........................那么第二种JMP hook 技术就出来。
首先和第一种一样都有一个g_StubCode,而这个大小已经变大了,不再是5个Byte,为什么呢,就是hook 完毕之后,就不但算在恢复原来函数的入口的字节了,等跳转到我们自己函数中,做完要做的事情,然后通过stubCode 在返回原来的函数,这样说明了一个问题,就是这样hook 只能在原来函数之前做事,之后,就不能做事了,只能直接返回,当然有没有可能还能做事情呢,能,怎么办,有点复杂。
这里我们先讨论,简单这种。
1.替换原来函数如果处若干个字节,但是必须大于要放JMP指令字节数,那么这个若干是多少呢?因为相对地址JMP,是5个字节,原函数入口处5个字节正好是完整指令,那么没有问题,如果5个自己不是完整指令,那么这样将一个指令劈成两半的做法是不是很不道德呢。
所以这里应该使用反汇编的手法识别出完成指令,且这些指令的长度是大于JMP指令长度的最小值。
2.将识别出的完整指令备份到stubCode, 然后将原来函数入口处写入JMP指令。