介绍
C++实现64/32位InlineHook
Windows IDE:Visual Studio 2022
Windows
引用库
- <iostream>
- <string>
- <Windows.h>
- <vector>
- <sstream>
前置:
获取请看这里C++内存修改和进程操作库
此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; } };