在这份Demo中,如果不安装钩子,将会弹出
MessageBoxW(0, L"i am kangkang", L"hello", 0);
钩子安装成功以后,WINAPI中的MessageBoxW被我们截获,并我们弹出了自己的MessageBox;
MessageBoxW(0, L"hook success", L"hacked", 0);
这份Demo适合于 回调API、获取API参数、返回值、自定义参数等需求。
C++代码(已添加注释)
// APIHook.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include "string.h"
#include "windows.h"
using namespace std;
struct StructAPIHook
{
string DLLName;
string APIName;
string DLLAndAPIName;
FARPROC APIAddr; // API地址
void* callback; // 回调地址
UINT8* oriBytes; // API地址对应的原始字节码
bool isHooked; // 是否已hook
};
class APIHook
{
private:
static StructAPIHook hookData[1000];
static int hookCount;
// 整数指针地址 转 字节数组 如0x00401000 -> {00 10 40 00}
static UINT8* voidToBytes(void* addr)
{
UINT8* bytes = (UINT8*)malloc(4);
memcpy(bytes, &addr, 4);
return bytes;
}
// 通过指针获取指针对应的字节数组
static UINT8* getPointerBytes(void *p,int len)
{
UINT8* bytes = (UINT8*)malloc(len);
memcpy(bytes, p, len);
return bytes;
}
static bool writeMemory(StructAPIHook *currData)
{
if (currData->APIAddr == 0)
{
return false;
}
MEMORY_BASIC_INFORMATION memoryInfo;
if (VirtualQueryEx((HANDLE)-1, (LPCVOID)currData->callback, &memoryInfo, sizeof(memoryInfo)) != sizeof(memoryInfo))
{
return false;
}
DWORD lpflOldProtect = 0;
bool isEditSuccess = VirtualProtectEx((HANDLE)-1, memoryInfo.BaseAddress, 8, 64, &lpflOldProtect);
if (isEditSuccess==0)
{
printf("VirtualProtectEx Fail,lpflOldProtect=%d \n", lpflOldProtect);
return false;
}
UINT8 asmBytes[7] = { 0xB8,0,0,0,0,0xFF,0xE0 };
if (currData->isHooked)
{
// 若已经被HOOK,则暂停hook,字节码恢复为初始的状态;
memcpy(asmBytes , currData->oriBytes, 7);
currData->isHooked = false;
}
else
{
// 若目前未被HOOK,则将我们的回调地址写汇编。
memcpy(asmBytes +1, voidToBytes(currData->callback), 4);
currData->isHooked = true;
}
SIZE_T successWritenNum = 0; //成功写入字节数
bool isWriteSuccess = WriteProcessMemory((HANDLE)-1, currData->APIAddr, asmBytes, 7 ,&successWritenNum);
if (isWriteSuccess)
{
return true;
}
return false;
}
public :
// 安装 参数:DLL名称、API名称、回调地址
static bool install(string DLLName,string APIName,void* callBack)
{
printf("callBack=0x%x\n", callBack);
/* if (hookData == NULL)
{
hookData = (StructAPIHook**)malloc(sizeof(StructAPIHook)*1000);
}*/
if (DLLName.length() < 5)
{
printf("DLLName length is too short\n");
return false;
}
// 添加dll文件后缀名
if (DLLName.substr(DLLName.length() - 4, 4) !=".dll")
{
DLLName += ".dll";
}
bool isHookExist = false;
int index = -1;
// 判断钩子是否已添加
for (size_t i = 0; i < hookCount; i++)
{
if ((hookData[i].DLLAndAPIName).compare(DLLName + APIName) == 0)
{
index = i;
isHookExist = true;
// 如果已存在,则继续挂钩;
// start()
break;
}
}
if (!isHookExist)
{
index = hookCount++;
}
StructAPIHook currData = hookData[index];
HMODULE moduleH = GetModuleHandleA(DLLName.c_str());
printf("moduleH=0x%x\n", moduleH);
if (moduleH == 0)
{
printf("GetModuleHandleA Fail\n");
return false;
}
currData.APIName = APIName;
currData.DLLName = DLLName;
currData.DLLAndAPIName = DLLName + APIName;
currData.APIAddr = GetProcAddress(moduleH,APIName.c_str());
currData.oriBytes = getPointerBytes((void*)currData.APIAddr,7);
currData.callback = callBack;
if (writeMemory(&currData))
{
currData.isHooked = true;
hookData[index] = currData;
return true;
}
else
{
hookData[index] = currData;
return false;
}
}
// 切换钩子状态
// 钩子被安装成功后,自动启动钩子;
// 通过调用该函数,可以切换钩子当前状态;停止挂钩 或者 启动挂钩
static bool changeStatu(string DLLName, string APIName)
{
// 在我的钩子列表中,查找某个钩子;
for (size_t i = 0; i < hookCount; i++)
{
if ((hookData[i].DLLAndAPIName).compare(DLLName + APIName) == 0)
{
if (writeMemory(&hookData[i]))
{
return true;
}
else
{
return false;
}
}
}
}
};
int APIHook::hookCount = 0;
StructAPIHook APIHook::hookData[1000];
// 这里的调用约定 要与WINAPI一致,否则会出现堆栈不平衡的错误
int __stdcall MyMessageBoxW(HWND hWnd, LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
cout << "进入MyMessageBoxW" << endl;
cout << "hWnd="<< hWnd << endl;
cout << "lpText=" << lpText << endl;
cout << "lpCaption=" << lpCaption << endl;
cout << "uType=" << uType << endl;
// 先取消钩子
if (!APIHook::changeStatu("user32.dll", "MessageBoxW"))
{
return 0;
}
// 取消后,可正常调用函数
int realReValue = MessageBoxW(0, L"hook success", L"hacked", 0);
// 再启动钩子。
if (!APIHook::changeStatu("user32.dll", "MessageBoxW"))
{
return 0;
}
return realReValue;
}
int main()
{
cout << "程序启动" << endl;
cout << "开始安装钩子" << endl;
bool isInstallSuccess = APIHook::install("user32.dll", "MessageBoxW", MyMessageBoxW);
cout << "钩子安装结束,安装结果="<<isInstallSuccess << endl;
system("pause");
MessageBoxW(0, L"i am kangkang", L"hello", 0);
cout << "demo end" << endl;
getchar();
//std::cout << APIHook::voidToBytes((void*)0x12345678);
}
APIHook类中,我们使用了静态的Hook数据表;
static StructAPIHook hookData[1000];
这样可方便我们进行 大量的API挂钩和卸载操作,也可继续扩展开发出钩子管理、扫描等功能。
使用方法:
我们使用函数都是对(-1)自身进程进行的操作,比如WriteProcessMemory;
这意味着,我们需要注入DLL。因此我们需要使用这份APIHOOK源码来编写一份DLL。
DLL的功能是对自身进程的一些API进行HOOK。而且我们的hookDLL也是进程的模块之一,也可以接收到Hook的callback(回调)。
那么如何把DLL注入到一个进程之中呢,请见上一篇“DLL注入器之线程注入”。