C/C++Windows黑客编程系列——InlineHook实现

InlineHook

#include <stdio.h>
#include <windows.h>

// 保存原函数机器指令
BYTE originalApiByte[20] = {0,};

// 自定义新函数执行流程
int WINAPI newMessageBoxA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) {
    // 为调用原API,这里需要进行脱钩
    unHookApiMessageBoxA();
    // 命令行程序没有引入user32,所以使用LoadLibrary
    HMODULE hDll = LoadLibrary("user32.dll");
    if (NULL == hDll) {
        return FALSE;
    }
    // 获取函数的导出地址
    FARPROC oldMessageBoxA = GetProcAddress(hDll, "MessageBoxA");
    if (NULL == oldMessageBoxA) {
        return FALSE;
    }
    int iRet = (int) oldMessageBoxA(hWnd, "i am nobody", "who are you?", MB_YESNO);
    // 再进行hook,方便下次钩取
    hookApiMessageBoxA();
    return iRet;
}

// Unhook Api
BOOL unHookApiMessageBoxA() {
    // 获取 user32.dll模块加载基址
    HMODULE hDll = LoadLibrary("user32.dll");
    if (NULL == hDll) {
        return FALSE;
    }
    // 获取函数的导出地址
    PVOID oldMessageBoxA = GetProcAddress(hDll, "MessageBoxA");
    if (NULL == oldMessageBoxA) {
        return FALSE;
    }
// 计算写入的前几字节数据, 32位下5字节, 64位下12字节
# ifndef _WIN64
    DWORD dwNewDataSize = 5;
# else
    DWORD dwNewDataSize = 12;
# endif
    // 设置页面的保护属性为 可读、可写、可执行
    DWORD dwOldProtect = 0;
    VirtualProtect(oldMessageBoxA, dwNewDataSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
    // 恢复数据
    memcpy(oldMessageBoxA, originalApiByte, dwNewDataSize);
    // 还原页面保护属性
    VirtualProtect(oldMessageBoxA, dwNewDataSize, dwOldProtect, &dwOldProtect);
    return TRUE;
}

BOOL hookApiMessageBoxA() {
    // 获取user32.dll模块加载基址
    HMODULE hDll = LoadLibrary("user32.dll");
    if (NULL == hDll) {
        return FALSE;
    }
    // 获取MessageBoxA函数的导出地址
    PVOID oldMessageBoxA = GetProcAddress(hDll, "MessageBoxA");
    if (NULL == oldMessageBoxA) {
        return FALSE;
    }
// 计算写入的前几字节数据, 32位下5字节, 64位下12字节
# ifndef _WIN64
    /*
    32位汇编代码:jmp funcAddress(4字节函数指针)
    机器码指令:e9 funcAddress(跳转偏移)
           addr1 --> jmp funcAddress指令的下一条指令的地址,即eip的值
           addr2 --> 跳转地址的值,即新函数指针所在地址的值
           跳转偏移计算公式: offset = addr2 - addr1 - 5
     */
   BYTE pNewData[5] = {0xe9, 0, 0, 0, 0};
   DWORD dwNewDataSize = 5;
   DWORD dwOffset = 0;
   // 计算跳转偏移,32位系统jmp funAddress对应的机器指令本身占用5个字节
   dwOffset = (DWORD)NewMessageBoxA - ((DWORD)oldMessageBoxA + 5);
   RtlCopyMemory(&pNewData[1], &dwOffset, sizeof(dwOffset));
# else
    /*
     64位汇编代码:mov rax, funcAddress(真实函数地址,如:0x1122334455667788)
                 jmp rax
     机器码指令:48 b8 funcAddress(0x1122334455667788)
               ff e0
     */
    BYTE pNewData[12] = {0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0};
    DWORD dwNewDataSize = 12;
    ULONGLONG ullNewFuncAddr = (ULONGLONG) newMessageBoxA;
    RtlCopyMemory(&pNewData[2], &ullNewFuncAddr, sizeof(ullNewFuncAddr));
# endif
    // 设置页面的保护属性为 可读、可写、可执行
    DWORD dwOldProtect = 0;
    VirtualProtect(oldMessageBoxA, dwNewDataSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
    // 保存原始数据
    RtlCopyMemory(originalApiByte, oldMessageBoxA, dwNewDataSize);
    // 开始修改 MessageBoxA 函数的前几字节数据, 实现 Inline Hook API
    RtlCopyMemory(oldMessageBoxA, pNewData, dwNewDataSize);
    // 还原页面保护属性
    VirtualProtect(oldMessageBoxA, dwNewDataSize, dwOldProtect, &dwOldProtect);
    return TRUE;
}

int main() {
    MessageBoxA(NULL, "before hook", "tips", MB_OK);
    hookApiMessageBoxA();
    MessageBoxA(NULL, "after hook", "tips", MB_OK);
    unHookApiMessageBoxA();
    MessageBoxA(NULL, "after unhook", "tips", MB_OK);
}

二、效果

本作品采用《CC 协议》,转载必须注明作者和本文链接
失色天空
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!