介绍

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;
    }
};