C++ HOOK 指定进程的指定 API(MessageBoxA 为例)(最简单)

敢说敢作敢为, 无怨无恨无悔。这篇文章主要讲述C++ HOOK 指定进程的指定 API(MessageBoxA 为例)(最简单)相关的知识,希望能为你提供帮助。
??这篇文章只是基于我之前的全局 HOOK 的修改,要看全局 HOOK点这里??
虽然全局 HOOK 很给力,但是越到后来越发现这个东西除了可以




以外,实际上用途并没有想象中的广泛。相反,对于制定进程的指定 API 的 HOOK 却非常实用,所以就把以前的代码精简一下,去掉它浮夸的外衣,以最少的代码,实现最基本的 HOOK 功能 。


dll 代码:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include < iostream>
#include < Windows.h>
#include < tlhelp32.h>
#include < process.h>

#pragma

HANDLE hProcess=NULL; // 进程句柄
BOOL bIsInjected=FALSE; // 是否注入完成
typedef int (WINAPI *MsgBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); // 声明一个别名 MsgBoxA
MsgBoxA oldMsgBoxA=NULL; // 保存原函数地址
FARPROC pfMsgBoxA=NULL; // 指向原函数地址的远指针
BYTE OldCodeA[5]; // 老的系统API入口代码
BYTE NewCodeA[5]; // 要跳转的API代码 (jmp xxxx)
int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); // 我们自己的 MessageBoxA 函数

#pragma

#pragma

// 开启钩子(修改 API 头 5 个字节)
void HookOn()

DWORD dwTemp = 0,// 修改后的内存保护属性
dwOldProtect,// 之前的内存保护属性
dwRet = 0; // 内存写入成功标志,0不成功、1成功
SIZE_T dwWrite; // 写入进程内存的字节数

// 更改虚拟内存保护
VirtualProtectEx(
hProcess,// 进程句柄
pfMsgBoxA,// 指向保护区域地址的指针
5,// 要更改的区域的字节大小
PAGE_READWRITE,// 内存保护类型,PAGE_READWRITE:可读可写
& dwOldProtect// 接收原来的内存保护属性
);

// 判断是否成功写入内存
dwRet = WriteProcessMemory(
hProcess,// 进程句柄
pfMsgBoxA,// 指向写入地址的指针
NewCodeA,// 指向存放写入内容的缓冲区指针
5,// 写入字节数
& dwWrite// 接收传输到进程中的字节数
);
if (0==dwRet||0==dwWrite)
MessageBoxW(NULL,L"NewCodeA 写入失败",L"",NULL); // 记录日志信息


// 恢复内存保护状态
VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,& dwTemp);



// 关闭钩子(修改 API 头 5 个字节)
void HookOff()


DWORD dwTemp = 0,// 修改后的内存保护属性
dwOldProtect = 0,// 之前的内存保护属性
dwRet = 0; // 内存写入成功标志,0不成功、1成功
SIZE_T dwWrite; // 写入进程内存的字节数

// 更改虚拟内存保护
VirtualProtectEx(
hProcess,// 进程句柄
pfMsgBoxA,// 指向保护区域地址的指针
5,// 要更改的区域的字节大小
PAGE_READWRITE,// 内存保护类型,PAGE_READWRITE:可读可写
& dwOldProtect// 接收原来的内存保护属性
);

dwRet = WriteProcessMemory(
hProcess,// 进程句柄
pfMsgBoxA,// 指向写入地址的指针
OldCodeA,// 指向存放写入内容的缓冲区指针
5,// 写入字节数
& dwWrite// 接收传输到进程中的字节数
);
if (0==dwRet||0==dwWrite)
MessageBoxW(NULL,L"OldCodeA 写入失败",L"",NULL); // 记录日志信息


// 恢复内存保护状态
VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,& dwTemp);


// 代码注入
void Inject()

// 如果还没有注入
if (!bIsInjected)

//保证只调用1次
bIsInjected=TRUE;

// 获取函数地址
HMODULE hmod=::LoadLibrary(L"User32.dll");
oldMsgBoxA=(MsgBoxA)::GetProcAddress(hmod,"MessageBoxA"); // 原 MessageBoxA 地址
pfMsgBoxA=(FARPROC)oldMsgBoxA; // 指向原 MessageBoxA 地址的指针


// 指针为空则结束运行
if (pfMsgBoxA==NULL)MessageBox(NULL,L"cannot get MessageBoxA()",L"error",0); return;


// 将原API中的入口代码保存入 OldCodeA[]
_asm

lea edi,OldCodeA; 把 OldCodeA 的地址给 edi
mov esi,pfMsgBoxA; 把 MessageBoxA 的地址给 esi
cld; 方向标志位复位
movsd; 复制双子
movsb; 复制字节


// 将原 API 第一个字节改为 jmp
NewCodeA[0]=0xe9;

// 计算 jmp 后面要跟的地址
_asm

lea eax,MyMessageBoxA; 将 MyMessageBoxA 的地址给 eax
mov ebx,pfMsgBoxA; 将 MessageBoxA 的地址给 ebx
sub eax,ebx; 计算 jmp 后面要跟的地址
sub eax,5
mov dword ptr [NewCodeA+1],eax


// 开始 Hook
HookOn();



// 假 MessageBoxA
int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType)

int nRet = 0;

// 先恢复 Hook,不然会造成死循环
HookOff();

// 检验 MessageBoxA 是否失败(失败返回 0)
nRet = ::MessageBoxA(hWnd,"Hook MessageBoxA",lpCaption,uType);
//nRet=::MessageBoxA(hWnd,lpText,lpCaption,uType); // 调用原函数(如果你想暗箱操作的话)

// 再次 HookOn,否则只生效一次
HookOn();

return nRet;


#pragma

BOOL APIENTRY DllMain( HMODULE hModule,
DWORDul_reason_for_call,
LPVOID lpReserved
)

// 获取调用 dll 的进程 ID
DWORD dwPid = ::GetCurrentProcessId();

switch (ul_reason_for_call)

case DLL_PROCESS_ATTACH:
// 获取调用 dll 的进程句柄
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

// 开始注入
Inject();

break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;

return TRUE;

好吧,这已经是最短的代码量了。下面演示下效果:




【C++ HOOK 指定进程的指定 API(MessageBoxA 为例)(最简单)】


    推荐阅读