Windows下 WINAPI HOOK实现方法 及 C++源码

 

在这份Demo中,如果不安装钩子,将会弹出

MessageBoxW(0,  L"i am kangkang", L"hello", 0);

钩子安装成功以后,WINAPI中的MessageBoxW被我们截获,并我们弹出了自己的MessageBox;

MessageBoxW(0, L"hook success", L"hacked", 0);

这份Demo适合于 回调API、获取API参数、返回值、自定义参数等需求。

 

C++代码(已添加注释)

// APIHook.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "string.h"
#include "windows.h"
using namespace std;

struct StructAPIHook
{
    string DLLName;
    string APIName;
    string DLLAndAPIName;
    FARPROC APIAddr; // API地址
    void* callback; // 回调地址
    UINT8* oriBytes; // API地址对应的原始字节码
    bool isHooked; // 是否已hook
};



class APIHook
{
private:
    static StructAPIHook hookData[1000];
    static int hookCount;

    // 整数指针地址 转 字节数组 如0x00401000 -> {00 10 40 00} 
    static UINT8* voidToBytes(void* addr)
    {
        UINT8* bytes = (UINT8*)malloc(4);
        memcpy(bytes, &addr, 4);
        return bytes;
    }

    // 通过指针获取指针对应的字节数组
    static UINT8* getPointerBytes(void *p,int len)
    {
        UINT8* bytes = (UINT8*)malloc(len);
        memcpy(bytes, p, len);
        return bytes;
    }

    static bool writeMemory(StructAPIHook *currData)
    {
        if (currData->APIAddr == 0)
        {
            return false;
        }
        
        MEMORY_BASIC_INFORMATION memoryInfo;
        

        if (VirtualQueryEx((HANDLE)-1, (LPCVOID)currData->callback, &memoryInfo, sizeof(memoryInfo)) != sizeof(memoryInfo))
        {
            return false;
        }
        DWORD lpflOldProtect = 0;

        bool isEditSuccess = VirtualProtectEx((HANDLE)-1, memoryInfo.BaseAddress, 8, 64, &lpflOldProtect);
        if (isEditSuccess==0)
        {
            printf("VirtualProtectEx Fail,lpflOldProtect=%d \n", lpflOldProtect);
            return false;
        }



		UINT8 asmBytes[7] = { 0xB8,0,0,0,0,0xFF,0xE0 };
        if (currData->isHooked)
        {
            // 若已经被HOOK,则暂停hook,字节码恢复为初始的状态;
            memcpy(asmBytes , currData->oriBytes, 7);
            currData->isHooked = false;
        }
		else
		{
            // 若目前未被HOOK,则将我们的回调地址写汇编。
            memcpy(asmBytes +1, voidToBytes(currData->callback), 4);
            currData->isHooked = true;
		}


        
        SIZE_T successWritenNum = 0; //成功写入字节数

        bool isWriteSuccess = WriteProcessMemory((HANDLE)-1, currData->APIAddr, asmBytes, 7 ,&successWritenNum);
        if (isWriteSuccess)
        {
            return true;
        }

        return false;


    }

public :
   

    // 安装 参数:DLL名称、API名称、回调地址
    static bool install(string DLLName,string APIName,void* callBack)
    {
        printf("callBack=0x%x\n", callBack);
    /*    if (hookData == NULL)
        {
            hookData = (StructAPIHook**)malloc(sizeof(StructAPIHook)*1000);
        }*/

        


		if (DLLName.length() < 5)
        {
            printf("DLLName length is too short\n");
            return false;
        }
     

        // 添加dll文件后缀名
        if (DLLName.substr(DLLName.length() - 4, 4) !=".dll")
        {
            DLLName += ".dll";
        }

        bool isHookExist = false;
        int index = -1;
        // 判断钩子是否已添加
        for (size_t i = 0; i < hookCount; i++)
        {
			if ((hookData[i].DLLAndAPIName).compare(DLLName + APIName) == 0)
			{
                index = i;
                isHookExist = true;
                // 如果已存在,则继续挂钩;
                // start()
                break;
            }

        }
        if (!isHookExist)
        {
            index = hookCount++;
        }
        StructAPIHook currData = hookData[index];

		HMODULE moduleH = GetModuleHandleA(DLLName.c_str());
        printf("moduleH=0x%x\n", moduleH);
		if (moduleH == 0)
		{
            printf("GetModuleHandleA Fail\n");
			return false;
        }

        currData.APIName = APIName;
        currData.DLLName = DLLName;
        currData.DLLAndAPIName = DLLName + APIName;

        currData.APIAddr = GetProcAddress(moduleH,APIName.c_str());
        currData.oriBytes = getPointerBytes((void*)currData.APIAddr,7);
        currData.callback = callBack;


		if (writeMemory(&currData))
		{
            currData.isHooked = true;
            hookData[index] = currData;
            return true;

		}
        else
        {
            hookData[index] = currData;
            return false;
        
        }
    }



    // 切换钩子状态
    // 钩子被安装成功后,自动启动钩子;
    // 通过调用该函数,可以切换钩子当前状态;停止挂钩 或者 启动挂钩
    static bool changeStatu(string DLLName, string APIName)
    {
        // 在我的钩子列表中,查找某个钩子;
        for (size_t i = 0; i < hookCount; i++)
        {
            if ((hookData[i].DLLAndAPIName).compare(DLLName + APIName) == 0)
            {
                if (writeMemory(&hookData[i]))
                {
                    return true;

                }
                else
                {
                    return false;

                }
            }
        }
    }



};
int APIHook::hookCount = 0;
StructAPIHook APIHook::hookData[1000];

// 这里的调用约定 要与WINAPI一致,否则会出现堆栈不平衡的错误
int __stdcall MyMessageBoxW(HWND hWnd, LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{

    cout << "进入MyMessageBoxW" << endl;
    cout << "hWnd="<< hWnd << endl;
    cout << "lpText=" << lpText << endl;
    cout << "lpCaption=" << lpCaption << endl;
    cout << "uType=" << uType << endl;

    // 先取消钩子
    if (!APIHook::changeStatu("user32.dll", "MessageBoxW"))
    {
        return 0;
    }

    // 取消后,可正常调用函数
    int realReValue = MessageBoxW(0, L"hook success", L"hacked", 0);

    // 再启动钩子。
    if (!APIHook::changeStatu("user32.dll", "MessageBoxW"))
    {
        return 0;
    }
    return realReValue;
}

int main()
{
    cout << "程序启动" << endl;
    cout << "开始安装钩子" << endl;
   
    bool isInstallSuccess = APIHook::install("user32.dll", "MessageBoxW", MyMessageBoxW);
    cout << "钩子安装结束,安装结果="<<isInstallSuccess << endl;
    system("pause");

    MessageBoxW(0,  L"i am kangkang", L"hello", 0);

    cout << "demo end" << endl;
    getchar();
    //std::cout << APIHook::voidToBytes((void*)0x12345678);
}

APIHook类中,我们使用了静态的Hook数据表;

static StructAPIHook hookData[1000];

这样可方便我们进行 大量的API挂钩和卸载操作,也可继续扩展开发出钩子管理、扫描等功能。

 

使用方法:

我们使用函数都是对(-1)自身进程进行的操作,比如WriteProcessMemory;

这意味着,我们需要注入DLL。因此我们需要使用这份APIHOOK源码来编写一份DLL。

DLL的功能是对自身进程的一些API进行HOOK。而且我们的hookDLL也是进程的模块之一,也可以接收到Hook的callback(回调)。

那么如何把DLL注入到一个进程之中呢,请见上一篇“DLL注入器之线程注入”。

 

 

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值