通过DLL劫持技术HookAPI
- 格式:doc
- 大小:111.50 KB
- 文档页数:8
利⽤HOOKAPI拦截⽂件操作先读下HookAPI 使⽤⽂档:功能简介HookAPI 是⼀个截获Windows 32位API函数的开发包,它可以在Windows调⽤某个API函数的时候,先调⽤⾃⼰编写的函数,从⽽实现特殊的功能。
HookAPI同样也适⽤于截获⽤户⾃⼰编写的DLL⽂件中的输出函数。
1.5系统特点:1)⾃⼰编写的替代函数的参数形式和原API函数完全⼀样,⽅便了Delphi和VB⽤户的使⽤。
2)实时截获所有新建⽴的进程,即进程建⽴后马上安装钩⼦,⽽不是采⽤定时扫描进程的⽅法3)由于不采⽤定时扫描进程的⽅法,所以系统资源消耗少,基本上看不到消耗CPU资源。
4)新建⽴的InstDLL动态库,减少了⽤户调⽤HookAPI的代码。
运⾏和开发平台为Windows NT/2000/9x/XP包含的⽂件列表:【EXE⽬录】:调⽤InstHook.dll来安装HookAPI的执⾏程序【InstHook⽬录】:安装HookAPI的DLL程序【dll⽬录】:NT/2000/XP/XP下截获32位API函数的DLL程序【HOOKAPI9x.dll】:Win9x下截获32位API函数的DLL程序【EXE⽬录】:HookAPI.exe的源码【HOOKSOCKET⽬录】:截获Socket函数的mydll例⼦【HOOKREG⽬录】:截获注册表函数的mydll例⼦【HOOKFILE⽬录】:截获⽂件存取的mydll例⼦【HOOKFILE9x⽬录】:win9x下的截获⽂件存取的mydll_9x例⼦【HookFile_Delphi⽬录】:截获⽂件存取的Delphi下的mydll的例⼦【HookSocket_Delphi⽬录】:截取Socket函数的Delphi下的mydll的例⼦使⽤:⽤户编写要截获的API函数相对应的⾃⼰的实现函数,编译成mydll.dll,同时在⾃⼰的程序中调⽤InstHook.dll中的安装/卸载函数就可以实现⾃⼰的截获过程。
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)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;}。
Hook技术是一种用于拦截API函数调用的技术,它通过修改系统API函数的内存地址,从而拦截系统函数的调用,实现对系统API函数的拦截和修改。
Hook技术的基本原理是将系统API函数的内存地址指向一个用户定义的函数,而不是指向实际的API函数。
当调用系统API函数时,系统将调用用户定义的函数,而不是原来的函数。
这样就可以实现对系统API函数的拦截和修改。
Hook技术的实现步骤如下:
1、首先,程序员需要查找和定位需要拦截的API函数的内存地址。
2、然后,程序员需要编写用户定义的函数,用来拦截和修改系统API函数的调用。
3、接着,程序员需要将系统API函数的内存地址指向用户定义的函数,从而实现API函数的拦截。
4、最后,程序员需要将系统API函数的原始内存地址保存起来,以便在不再需要拦截时,可以恢复原来的API函数调用行为。
Hook技术是一种强大的技术,可以用来实现各种功能,比如拦截软件的调用,拦截软件的输入输出,拦截系统函数的调用等。
Hook技术也可以用来实现防病毒,反垃圾邮件,防恶意程序,实现软件保护以及实现自定义控件等功能。
AheadLib 2.2.150--------------------------------------------------------------------------------一、简介AheadLib 是用来生成一个特洛伊DLL的工具,用于分析DLL中的函数参数调用(比如记录Socket send 了什么等等)、更改函数功能(随心所欲了:)、更改界面功能(比如在Hook里面生成一个按钮,截获事件等等)。
二、使用1.用AheadLib 打开要模拟的DLL,生成一个CPP 文件。
2.用Visual Studio 6.0/.NET 建立一个DLL 工程,把这个CPP 文件加入到项目中。
3.使用Release 方式编译,生成的DLL 将和原来的DLL 具有一模一样的导出函数,并且能顺利把这些函数转发到原来的函数中。
4.AheadLib 还可以生成Hook 代码,用于截取当前进程的所有消息,这样就可以随心所欲地处理各种消息了(修改第三方程序界面功能的好助手)。
三、备注1.如果导出函数过多,在Visual Studio 6.0 中,如果出现编译错误,请在项目属性关闭与编译头功能。
2.如果是C++ 、C __stdcall、C __fastcall 的方式导出的话,生成的函数声明将会还原成原代码级别(可能需要修改才能编译,比如导出C++类的情况)。
此时使用__declspec(dllexport) 导出——不能指定导出序号。
3.如果是NONAME 或者C _CDECL 方式导出(比如DEF 导出,大多数Windows DLL都是这种情况,比如WS2_32等等),则使用#pragma comment(linker, "/EXPORT:...)导出,且指定导出序号。
4.如果系统中没有DbgHelp.dll,将无法识别C++ 模式的导出。
DLL劫持技术说明我是从CoDe_Inject帮助下才了解这个DLL劫持技术(或称HOOK),利用这个制作内存补丁非常的好用。
Windows下Hook API技术 inline hook分类: WINDOWS什么叫Hook API?所谓Hook就是钩子的意思,而API是指 Windows开放给程序员的编程接口,使得在用户级别下可以对操作系统进行控制,也就是一般的应用程序都需要调用API来完成某些功能, Hook API的意思就是在这些应用程序调用真正的系统API前可以先被截获,从而进行一些处理再调用真正的API来完成功能。
在讲Hook API之前先来看一下如何Hook消息,例如Hook全局键盘消息,从而可以知道用户按了哪些键,这种Hook消息的功能可以由以下函数来完成,该函数将一个新的 Hook加入到原来的Hook链中,当某一消息到达后会依次经过它的Hook链再交给应用程序。
HHOOK SetWindowsHookEx(int idHook, //Hook类型,例如WH_KEYBOARD,WH_MOUSEHOOKPROC lpfn, //Hook处理过程函数的地址HINSTANCE hMod, //包含Hook处理过程函数的dll句柄(若在本进程可以为NULL)DWORD dwThreadId, //要Hook的线程ID,若为0,表示全局Hook所有);这里需要提一下的就是如果是Hook全局的而不是某个特定的进程则需要将Hook过程编写为一个DLL,以便让任何程序都可以加载它来获取Hook过程函数。
而对于Hook API微软并没有提供直接的接口函数,也许它并不想让我们这样做,不过有2种方法可以完成该功能。
第一种,修改可执行文件的IAT表(即输入表),因为在该表中记录了所有调用API的函数地址,则只需将这些地址改为自己函数的地址即可,但是这样有一个局限,因为有的程序会加壳,这样会隐藏真实的IAT表,从而使该方法失效。
第二种方法是直接跳转,改变API函数的头几个字节,使程序跳转到自己的函数,然后恢复API开头的几个字节,在调用AP完成功能后再改回来又能继续Hook了,但是这种方法也有一个问题就是同步的问题,当然这是可以克服的,并且该方法不受程序加壳的限制。
HOOKAPI(⼀)——HOOK基础+⼀个⿏标钩⼦实例HOOK API (⼀)——HOOK基础+⼀个⿏标钩⼦实例code: https:///hfl15/windows_kernel_development/tree/master/demo_source_code/MouseHook0x00 起因最近在做毕业设计,有⼀个功能是需要实现对剪切板的监控和进程的防终⽌保护。
原本想从内核层实现,但没有头绪。
最后决定从调⽤层⼊⼿,即采⽤HOOK API的技术来挂钩相应的API,从⽽实现预期的功能。
在这样的需求下,就开始学习了HOOK API。
0x01什么是HOOK APIHOOK(钩⼦,挂钩)是⼀种实现Windows平台下类似于中断的机制。
HOOK机制允许应⽤程序拦截并处理Windows消息或指定事件,当指定的消息发出后,HOOK程序就可以在消息到达⽬标窗⼝之前将其捕获,从⽽得到对消息的控制权,进⽽可以对该消息进⾏处理或修改,加⼊我们所需的功能。
钩⼦按使⽤范围分,可分为线程钩⼦和系统钩⼦,其中,系统钩⼦具有相当⼤的功能,⼏乎可以实现对所有Windows消息的拦截、处理和监控。
这项技术涉及到两个重要的API,⼀个是SetWindowsHookEx,安装钩⼦;另⼀个是UnHookWindowsHookEx,卸载钩⼦。
本⽂使⽤的HOOK API技术,是指截获系统或进程对某个API函数的调⽤,使得API的执⾏流程转向我们指定的代码段,从⽽实现我们所需的功能。
Windows下的每个进程均拥有⾃⼰的地址空间,并且进程只能调⽤其地址空间内的函数,因此HOOK API尤为关键的⼀步是,设法将⾃⼰的代码段注⼊到⽬标进程中,才能进⼀步实现对该进程调⽤的API进⾏拦截。
然⽽微软并没有提供HOOK API的调⽤接⼝,这就需要开发者⾃⼰编程实现,⼤家所熟知的防毒软件、防⽕墙软件等均采⽤HOOK API实现。
⼀般来说,HOOK API由两个组成部分,即实现HOOK API的DLL⽂件,和启动注⼊的主调程序。
DLL劫持技术当一个可执行文件运行时,Windows加载器将可执行模块映射到进程的地址空间中,加载器分析可执行模块的输入表,并设法找出任何需要的DLL,并将它们映射到进程的地址空间中。
由于输入表中只包含DLL名而没有它的路径名,因此加载程序必须在磁盘上搜索DLL文件。
首先会尝试从当前程序所在的目录加载DLL,如果没找到,则在Windows系统目录中查找,最后是在环境变量中列出的各个目录下查找。
利用这个特点,先伪造一个系统同名的DLL,提供同样的输出表,每个输出函数转向真正的系统DLL。
程序调用系统DLL时会先调用当前目录下伪造的DLL,完成相关功能后,再跳到系统DLL同名函数里执行,如图18.3所示。
这个过程用个形象的词来描述就是系统DLL被劫持(hijack)了。
图18.3 DLL劫持技术演示利用这种方法取得控制权后,可以对主程序进行补丁。
此种方法只对除kernel32.dll、ntdll.dll等核心系统库以外的DLL有效,如网络应用程序的ws2_32.dll、游戏程序中的d3d8.dll,还有大部分应用程序都调用的lpk.dll,这些DLL都可被劫持。
利用第5章5.6.2节提供的CrackMeNet.exe来演示一下如何利用劫持技术制作补丁,目标文件用Themida v1.9.2.0加壳保护。
1.补丁地址去除这个CrackMe网络验证方法参考第5章5.6.2节,将相关补丁代码存放到函数PatchProcess()里。
例如将401496h改成:00401496 EB 29 jmp short 004014C1补丁编程实现就是:unsigned char p401496[2] = {0xEB, 0x29};WriteProcessMemory(hProcess,(LPVOID)0x401496, p401496, 2, NULL);p401496这个数组的数据格式,可以用OllyDbg插件获得,或十六进制工具转换。
例如Hex Workshop打开文件,执行菜单“Edit/Copy As/Source”即可得到相应的代码格式。
2.构建输出函数查看实例CrackMeNet.exe输入表,会发现名称为“ws2_32.dll”的DLL,因此构造一个同名的DLL来完成补丁任务。
伪造的ws2_32.dll 有着真实ws2_32.dll一样的输出函数,完整源码见光盘映像文件。
实现时,可以利用DLL模块中的函数转发器来实现这个目标,其会将对一个函数的调用转至另一个DLL中的另一个函数。
可以这样使用一个pragma指令:#pragma comment(linker, "/EXPORT:SomeFunc=DllWork.someOtherFunc")这个pragma告诉链接程序,被编译的DLL应该输出一个名叫SomeFunc的函数。
但是SomeFunc函数的实现实际上位于另一个名叫SomeOtherFunc的函数中,该函数包含在称为DllWork. dll的模块中。
如果要达到劫持DLL的目的,生成的DLL输出函数必须与目标DLL输出函数名一样。
本例可以这样构造pragma指令:#pragma comment(linker, "/EXPORT:WSAStartup=_MemCode_WSAStartup,@115") 编译后的DLL,会有与ws2_32.dll同名的一个输出函数WSAStartup,实际操作时,必须为想要转发的每个函数创建一个单独的pragma代码行,读者可以用工具AheadLib或用其他办法,将ws2_32.dll输出函数转换成相应的pragma指令。
当应用程序调用伪装ws2_32.dll的输出函数时,必须将其转到系统ws2_32.dll中,这部分的代码自己实现。
例如,WSAStartup输出函数构造如下:ALCDECL MemCode_WSAStartup(void){GetAddress("WSAStartup");__asm JMP EAX;//转到系统ws2_32.dll的WSAStartup输出函数}其中,GetAddress()函数的代码如下:// MemCode 命名空间namespace MemCode{HMODULE m_hModule = NULL; //原始模块句柄DWORD m_dwReturn[500] = {0}; //原始函数返回地址// 加载原始模块inline BOOL WINAPI Load(){TCHAR tzPath[MAX_PATH]={0};TCHAR tzTemp[MAX_PATH]={0};GetSystemDirectory(tzPath, sizeof(tzPath));strcat(tzPath,"\\ws2_32.dll");m_hModule = LoadLibrary(tzPath);//加载系统系统目录下ws2_32.dllif (m_hModule == NULL){wsprintf(tzTemp, TEXT("无法加载 %s,程序无法正常运行。
"), tzPath);MessageBox(NULL, tzTemp, TEXT("MemCode"), MB_ICONSTOP); }return (m_hModule != NULL);}// 释放原始模块inline VOID WINAPI Free(){if (m_hModule)FreeLibrary(m_hModule);}// 获取原始函数地址FARPROC WINAPI GetAddress(PCSTR pszProcName){FARPROC fpAddress;TCHAR szProcName[16]={0};TCHAR tzTemp[MAX_PATH]={0};if (m_hModule == NULL){if (Load() == FALSE)ExitProcess(-1);}fpAddress = GetProcAddress(m_hModule, pszProcName);if (fpAddress == NULL){if (HIWORD(pszProcName) == 0){wsprintf(szProcName, "%d", pszProcName);pszProcName = szProcName;}wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运行。
"), pszProcName);MessageBox(NULL, tzTemp, TEXT("MemCode"), MB_ICONSTOP); ExitProcess(-2);}return fpAddress;}}using namespace MemCode;编译后,用LordPE查看伪造的ws2_32.dll输出函数,和真实ws2_32.dll完全一样,如图18.4所示。
(点击查看大图)图18.4 伪造ws2_32.dll的输出表查看伪造的ws2_32.dll中任意一个输出函数,例如WSACleanup:.text:10001CC0 ; int __stdcall WSACleanup().text:10001CC0 WSACleanup proc near.text:10001CC0 push offsetaWsacleanup ;"WSACleanup".text:10001CC5 call sub_10001000 ;GetAddress(WSA Cleanup).text:10001CCA jmp eax.text:10001CCA WSACleanup endp会发现输出函数WSACleanup()首先调用GetAddress(WSACleanup),获得真实ws2_32.dll中WSACleanup的地址,然后跳过去执行,也就是说,ws2_32.dll各输出函数被Hook了。
3.劫持输出函数ws2_32.dll有许多输出函数,经分析,程序发包或接包时,WSAStartup输出函数调用的比较早,因此在这个输出函数放上补丁的代码。
代码如下:ALCDECL MemCode_WSAStartup(void){hijack();GetAddress("WSAStartup");__asm JMP EAX;}hijack()函数主要是判断是不是目标程序,如果是就调用PatchProcess()进行补丁。
void hijack(){if (isTarget(GetCurrentProcess())) //判断主程序是不是目标程序,是则补丁之{PatchProcess(GetCurrentProcess());}}伪造的ws2_32.dll制作好后,放到程序当前目录下,这样当原程序调用WSASTartup函数时就调用了伪造的ws2_32.dll的WSASTartup 函数,此时hijack()函数负责核对目标程序校验,并将相关数据补丁好,处理完毕后,转到系统目录下的ws2_32.dll执行。
这种补丁技术,对加壳保护的软件很有效,选择挂接的函数最好是在壳中没有被调用的,当挂接函数被执行时,相关的代码已被解压,可以直接补丁了。
在有些情况下,必须用计数器统计挂接的函数的调用次数来接近OEP。
此方法巧妙地绕过了壳的复杂检测,很适合加壳程序的补丁制作。
一些木马或病毒也会利用DLL劫持技术搞破坏,因此当在应用程序目录下发现系统一些DLL文件存在时,如lpk.dll,应引起注意。