我的API HOOK库

API HOOK有两种做法,一种是SetWindowHookEx,简单易用,但如果做其它的HOOK,如HOOK OpenProcess,就需要修改内存地址了,内存地址可以通过WriteProcessMemory来修改,先将调用函数的地址改成自己的(jmp到自己的函数),然后需要时,再改回来。

#pragma once

#ifdef _M_IX86
template <typename T>
class Hooker
{
protected:
    static DWORD HookFunction(LPCWSTR lpModule, LPCSTR lpFuncName, PROC lpFunction)
    {
        DWORD dwAddr = (DWORD) GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
        BYTE jmp [] =
        {
            0xe9,    //jmp
            0x00, 0x00, 0x00, 0x00,    //address
            0xc3    //retn
        };

        ReadProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 6, 0);

        DWORD dwCalc = ((DWORD) lpFunction - dwAddr - 5);    //((to)-(from)-5)

        memcpy(&jmp[1], &dwCalc, 4);    //build the jmp

        WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, jmp, 6, 0);

        return dwAddr;
    }

    static BOOL UnHookFunction(LPCWSTR lpModule, LPCSTR lpFuncName)
    {
        DWORD dwAddr = (DWORD) GetProcAddress(GetModuleHandle(lpModule), lpFuncName);

        if (WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 6, 0))
            return TRUE;

        return FALSE;
    }

    static BYTE* MemoryAddress()
    {
        static BYTE backup[6];
        return backup;
    }
};
#elif _M_AMD64
template <typename T>
class Hooker
{
protected:
    static UINT64 HookFunction(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction)
    {
        UINT64 dwAddr = (UINT64) GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
        BYTE jmp [] =
        {
            0x48, 0xb8,    //jmp
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, //address
            0x50, 0xc3  //retn
        };

        ReadProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 12, 0);

        UINT64 dwCalc = (UINT64) lpFunction;

        memcpy(&jmp[2], &dwCalc, 8);    //build the jmp

        WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, jmp, 12, nullptr);

        return dwAddr;
    }

    static BOOL UnHookFunction(LPCWSTR lpModule, LPCSTR lpFuncName)
    {
        UINT64 dwAddr = (UINT64) GetProcAddress(GetModuleHandle(lpModule), lpFuncName);

        if (WriteProcessMemory(GetCurrentProcess(), (LPVOID) dwAddr, MemoryAddress(), 12, 0))
            return TRUE;

        return FALSE;
    }

    static BYTE* MemoryAddress()
    {
        static BYTE backup[12];
        return backup;
    }
};
#endif
View Code

值得注意的是,64位和32位的注入字节有些许不同。

由于目前Visual Studio 2013 Preview实现的C++类中,还是不允许有非int静态变量,但却允许函数中有静态变量,所以我将目标指针数据备份到静态成员中:

    static BYTE* MemoryAddress()
    {
        static BYTE backup[6];
        return backup;
    }

然后,在使用时,从Hooker继承一个类即可:

class MessageBoxHooker : Hooker<MessageBoxHooker>
{
public:
    static void BeginHook()
    {
        HookFunction(L"user32.dll", "MessageBoxW", (PROC) MyMessageBoxW);
    }
    static void StopHook()
    {
        UnHookFunction(L"user32.dll", "MessageBoxW");
    }
private:
    static int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
    {
        StopHook();
        int x = MessageBox(hWnd, L"hooked", lpCaption, uType);
        BeginHook();
        return x;
    }
};
View Code

要开启Hook,只需调用:

MessageBoxHooker::BeginHook();

这个API HOOK库我使了一个模板,之所以用模板是因为C++函数指针不包含实例的指针。这种使用模板来解决C++指针的缺点的做法很常见,ATL也是这样实现的。

本文提供的代码可以随意引用,但请充分测试后再部署,出问题本人不承担任何责任,欢迎有任何建议和补充~

原文地址:https://www.cnblogs.com/sdflysha/p/my-api-hook-library.html