内容纲要

https://github.com/TsudaKageyu/minhook

hook 类成员函数需要 __fastcall 传递 this 指针,第二个参数无用。

#include "minhook.h"
#include <iostream>

#pragma comment(lib, "libMinHook.x86.lib")

static int(*test1_Orig)(int, const char*);

int test1(int arg1, const char* arg2)
{
    std::cout << "test1" << std::endl;
    std::cout << "arg1: " << arg1 << std::endl;
    std::cout << "arg2: " << arg2 << std::endl;
    return 1;
}

int test1_Stub(int arg1, const char* arg2)
{
    std::cout << "hooked test1" << std::endl;
    std::cout << "arg1: " << arg1 << std::endl;
    std::cout << "arg2: " << arg2 << std::endl;
    std::cout << "call origin function test1: " << std::endl;
    test1_Orig(arg1, arg2);
    return 2;
}

static int(__stdcall *test2_Orig)(int, const char*);

int __stdcall test2(int arg1, const char* arg2)
{
    std::cout << "test2" << std::endl;
    std::cout << "arg1: " << arg1 << std::endl;
    std::cout << "arg2: " << arg2 << std::endl;
    return 1;
}

int __stdcall test2_Stub(int arg1, const char* arg2)
{
    std::cout << "hooked test2" << std::endl;
    std::cout << "arg1: " << arg1 << std::endl;
    std::cout << "arg2: " << arg2 << std::endl;
    std::cout << "call origin function test2: " << std::endl;
    test2_Orig(arg1, arg2);
    return 2;
}

static int(__fastcall *test3_Orig)(int, const char*);

int __fastcall test3(int arg1, const char* arg2)
{
    std::cout << "test3" << std::endl;
    std::cout << "arg1: " << arg1 << std::endl;
    std::cout << "arg2: " << arg2 << std::endl;
    return 1;
}

int __fastcall test3_Stub(int arg1, const char* arg2)
{
    std::cout << "hooked test3" << std::endl;
    std::cout << "arg1: " << arg1 << std::endl;
    std::cout << "arg2: " << arg2 << std::endl;
    std::cout << "call origin function test3: " << std::endl;
    test3_Orig(arg1, arg2);
    return 2;
}

class Test
{
public:
    Test()
    {
    }
    ~Test()
    {
    }
public:
    int test4(int arg1, const char* arg2)
    {
        std::cout << "test4" << std::endl;
        std::cout << "arg1: " << arg1 << std::endl;
        std::cout << "arg2: " << arg2 << std::endl;
        return 1;
    }
};

static int(__fastcall *test4_Orig)(void*, void*, int, const char*);

int __fastcall test4_Stub(void* pThis, void* notUsed, int arg1, const char* arg2)
{
    std::cout << "hooked test4" << std::endl;
    std::cout << "arg1: " << arg1 << std::endl;
    std::cout << "arg2: " << arg2 << std::endl;
    std::cout << "call origin function test4: " << std::endl;
    test4_Orig(pThis, NULL, arg1, arg2);
    return 2;
}

Test g_Test1;

int main()
{
    MH_Initialize();

    MH_CreateHook(test1, (LPVOID)&test1_Stub, (LPVOID*)&test1_Orig);
    MH_EnableHook(test1);
    test1(10, "hello world!");
    std::cout << "-----------------------------------" << std::endl;

    MH_CreateHook(test2, (LPVOID)&test2_Stub, (LPVOID*)&test2_Orig);
    MH_EnableHook(test2);
    test2(10, "hello world!");
    std::cout << "-----------------------------------" << std::endl;

    MH_CreateHook(test3, (LPVOID)&test3_Stub, (LPVOID*)&test3_Orig);
    MH_EnableHook(test3);
    test3(10, "hello world!");
    std::cout << "-----------------------------------" << std::endl;    

    typedef int(__thiscall Test::* test4_Ptr)(int, const char*);
    std::cout << "class Test::test4 member function address: 0x" << std::hex << &((test4_Ptr)&Test::test4) << std::endl;
    MH_CreateHook((LPVOID) &((test4_Ptr)&Test::test4), (LPVOID)&test4_Stub, (LPVOID*)&test4_Orig);
    MH_EnableHook((LPVOID) &((test4_Ptr)&Test::test4));
    g_Test1.test4(10, "hello world!");

    MH_Uninitialize();
    return 0;
}
#pragma once

#include "Logging.h"
#include <MinHook.h>
#include <map>
#include <string>

class IHook
{
public:
    const std::string name;

    IHook(const std::string &name) : name(name) { }
    virtual ~IHook() { }

    virtual void Destroy() = 0;

    static bool Exists(const std::string &name);
    static void Register(IHook *hook);
    static void Unregister(IHook *hook);
    static void DestroyAll();

private:
    static std::map<std::string, IHook *> hooks;
};

template<class FuncType> class Hook : public IHook
{
public:
    FuncType originalFunc = nullptr;
    Hook(const std::string &name) : IHook(name) { }

    bool CreateHookInObjectVTable(void *object, int vtableOffset, void *detourFunction)
    {
        // For virtual objects, VC++ adds a pointer to the vtable as the first member.
        // To access the vtable, we simply dereference the object.
        void **vtable = *((void ***)object);

        // The vtable itself is an array of pointers to member functions,
        // in the order they were declared in.
        targetFunc = vtable[vtableOffset];

        auto err = MH_CreateHook(targetFunc, detourFunction, (LPVOID *)&originalFunc);
        if (err != MH_OK)
        {
            LOG("Failed to create hook for %s, error: %s", name.c_str(), MH_StatusToString(err));
            return false;
        }

        err = MH_EnableHook(targetFunc);
        if (err != MH_OK)
        {
            LOG("Failed to enable hook for %s, error: %s", name.c_str(), MH_StatusToString(err));
            MH_RemoveHook(targetFunc);
            return false;
        }

        LOG("Enabled hook for %s", name.c_str());
        enabled = true;
        return true;
    }

    void Destroy()
    {
        if (enabled)
        {
            MH_RemoveHook(targetFunc);
            enabled = false;
        }
    }

private:
    bool enabled = false;
    void* targetFunc = nullptr;
};

参考

发表评论

电子邮件地址不会被公开。 必填项已用*标注