前言
在上节中介绍了 InlineHook 钩子函数,主要是通过jmp 目标地址(转为机器码E9 偏移量) 来实现的,是修改被Hook函数首地址处的 5个字节的内容。这里再介绍另一种方法,修改被Hook函数首地址处的7字节的内容。我们看下图的汇编指令
之前是jmp 目标地址(5字节),这次是将目标地址放到 eax寄存器中 这里是2条汇编指令(00B417E4-00B417DF = 5字节 + JMP EAX占2字节 = 7字节)。他们有什么不一样呢?
mov eax,78563412
jmp eax
;上面的汇编指令 转为机器码为:
;B8 12345678
;FFE0
这里可以看出 B8为mov指令的机器码,jmp eax 对应的机器码为:FFE0,中间的机器码为目标地址了。这里刚好7个字节,开头和结尾的 机器码 是固定的,变化的唯有中间4字节的 目标地址。故此我们可以修改 被Hook函数地址处的 7个字节即可,这样就不必计算偏移量了。
示例效果
卸载钩子后
下钩子后
代码实现
InlineHook7.h
#pragma once
#include <Windows.h>
class CInlineHook7
{
public:
CInlineHook7(void);
~CInlineHook7(void);
bool Hook(LPSTR strModuleName,LPSTR strHookFnName,FARPROC strHookCallFnName);
bool UnHook();
bool ReHook();
private:
FARPROC m_pFnOrign; // 要Hook的函数地址
BYTE m_bOld[7]; // 要Hook的函数 前7个字节
BYTE m_bNew[7]; // 要Hook的函数 修改后的7个字节
};
InlineHook7.cpp
#include "StdAfx.h"
#include "InlineHook7.h"
CInlineHook7::CInlineHook7(void)
{
m_pFnOrign = NULL;
memset(m_bOld,0,7);
memset(m_bNew,0,7);
}
CInlineHook7::~CInlineHook7(void)
{
UnHook();
}
bool CInlineHook7::Hook(LPSTR strModuleName,LPSTR strHookFnName,FARPROC strTargetFnAddr)
{
bool ret = false;
HMODULE hModule = GetModuleHandleA(strModuleName);
if( hModule == NULL )
goto end;
m_pFnOrign = (FARPROC)GetProcAddress(hModule,strHookFnName);
if( m_pFnOrign == NULL )
goto end;
SIZE_T numByte;
// 保存被Hook函数的前7个字节
if( ReadProcessMemory(GetCurrentProcess(),m_pFnOrign,m_bOld,7,&numByte) == 0 )
goto end;
// 构造jmp指令:mov eax,jmp 目标地址,对应的机器码:B8 4字节的目标地址 FFE0
m_bNew[0] = 0xB8,m_bNew[5] = 0xFF,m_bNew[6] = 0xE0;
// 中间4字节 放目标地址
* (DWORD*)(&m_bNew[0]+1) = (DWORD)strTargetFnAddr;
// 修改被Hook函数的前7个字节 改变其执行流程
if( WriteProcessMemory(GetCurrentProcess(),m_pFnOrign,m_bNew,7,&numByte) == 0 )
goto end;
ret = true;
end:
return ret;
}
bool CInlineHook7::UnHook()
{
bool ret = false;
// 卸载钩子,实际上即是将更改的7个字节还原
SIZE_T numByte;
if( m_pFnOrign != NULL && WriteProcessMemory(GetCurrentProcess(),m_pFnOrign,m_bOld,7,&numByte) != 0)
ret = true;
return ret;
}
bool CInlineHook7::ReHook()
{
bool ret = false;
// 再次装钩子,更改要Hook的函数的前7字节 让其跳转到目标函数
SIZE_T numByte;
if( m_pFnOrign != NULL && WriteProcessMemory(GetCurrentProcess(),m_pFnOrign,m_bNew,7,&numByte) != 0)
ret = true;
return ret;
}
目标函数代码
// WINAPI 一定要声明,指明函数调用方式,这里和MessageBox保持一致
int WINAPI MyMessageBox7(HWND hWnd,LPCSTR lpText, LPCSTR lpCaption,UINT uType)
{
g_inlineHookObj7.UnHook(); // 必须先卸载钩子 再才可以再次调用被Hook的函数,不然会进入死循环
::MessageBoxA(hWnd ,"进入MyMessageBox7了","被Hook了,7字节InlineHook",MB_OK);
::MessageBoxA(hWnd ,lpText,lpCaption,MB_OK);
g_inlineHookObj7.ReHook();
return 0;
}
完整项目
完整项目下载请在这里下载,没分也可以在这里github下载最新代码,如果可以的话,帮忙点个星星哟 。