C++实现64/32位InlineHook
Windows IDE:Visual Studio 2022
引用库
#include <iostream>
#include <string>
#include <Windows.h>
#include <vector>
#include <sstream>
前置:
获取请看这里Windows内存修改库(包括HOOK,以及常用指令)
此InlineHook部分依赖已经包含在C++内存修改和进程操作库
InlineHook就是在某地址做一个跳转,跳转到我们的自定义的汇编代码,然后跳转回去
实现代码-方法一
class InlineHookRelativeMode
{
// 这种方式至少预留要5个字节(32/64位)
private:
struct HookInfo
{
HANDLE process = 0;
uintptr_t startAddress = 0;
uintptr_t aimAddress = 0;
uintptr_t offset = 0;
std::vector<uint8_t> startMachine = {};
std::vector<uint8_t> hookMachine = {};
int length = 5;
int nopUnmber = 0;
};
MemoryOpera memoryOpera;
HookInfo hookInfo;
public:
void install(HANDLE process, uintptr_t address, std::vector<uint8_t> machineCode, int byteGroupNumber = 0, bool is64 = false)
{
hookInfo.process = process;
hookInfo.startAddress = address;
for (const auto &element : machineCode)
{
hookInfo.hookMachine.push_back(element); // 保存原地址汇编码
}
// 分配内存
if (is64 == true)
{
hookInfo.aimAddress = FindAllowRemoteMemory(process, address, machineCode.size(), 0X01FFFFFF);
}
else
{
hookInfo.aimAddress = SimpleRemoteMemory(process, machineCode.size());
}
hookInfo.offset = hookInfo.aimAddress - address - hookInfo.length;
hookInfo.nopUnmber = byteGroupNumber - hookInfo.length; // 获取nop数量
memoryOpera.Prepare(process, address, hookInfo.length);
}
BOOL hook()
{
if (hookInfo.nopUnmber < 0)
{
return false;
}
bool result = true;
memoryOpera.Chage(3);
std::vector<uint8_t> readByteArray = ReadMemoryByteArray(hookInfo.process, hookInfo.startAddress, static_cast<SIZE_T>(hookInfo.length + hookInfo.nopUnmber));
for (const auto &element : readByteArray)
{
hookInfo.startMachine.push_back(element);
}
std::vector<uint8_t> JmpAimCode = {0XE9}; // jmp
std::string startMachineCode = HEXTenToSixteen(hookInfo.offset);
if ((startMachineCode.length() % 2 == 0) == false) // 判断是否为偶数
{
startMachineCode = "0" + startMachineCode;
}
if ((startMachineCode.length() / 2) <= hookInfo.length - 1)
{ // 判断是否是指定长度
for (size_t i = 0; i < hookInfo.length - (startMachineCode.length() / 2); i++)
{
startMachineCode = "00" + startMachineCode;
}
}
else
{
startMachineCode = startMachineCode.substr(startMachineCode.length() - 2 * (hookInfo.length - 1), 2 * (hookInfo.length - 1));
}
for (size_t i = startMachineCode.length(); i >= 2; i -= 2)
{
std::string temp = startMachineCode.substr(i - 2, 2);
uint8_t hexByte = static_cast<uint8_t>(std::stoi(temp, nullptr, 16));
JmpAimCode.push_back(hexByte);
}
for (size_t i = 0; i < hookInfo.nopUnmber; i++) // 补充nop
{
JmpAimCode.push_back(0X90); // nop
}
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.startAddress, JmpAimCode) == FALSE)
{
result = false;
}
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.aimAddress, hookInfo.hookMachine) == FALSE)// 写入自定义汇编码
{
result = false;
}
uintptr_t JmpBackMachineCode = 0 - hookInfo.hookMachine.size() - hookInfo.offset - hookInfo.length + hookInfo.nopUnmber; // 计算回跳偏移
std::vector<uint8_t> JmpBackCode = {0XE9};//jmp
std::string backMachineCode = HEXTenToSixteen(JmpBackMachineCode);
if ((backMachineCode.length() % 2 == 0) == false) // 判断是否为偶数
{
backMachineCode = "0" + backMachineCode;
}
if ((backMachineCode.length() / 2) <= hookInfo.length - 1)// 判断是否是指定长度
{
for (size_t i = 0; i < hookInfo.length - (backMachineCode.length() / 2); i++)
{
backMachineCode = "00" + backMachineCode;
}
}
else
{
backMachineCode = backMachineCode.substr(backMachineCode.length() - 2 * (hookInfo.length - 1), 2 * (hookInfo.length - 1));
}
for (size_t i = backMachineCode.length(); i >= 2; i -= 2)
{
std::string temp = backMachineCode.substr(i - 2, 2);
uint8_t hexByte = static_cast<uint8_t>(std::stoi(temp, nullptr, 16));
JmpBackCode.push_back(hexByte);
}
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.aimAddress + hookInfo.hookMachine.size(), JmpBackCode) == FALSE)// 写入回跳汇编码
{
result = false;
}
return result;
}
BOOL uninstall()
{
if (hookInfo.nopUnmber < 0)
{
return false;
}
bool result = true;
memoryOpera.Restore();
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.startAddress, hookInfo.startMachine) == FALSE)// 还原原汇编代码
{
result = false;
}
if (SimpleFreeMemory(hookInfo.process, hookInfo.aimAddress) == FALSE)// 释放分配内存
{
result = false;
}
return result;
}
};
实现代码-方法二
class InlineHookAbsoluteMode
{
// 这种方式至少预留要9个字节(32位),14个字节(64位)
private:
struct HookInfo
{
HANDLE process = 0;
uintptr_t startAddress = 0;
uintptr_t aimAddress = 0;
std::vector<uint8_t> startMachine = {};
std::vector<uint8_t> hookMachine = {};
int length = 9;
bool is64 = false;
int addressLength = 4;
int nopUnmber = 0;
};
MemoryOpera memoryOpera;
HookInfo hookInfo;
public:
void install(HANDLE process, uintptr_t address, std::vector<uint8_t> machineCode, int byteGroupNumber = 0, bool is64 = false)
{
hookInfo.process = process;
hookInfo.startAddress = address;
hookInfo.hookMachine.push_back({0X58}); // pop rax(64);pop eax(32)
hookInfo.is64 = is64;
if (is64 == true)
{
hookInfo.addressLength = 8;
hookInfo.length = 14;
}
for (const auto &element : machineCode)
{
hookInfo.hookMachine.push_back(element);
}
hookInfo.aimAddress = SimpleRemoteMemory(process, machineCode.size()); // 分配内存
hookInfo.nopUnmber = byteGroupNumber - hookInfo.length;
memoryOpera.Prepare(process, address, hookInfo.length);
}
BOOL hook()
{
if (hookInfo.nopUnmber < 0)
{
return false;
}
bool result = true;
memoryOpera.Chage(3);
std::vector<uint8_t> readByteArray = ReadMemoryByteArray(hookInfo.process, hookInfo.startAddress, static_cast<SIZE_T>(hookInfo.length + hookInfo.nopUnmber)); // 获取原地址数据
for (const auto &element : readByteArray)
{
hookInfo.startMachine.push_back(element); // 保存原地址汇编码
}
std::vector<uint8_t> JmpAimCode;
if (hookInfo.is64 == false)
{
JmpAimCode = {0X50, 0XB8};
// push eax
// mov eax,..
}
else
{
JmpAimCode = {0X50, 0X48, 0XB8};
// push rax
// mov rax,..
}
std::string startMachineCode = HEXTenToSixteen(hookInfo.aimAddress);
if ((startMachineCode.length() % 2 == 0) == false) // 判断文本长度是否是偶数
{
startMachineCode = "0" + startMachineCode;
}
if ((startMachineCode.length() / 2) < hookInfo.addressLength)
{
for (size_t i = 0; i <= hookInfo.addressLength - (startMachineCode.length() / 2); i++)
{
startMachineCode = "00" + startMachineCode;
}
}
else
{
startMachineCode = startMachineCode.substr(startMachineCode.length() - 2 * hookInfo.addressLength, 2 * hookInfo.addressLength);
}
for (size_t i = startMachineCode.length(); i >= 2; i -= 2)
{
std::string temp = startMachineCode.substr(i - 2, 2);
uint8_t hexByte = static_cast<uint8_t>(std::stoi(temp, nullptr, 16));
JmpAimCode.push_back(hexByte);
}
JmpAimCode.push_back({0XFF});
JmpAimCode.push_back({0XE0});
// jmp rax(64);jmp eax(32)
for (size_t i = 0; i < hookInfo.nopUnmber; i++) // 补充nop
{
JmpAimCode.push_back(0X90);
}
JmpAimCode.push_back({0X58});
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.startAddress, JmpAimCode) == FALSE)
{
result = false;
}
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.aimAddress, hookInfo.hookMachine) == FALSE)// 写入自定义汇编码
{
result = false;
}
uintptr_t JmpBackMachineCode = hookInfo.startAddress + hookInfo.length + hookInfo.nopUnmber - 1; // 计算回跳地址
std::vector<uint8_t> JmpBackCode;
if (hookInfo.is64 == false)
{
JmpBackCode = {0X50, 0XB8};
}
else
{
JmpBackCode = {0X50, 0X48, 0XB8};
}
std::string backMachineCode = HEXTenToSixteen(JmpBackMachineCode);
if ((backMachineCode.length() % 2 == 0) == false)
{
backMachineCode = "0" + backMachineCode;
}
if ((backMachineCode.length() / 2) < hookInfo.addressLength)
{
for (size_t i = 0; i <= hookInfo.addressLength - (backMachineCode.length() / 2); i++)
{
backMachineCode = "00" + backMachineCode;
}
}
else
{
backMachineCode = backMachineCode.substr(backMachineCode.length() - 2 * hookInfo.addressLength, 2 * hookInfo.addressLength);
}
for (size_t i = backMachineCode.length(); i >= 2; i -= 2)
{
std::string temp = backMachineCode.substr(i - 2, 2);
uint8_t hexByte = static_cast<uint8_t>(std::stoi(temp, nullptr, 16));
JmpBackCode.push_back(hexByte);
}
JmpBackCode.push_back({0XFF});
JmpBackCode.push_back({0XE0});
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.aimAddress + hookInfo.hookMachine.size(), JmpBackCode) == FALSE)// 写入回跳汇编码
{
result = false;
}
return result;
}
BOOL uninstall()
{
if (hookInfo.nopUnmber < 0)
{
return false;
}
bool result = true;
memoryOpera.Restore();
if (WriteMenmoryByteArray(hookInfo.process, hookInfo.startAddress, hookInfo.startMachine) == FALSE)// 还原汇编码
{
result = false;
}
if (SimpleFreeMemory(hookInfo.process, hookInfo.aimAddress) == FALSE)// 释放分配内存
{
result = false;
}
return result;
}
};