先简单说下原理:hook,即野蛮地借用jmp等指令钩住目标函数,修改运行路径使其执行我们自己的代码。方法是在指定进程中的内存里找到目标函数的地址,然后修改其首地址的前几字节为jmp指令,指向我们自己的自定义函数地址。这样,进程执行这个函数的时候,会先执行我们自己的代码,之后可以选择性执行原函数或不执行。
流程:
1.构造跳转指令。
2.在内存中找到欲hook函数地址,并保存欲hook位置处的前5个字节。
3.将构造的跳转指令写入需hook的位置处。
4.当被hook位置被执行时会转到我们的流程执行。
5.如果要执行原来的流程,那么取消hook,也就是还原被修改的字节。
6.执行原来的流程。
7.继续hook住原来的位置。
下面就要见具体代码实现了。这是我第一次接触hook,写得很简单,对MessageBox函数hook一下下。
我们来把hook封装一下。
ILHook.h
#ifndef __ILHOOK_H_1_ #define __ILHOOK_H_1_ #include <Windows.h> class CILHook{ public: CILHook(); ~CILHook(); BOOL Hook(LPSTR pszModuleName, LPSTR pszFuncName, PROC pfnHookFunc); VOID UnHook(); BOOL ReHook(); private: PROC m_pfnOrig;//函数地址 BYTE m_bOldBytes[5];//函数入口代码 BYTE m_bNewBytes[5];//Inline代码 }; #endif
ILHook.cpp
#include "ILHook.h" CILHook::CILHook(){ m_pfnOrig=NULL; ZeroMemory(m_bOldBytes, 5); ZeroMemory(m_bNewBytes, 5); } CILHook::~CILHook(){ UnHook(); } /* 函数名称:Hook 函数功能:对指定模块中的函数进行挂钩 参数说明: pszModuleName:模块名称 pszFuncName:函数名称 pfnHookFunc:钩子函数 */ BOOL CILHook::Hook(LPSTR pszModuleName,LPSTR pszFuncName,PROC pfnHookFunc){ BOOL bRet=FALSE; //获取指定模块中函数的地址 m_pfnOrig=(PROC)GetProcAddress(GetModuleHandle(pszModuleName),pszFuncName); if(m_pfnOrig!=NULL){ //保存该地址处5个字节的内容 DWORD dwNum=0; ReadProcessMemory(GetCurrentProcess(),m_pfnOrig,m_bOldBytes,5,&dwNum); //构造JMP指令 m_bNewBytes[0]=‘\xe9‘;//jmp Opcode //pfnHookFunc是HOOK后的目标地址 //m_pfnOrig是原来的地址 //5是指令长度 *(DWORD*)(m_bNewBytes+1)=(DWORD)pfnHookFunc-(DWORD)m_pfnOrig-5; //将构造好的地址写入该地址处 WriteProcessMemory(GetCurrentProcess(),m_pfnOrig,m_bNewBytes,5,&dwNum); bRet=TRUE; } return bRet; } /* 函数名称:UnHook 函数功能:取消函数的挂钩 */ VOID CILHook::UnHook(){ if(m_pfnOrig!=0){ DWORD dwNum=0; WriteProcessMemory(GetCurrentProcess(),m_pfnOrig,m_bOldBytes,5,&dwNum); } } /* 函数名称:ReHook 函数功能:重新对函数进行挂钩 */ BOOL CILHook::ReHook(){ BOOL bRet=FALSE; if(m_pfnOrig!=0){ DWORD dwNum=0; WriteProcessMemory(GetCurrentProcess(),m_pfnOrig,m_bNewBytes,5,&dwNum); bRet=TRUE; } return bRet; }
test.cpp
#include "ILHook.h" CILHook MsgHook; int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType){ MsgHook.UnHook(); MessageBox(hWnd,"Hook",lpCaption,uType); MessageBox(hWnd,lpText,lpCaption,uType); MsgHook.ReHook(); return 0; } int main(){ MessageBox(NULL,"test","test",MB_OK); MsgHook.Hook("User32.dll","MessageBoxA",(PROC)MyMessageBoxA); MessageBox(NULL,"test","test",MB_OK); MsgHook.UnHook(); return 0; }
最后的结果是弹出3个对话框,第一个是正常调用,后两个是跳转到自己的自定义函数里进行两次调用原函数,当然是恢复了hook之后。
这个例子是lnline hook本进程,后面会学习lnline hook非本进程。
时间: 2024-10-17 01:35:38