通过DLL劫持技术HookAPI
利用HOOKAPI拦截文件操作
利⽤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的实现原理
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;}。
hook技术原理
Hook技术是一种用于拦截API函数调用的技术,它通过修改系统API函数的内存地址,从而拦截系统函数的调用,实现对系统API函数的拦截和修改。
Hook技术的基本原理是将系统API函数的内存地址指向一个用户定义的函数,而不是指向实际的API函数。
当调用系统API函数时,系统将调用用户定义的函数,而不是原来的函数。
这样就可以实现对系统API函数的拦截和修改。
Hook技术的实现步骤如下:
1、首先,程序员需要查找和定位需要拦截的API函数的内存地址。
2、然后,程序员需要编写用户定义的函数,用来拦截和修改系统API函数的调用。
3、接着,程序员需要将系统API函数的内存地址指向用户定义的函数,从而实现API函数的拦截。
4、最后,程序员需要将系统API函数的原始内存地址保存起来,以便在不再需要拦截时,可以恢复原来的API函数调用行为。
Hook技术是一种强大的技术,可以用来实现各种功能,比如拦截软件的调用,拦截软件的输入输出,拦截系统函数的调用等。
Hook技术也可以用来实现防病毒,反垃圾邮件,防恶意程序,实现软件保护以及实现自定义控件等功能。
hook api
实现HOOK API两种方法
改引入表式 陷阱式
用改引入表式方法来实现,这种方法易 于实现,但要求你熟悉PE文件结构。主 要是定位到Kernel32.dll模块的 OpenProcess函数地址,并用 WriteProcessMemory函数改写函数地址。
进程的定义
通常被定义为一个正在运行的程序的实 例,是一个程序在其自身的地址空间中 的一次执行活动。 的一次执行活动。
Hook的应用模式 的应用模式
观察模式 最为常用,像Windows提供的SetWindowHook 就是典型地为这类应用准备的。而且这也是最 普遍的用法。 这个模式的特点是,在事情发生 的时候,发出一个通知信息。观察者只可以查 看过程中的信息,根据自己关心的内容处理自 己的业务,但是不可以更改原来的流程。 如全 局钩子中,经常使用的鼠标消息、键盘消息的 监视等应用。金山词霸屏幕取词的功能是一个 典型的应用
HOOKAPI的原则
被HOOK的API的原有功能不能受到任何 影响。就像医生救人,如果把病人身体里 的病毒杀死了,病人也死了,那么这个 “救人”就没有任何意义了。如果你 HOOK API之后,你的目的达到了,但 API的原有功能失效了,这样不是HOOK, 而是REPLACE,操作系统的正常功能就 会受到影响,甚至会崩溃。
HOOK API
Hook API是一种拦截应用程序API函 数调用的通用机制,通过建立API Hook 可以监视和改变应用程序的行为。 HookAPI 技术常用于屏幕取词、网络防 火墙、病毒木马等领域。
Hook就是钩子的意思,而API是指 Windows开放给程序员的编程接口,使 得在用户级别下可以对操作系统进行控 制,也就是一般的应用程序都需要调用 API来完成某些功能,Hook API就是在这 些应用程序调用真正的系统API前可以先 被截获,从而进行一些处理再调用真正 的API来完成功能。
DLL劫持技术
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),利用这个制作内存补丁非常的好用。
HOOK的原理
这种DLL注入方式有两个优点: 这种机制在Win 9x/Me和Win NT/2K中都是得到支持的,预计在以后的版本中也将得到支持;钩子DLL可以在不需要的时候,可由我们主动的调用 UnHookWindowsHookEx来卸载,比起使用注册表的机制来说方便了许多。尽管这是一种相当简洁明了的方法,但它也有一些显而易见的缺点:首先值得我们注意的是,Windows钩子将会降低整个系统的性能,因为它额外增加了系统在消息处理方面的时间;其次,只有当目标进程准备接受某种消息时,钩子所在的DLL才会被系统映射到该进程的地址空间中,钩子才能真正开始发挥作用,因此如果我们要对某些进程的整个生命周期内的API调用情况进行监控,用这种方法显然会遗漏某些API的调用 。
通常可采用的几种注入方式:
1.利用注册表
如果我们准备拦截的进程连接了User32.dll,也就是使用了User32.dll中的API(一般图形界面的应用程序都是符合这个条件),那么就可以简单把你的钩子驱动器DLL的名字作为值添加在下面注册表的键下: HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs 值的形式可以为单个DLL的文件名,或者是一组DLL的文件名,相邻的名称之间用逗号或空格间隔。所有由该值标识的DLL将在符合条件的应用程序启动的时候装载。这是一个操作系统内建的机制,相对其他方式来说危险性较小,但它也有一些比较明显的缺点:该方法仅适用于NT/2K操作系统,显然看看键的名称就可以明白;如果需要激活或停止钩子的注入,只有重新启动Windows,这个就似乎太不方便了;最后一点也很显然,不能用此方法向没有使用User32.dll的应用程序注入DLL,例如控制台应用程序等。另外,不管是否为你所希望,钩子DLL将注入每一个GUI应用程序,这将导致整个系统性能的下降!
hook api几种方法
:71A21B72 8B4508 mov eax, dword ptr [ebp+08]
:71A21B75 5F pop edi
:71A21B76 5E pop esi
:71A21B77 C9 leave
:71A21B78 C21000 ret 0010
下面用4种方法来HOOK这个API:
:71A21B62 8BD8 mov ebx, eax
:71A21B64 E8C7F6FFFF call 71A21230 //将被HOOK的机器码(第3种方法)
:71A21B69 3BDF cmp ebx, edi
:71A21B6B 5B pop ebx
:71A21B6C 0F855F940000 jne 71A2AFD1
假设我们的HOOK代码在71A20400处,那么我们把71A21B64处的CALL指令改为CALL 71A20400(原指令是这样的:CALL 71A21230)
而71A20400处的HOOK代码是这样的:
71A20400:
pushad
//在这里做你想做的事情
:71A21B42 57 push edi
:71A21B43 57 push edi
:71A21B44 FF7514 push [ebp+14]
:71A21B47 8945F0 mov dword ptr [ebp-10], eax
:71A21B4A 8B450C mov eax, dword ptr [ebp+0C]
4,上下文的问题,有些HOOK代码不能执行某些操作,否则会破坏原API的上下文,原API就失效了;
5,同步问题,在HOOK代码里尽量不使用全局变量,而使用局部变量,这样也是模块化程序的需要;
Windows中Hook API技术
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基础+一个鼠标钩子实例
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⽂件,和启动注⼊的主调程序。
Apihook
API拦截(API HOOK)技术及应用常用的API Hook(截取API,或函数钩子)有两种方式:陷阱式、改引入表式。
在Windows 9x、WindowsNT/2000这两个系统中的API Hook代码完全不同。
就Windows 9x而言,16位DLL与32位DLL的API Hook代码也完全不相同。
API HOOK入门API Hook是一项有趣而实用的Windows系统编程技术,应用领域十分广泛,屏幕取词、内码转换、屏幕翻译、中文平台、网络防火墙、串口红外通信或Internet通信的监视等,都涉及到了此项技术。
API Hook就是钩住API,钩就是绕弯的意思,即让API函数的调用先绕一个弯路,在它执行之前,先做一些“预处理”,这样我们就可以监视或定制某个Win32 API的调用,以实现一些特殊的功能。
至于具体可以实现些什么样的功能,就取决于程序设计者的想象力了。
在很多情况下,想监视或改变某个应用程序的一些特定的操作,但是该应用程序却没有提供相应的接口,而又几乎不可能得到其源代码。
因为大多数Windows应用程序的操作很大程度上依赖于API,所以可以采用API Hook的方式来试图监视和改变应用程序的行为。
常用的API Hook有两种方式:陷阱式和改引入表式。
API Hook的运行平台有三种:Windows 9x的16位DLL、Windows 9x的32位DLL和Windows NT/2000的32位DLL。
其关系如表7-1所示。
表7-1 API Hook的方式表示在VC下可以实现,在C++Builder/Delphi下很难实现;√表示可以实现。
表7-2列出了两种方式各自的优缺点。
陷井式API HOOK原理Windows NT/2000陷阱式API Hook的工作原理如图1所示。
其工作过程如下:(1)加载陷阱式API Hook时,需要定位至被截函数处(图中是BF501234),写入一条跳转指令(Jmp XXXX,二进制代码为E9XXXX),表示所有程序调用被截函数时都自动跳转到自定义函数。
DLL 注入hook API
二、API Hook 的原理 这里的 API 既包括传统的 Win32 APIs,也包括任何 Module 输出的函数调用。熟悉 PE 文件格 式的朋友都知道, PE 文件将对外部 Module 输出函数的调用信息保存在输入表中,即.idata 段。 下面首先介绍本段的结构。 输入表首先以一个 IMAGE_IMPORT_DESCRIPTOR(简称 IID)数组开始。每个被 PE 文件隐式链接 进来的 DLL 都有一个 IID.在这个数组中的最后一个单元是 NULL,可以由此计算出该数组的项数。 例如,某个 PE 文件从两个 DLL 中引入函数,就存在两个 IID 结构来描述这些 DLL 文件,并在两个 IID 结构的最后由一个内容全为 0 的 IID 结构作为结束。几个结构定义如下: IMAGE_IMPORT_DESCRIPTOR struct union{ DWORD Characteristics; ;00h DWORD OriginalFirstThunk; }; TimeDateStamp DWORD ;04h ForwarderChain DWORD ;08h Name DWORD ;0Ch FirstThunk DWORD ;10h IMAGE_IMPROT_DESCRIPTOR ends typedef struct _IMAGE_THUNK_DATA{ union{ PBYTE ForwarderString; PDWORD Functions; DWORD Ordinal; PIMAGE_IMPORT_BY_NAME AddressOfData; }u1; } IMAGE_IMPORT_BY_NAME 结构保存一个输入函数的相关信息: IMAGE_IMPORT_BY_NAME struct Hint WORD ? ;本函数在其所驻留 DLL 的输出表中的序号 Name BYTE ? ;输入函数的函数名,以 NULL 结尾的 ASCII 字符串 IMAGE_IMPORT_BY_NAME ends
8种hook技术_hook方式
8种hook技术_hook方式
有很多种hook技术,以下是其中一些常见的hook方式:
1. Inline hook:在应用程序执行的过程中,修改或替换指令,从而实现hook功能。
2. DLL hook:通过替换目标程序的函数地址指向自己的DLL 函数来实现hook功能。
3. VTable hook:通过修改类对象的虚函数表指针,将目标函数指针替换为自己的函数指针来实现hook功能。
4. API hook:通过劫持或替换目标程序中的API函数,从而实现hook功能。
5. System call hook:通过修改系统调用表或系统调用中断向量表,将目标系统调用指向自己的函数来实现hook功能。
6. Message hook:通过修改消息处理函数来截取和修改目标程序接收到的消息,从而实现hook功能。
7. Keyboard/Mouse hook:通过拦截和篡改键盘或鼠标事件的处理函数,实时监控和修改用户的输入。
8. Network hook:在网络层拦截和处理网络数据包,实现对网络通信的监控和修改。
API Hook完全手册
注:本文是根据我两年前写的一个系统行为监测程序写成(参考了一些书籍和文章)。
最近在论坛上看到有不少人在问关于API Hook的问题,便写成此文,希望能对朋友们在写API Hook代码的时候能够有所帮助。
1 基本原理API Hook是什么我就不多说了,直接进入正题。
API Hook技术主要有下面的技术难点:1.如何将自己的的代码Inject到其他进程2.如何Hook到API1.1 代码的Injection常用的方法有:1.使用注册表HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs这种方法可以指定多个DLL,用空格隔开。
这些DLL会被任何用到User32.dll的所有程序自动加载。
当User32.dll加载的时候,User32.dll的DllMain会收到一个DLL_PROCESS_ATTACH通知,User32在这个时候读取注册表项中的值,调用LoadLibrary加载各个DLL。
显然使用这种方法要求设置注册表之后立刻重起系统,不过一般情况下这不是大问题。
这种方法的主要问题在于,只有用到User32.dll的应用程序才会被Inject。
所有的GUI和少部分CUI程序会用到User32.dll,所以如果你的API Hook程序不打算监视CUI程序的话,那么可能问题并不太大。
但是如果你的API Hook程序需要监视系统中所有进程的话,这种方法的限制将是非常致命的。
2.调用SetWindowsHookEx(WH_GETMESSAGE, …, 0)可以使用SetWindowsHookEx(WH_GETMESSAGE, …, 0) 设置全局的消息钩子,虽然可能你的程序并不用到消息钩子,但是钩子的一个副作用是会将对应的DLL加载到所有的GUI线程之中。
类似的,只有用到GUI的进程才会被挂接。
虽然有这种限制,这种方法仍然是最常用的挂接进程的方法。
dll劫持原理
dll劫持原理DLL 劫持,也称为 DLL 劫持攻击,是一种恶意攻击,它利用Windows 系统在加载 DLL 文件时的一些漏洞,从而迫使系统加载恶意DLL 文件,达到控制计算机系统或者窃取数据等目的。
在这篇文章中,我们将详细介绍 DLL 劫持的原理及其防范措施。
1. DLL 劫持的原理在 Windows 系统中,DLL 是一个重要的系统组件,它包含一些可与其他程序相互共用的函数、类和变量等资源。
一些程序依赖于某些 DLL 文件,而 Windows 系统在加载这些 DLL 文件时,会先在应用程序所在的目录中搜索这些文件,如果找到了就直接加载,否则再从系统目录中搜索。
这就是 DLL 劫持的漏洞利用点。
攻击者可以将一个恶意的 DLL文件命名为与某个应用程序需要的 DLL 文件相同的名称,然后将其放置在应用程序所在的目录中,这样,当应用程序启动时,Windows 系统会优先加载这个恶意的 DLL 文件。
随后,恶意代码就可以进入系统,获取权限并执行攻击者指定的操作。
2. DLL 劫持的步骤下面我们将详细介绍 DLL 劫持的攻击步骤:1)攻击者制作一个恶意的 DLL 文件,并将其命名为与目标应用程序依赖的 DLL 文件名称相同,例如 kernel32.dll。
2)攻击者将这个恶意 DLL 文件放置在应用程序所在的目录中,或者是在环境变量 PATH 指定的目录中。
3)当应用程序启动并执行代码时,Windows 系统会搜索与其依赖的 DLL 相关的路径,然后发现恶意 DLL,进而加载它。
4)恶意 DLL 被加载后,攻击者就可以利用它来控制系统或进行信息窃取等攻击。
3. DLL 劫持的防范措施为了防止 DLL 劫持攻击,以下是一些有效的防范措施:1)升级系统和软件保持系统和软件的最新版本能够有效地提高其安全性。
因为更新版本通常会修复先前版本中存在的一些漏洞和问题,从而减少攻击者利用系统和软件的漏洞的几率。
2)限制应用程序访问DLL文件可以通过在 Windows 系统中设置文件和文件夹的访问权限,从而限制应用程序对某些 DLL 文件的访问。
HOOKAPI——Windows核心编程第22章插入DLL和挂接API学习笔记
HOOKAPI——Windows核心编程第22章插入DLL和挂接API学习笔记HOOK API——Windows核心编程第22章插入DLL和挂接API 学习笔记介绍:HOOK API是指截获特定进程或系统对某个API函数的调用,使得API的执行流程转向指定的代码。
Windows下的应用程序都建立在API函数至上,所以截获API是一项相当有用的技术,它使得用户有机会干预其它应用程序的程序流程。
最常用的一种挂钩API的方法是改变目标进程中调用API函数的代码,使得它们对API的调用变为对用户自定义函数的调用。
HOOK API和HOOK技术完全不同。
尽管它们都是钩子。
HOOK 钩的是消息,它在系统将消息传递给应用程序之前截获它,然后进行操作、或修改消息、或停止消息的传递;而HOOK API截获的是应用程序对系统API的调用,它在应用程序对系统API的调用之前截获此调用动作,让其转而调用我们所定义的函数(内容可能是进行一些操作后再调用原系统API)。
关于HOOK技术,微软为我们提供了现成的API,有固定的使用步骤。
而对于HOOK API技术,微软并没有向我们提供类似的API,没有那么简洁的步骤可供我们参考,也许是因为微软并不希望我们用这样的手段编程,所以相对要麻烦一些。
以下为《windows核心编程》学习笔记:windows编程中,有些时候必须要打破进程的界限。
访问另一个进程的地址空间。
这些情况包括:1.当你想要为另一个进程创建的窗口建立子类时,即为此窗口指定新的窗口过程函数。
2.当你需要调试帮助时。
3.当你想要挂接其它进程时(HOOK API?)。
一旦你的DLL插入到另一个进程的地址空间,就可以对另一个进程为所欲为。
一、为另一个进程创建的窗口建立一个子类。
建立子类就能改变窗口的行为特性。
若要建立子类,只需要调用SetWindowLongPtr函数,改变窗口的内存块中的窗口过程地址,指向一个新的(你自己的)WndProc。
dll劫持方法-概述说明以及解释
dll劫持方法-概述说明以及解释1.引言1.1 概述概述DLL劫持是一种常见的安全漏洞,攻击者利用该漏洞可以篡改程序正常加载的动态链接库(Dynamic Link Library,简称DLL),并向其注入恶意代码。
通过DLL劫持攻击,攻击者可以获取系统的敏感信息、执行恶意操作,甚至掌控受害者的计算机。
DLL(Dynamic Link Library)是Windows操作系统中常见的一种共享库文件,拥有一个或多个函数、数据和资源。
在程序运行过程中,当需要某个函数或资源时,操作系统会自动加载并链接相应的DLL文件,以提供所需的功能。
然而,DLL劫持利用了操作系统的搜索和加载机制,注入具有恶意行为的DLL文件,从而欺骗系统程序加载恶意DLL并执行恶意代码。
攻击者可以将恶意DLL文件重命名为与目标程序依赖的DLL文件同名的文件,利用操作系统搜索DLL文件时的默认搜索顺序,使恶意DLL被系统误认为是合法的DLL文件。
通过DLL劫持,攻击者可以执行各种恶意操作,比如窃取用户敏感信息、下载和安装其他恶意软件、实施远程控制等。
由于DLL劫持攻击方式相对隐蔽,很难被用户察觉,因此成为了广泛应用于黑客攻击和恶意软件传播的一种手段。
为了提高系统的安全性,我们需要了解DLL劫持的各种方法,并采取相应的防范措施。
本文将详细介绍几种常见的DLL劫持方法,分析其影响和可能造成的危害,并提供一些有效的防范措施,帮助读者加强对DLL劫持的防范意识和知识储备。
1.2文章结构1.2 文章结构本文将介绍dll劫持方法的相关内容。
文章主要分为三个部分:引言、正文和结论。
在引言部分,将对dll劫持方法的概念进行概述,简要介绍dll劫持的危害以及本文的目的。
通过对概念和目的的说明,读者将对dll劫持有一个初步的了解。
接着,在正文部分,将详细介绍三种常见的dll劫持方法。
每种方法将包括具体的实现原理和步骤,以及对应的实例分析。
通过对每种方法的介绍,读者将能够了解dll劫持的具体操作,并对各种方法有一个全面的认识。
内存马实现方法
内存马(Memory Resident Malware)是一种驻留在计算机内存中运行的恶意软件,它不依赖于硬盘上的文件,而是将自身注入到合法进程中,通过篡改或劫持进程的执行流来达到隐藏自身并实施恶意行为的目的。
以下是内存马实现的一些常见方法:
1. DLL注入:
恶意代码被封装在一个动态链接库(DLL)中,通过API函数(如CreateRemoteThread、VirtualAllocEx和WriteProcessMemory等)将其注入到目标进程的地址空间,并调用该DLL中的入口点函数。
2. Shellcode注入:
将精心构造的机器码(Shellcode)注入到目标进程内存,然后跳转至Shellcode执行。
Shellcode通常包含了恶意功能以及加载更多恶意代码到内存的功能。
3. 利用漏洞注入:
利用操作系统或应用程序的漏洞(例如缓冲区溢出、UAF等),在目标进程中执行恶意代码,将其植入内存中。
4. 驱动级注入:
通过编写内核级别的驱动程序,直接在内核模式下将恶意代码注入到用户模式进程的地址空间中,这种方式更隐蔽且难以检测。
5. Hook技术:
修改目标进程的系统调用表或其他关键函数地址,将控制权转移给恶意代码,从而在特定时刻执行恶意操作。
6. 反射加载:
避免直接从磁盘加载恶意模块,而是先将恶意模块载入内存后,通过API 解析PE结构并在内存中执行。
总之,内存马实现的核心在于如何隐秘地将恶意代码注入到内存中,并确保其能够在目标进程中持续存在和执行。
由于这类恶意软件具有极高的隐蔽性和复杂性,因此对安全防护带来了较大挑战。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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,应引起注意。