C++ HOOK 指定进程的指定 API(MessageBoxA 为例)(最简单)
Posted mb62d3c286f15ed
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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,
DWORD ul_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 为例)(最简单)的主要内容,如果未能解决你的问题,请参考以下文章
如何使用C或C++编程获取电脑CPU使用率?如何使用C或C++获取指定进程的CPU使用率?