API Hook 自身 MessageBoxW

#include "stdafx.h"
//原函数类型定义
typedef int (WINAPI* MsgBoxW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
MsgBoxW OldMsgBoxW = NULL;//指向原函数的指针
FARPROC pfOldMsgBoxW;  //指向函数的远指针
BYTE OldCode[5]; //原系统API入口代码
BYTE NewCode[5]; //原系统API新的入口代码 (jmp xxxxxxxx)
HANDLE hProcess = NULL;//本程序进程句柄
HINSTANCE hInst = NULL;//API所在的dll文件句柄
void HookOn();
void HookOff();
void GetApiEntrance();
void OnBnClickedBtnStartHook();
void OnBnClickedBtnCallMsgBox();
void OnBnClickedBtnStopHook();
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
    TRACE(lpText);
    HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的
    //如果不恢复HOOK,就调用原函数,会造成死循环
    //毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。

    int nRet = ::MessageBoxW(hWnd, _T("MessageBoxW被HOOK了"), lpCaption, uType);

    HookOn();//调用完原函数后,记得继续开启HOOK,不然下次会HOOK不到。 

    return nRet;
}

//开启钩子的函数
void HookOn()
{
    ASSERT(hProcess != NULL);

    DWORD dwTemp = 0;
    DWORD dwOldProtect;

    //修改API函数入口前5个字节为jmp xxxxxx
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
    WriteProcessMemory(hProcess, pfOldMsgBoxW, NewCode, 5, 0);
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);

}

//关闭钩子的函数
void HookOff()
{
    ASSERT(hProcess != NULL);

    DWORD dwTemp = 0;
    DWORD dwOldProtect;

    //恢复API函数入口前5个字节
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
    WriteProcessMemory(hProcess, pfOldMsgBoxW, OldCode, 5, 0);
    VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}

//获取API函数入口前5个字节
//旧入口前5个字节保存在前面定义的字节数组BYTE OldCode[5]
//新入口前5个字节保存在前面定义的字节数组BYTE NewCode[5]
void GetApiEntrance()
{
    HMODULE hmod = ::LoadLibrary(_T("User32.dll"));
    OldMsgBoxW = (MsgBoxW)::GetProcAddress(hmod, "MessageBoxW");
    pfOldMsgBoxW = (FARPROC)OldMsgBoxW;

    if (pfOldMsgBoxW == NULL)
    {
        MessageBox(NULL, _T("获取原API入口地址出错"), _T("error!"), 0);
        return;
    }
    _asm
    {
        lea edi, OldCode        //获取OldCode数组的地址,放到edi
            mov esi, pfOldMsgBoxW //获取原API入口地址,放到esi
            cld   //方向标志位,为以下两条指令做准备
            movsd //复制原API入口前4个字节到OldCode数组
            movsb //复制原API入口第5个字节到OldCode数组
    }
    NewCode[0] = 0xe9;//实际上0xe9就相当于jmp指令
    _asm
    {
        lea eax, MyMessageBoxW //获取我们的MyMessageBoxW函数地址
            mov ebx, pfOldMsgBoxW  //原系统API函数地址
            sub eax, ebx             //int nAddr= UserFunAddr – SysFunAddr
            sub eax, 5           //nAddr=nAddr-5
            mov dword ptr[NewCode + 1], eax //将算出的地址nAddr保存到NewCode后面4个字节
            //注:一个函数地址占4个字节
    }
    HookOn();
}

void OnBnClickedBtnStartHook()
{
    DWORD dwPid = ::GetCurrentProcessId();
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);

    GetApiEntrance();
    printf("Hook已启动");
}


void OnBnClickedBtnCallMsgBox()
{
    HWND m_hWnd = GetConsoleWindow();
    ::MessageBoxW(m_hWnd, _T("这是正常的MessageBoxW"), _T("Hello"), 0);
}

//停止HOOK
void OnBnClickedBtnStopHook()
{
    HookOff();
    printf("Hook未启动");
}

void main()
{
    OnBnClickedBtnStartHook();
    OnBnClickedBtnStopHook();
    OnBnClickedBtnCallMsgBox();
}

HOOK前

HOOK后

原作者的程序是窗口的

我提取了下,改成dos了

原作者连接

  • 0
    点赞
  • 0
    收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值