HOOK API(三)—— HOOK 所有程序的 MessageBox

HOOK API(三)

—— HOOK 所有程序的 MessageBox

原文出处:http://www.cnblogs.com/fanling999/p/4595035.html

程序源代码:https://github.com/hfl15/windows_kernel_development/tree/master/demo_source_code/HoolAllMessageBox

0x00 前言

本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与HOOK API(二)中介绍的基本类似,唯一不同的是,本实例要实现对所有程序的HOOK MessageBox,即无论系统中哪一个程序调用MessageBox都会被重定向到我们实现的新的API中。

之前说过,在Windows中,每个进程都有自己的地址空间,进程不能调用别的进程中的函数。这里涉及到一个关键,如何让我们实现的新的API调用地址存在于所有进程的地址空间中呢?如果这无法实现的话,其他进程就无法调用到我们所实现的API。这里涉及到的关键就是,如何将我们的代码注入到别的进程中。

这里有一个实现手段,就是将我们实现的代码随着系统钩子注入到目标进程中,我们在HOOK API (一)中讲过鼠标钩子,鼠标钩子一旦启动,就会存在于每个当前运行的进程中,实现对屏幕坐标的定位。还有一个关键就是,这样的钩子需要注入到多个目标进程中,那么这就要在动态链接库(DLL)中实现,然后启动某一主调进程将这样一个DLL注入到目标进程中,从而实现HOOK API。

本实例介绍如何将实现了HOOK MessageBox的DLL注入到所有进程中的过程。

0x01 HOOK DLL的实现

建立一个MFC DLL工程

由于被实例的DLL用于MFC框架,因此创建的是MFC DLL,需要的话,也可以建立其他类型的DLL工程。

鼠标钩子回调函数

我们的DLL要跟随鼠标钩子注入到目标进程中,而鼠标钩子是系统钩子,我们需要实现其钩子回调函数。

/*
     鼠标钩子子过程,目的是加载本dll到使用鼠标的程序中。
     鼠标钩子的作用:当鼠标在某程序窗口中时,就会加载我们这个dll。
*/

LRESULT CALLBACK MouseProc(
                        int nCode,     // hook code
                        WPARAM wParam,// message identifier
                        LPARAM lParam // mouse coordinates
                        )
{
return CallNextHookEx(hhk,nCode,wParam,lParam); }

安装鼠标钩子

调用SetWindowsHookEx() API可以安装鼠标钩子,其中SetWindowsHookEx() 原型如下:

HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )

参数:

idHook表示钩子类型,它是和钩子函数类型一一对应的。比如,WH_KEYBOARD表示安装的是键盘钩子,WH_MOUSE表示是鼠标钩子等等。

  Lpfn是钩子函数的地址。

  HMod是钩子函数所在的实例的句柄。对于线程钩子,该参数为NULL;对于系统钩子,该参数为钩子函数所在的DLL句柄。

dwThreadId 指定钩子所监视的线程的线程号。对于全局钩子,该参数为NULL。

返回值:

  SetWindowsHookEx返回所安装的钩子句柄。

//
// 安装钩子
//
BOOL WINAPI StartHook(HWND hWnd){

    g_hWnd = hWnd;
    hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0);

    if (hhk == NULL){
        return FALSE;
    }else{
        return TRUE;
    }
}
 

卸载鼠标钩子

//
// 卸载钩子
//
BOOL WINAPI StopHook()
{    

    /*
        卸载钩子时,一定要记得恢复原API入口。
        这里恢复的只是主程序的原API入口,其它程序的API入口还没有被恢复。
        因此我们必须处理dll退出过程,即在函数ExitInstance()中,调用恢复
        API入口的函数HookOff(),只有这样,其它程序再次调用原API时,才不
        会发生错误。
        当我们HOOK所有程序的某个系统API时,千万要注意在ExitInstance()中
        调用HookOff()!!!!!
    */

    HookOff();
    if (hhk!=NULL){
        UnhookWindowsHookEx(hhk);
        FreeLibrary(g_hInstance);
    }

    return TRUE;
} 

导出我们的安装和卸载函数

.def内容如下:

将StarHook和StopHook函数导出,一遍主程序安装和卸载HOOK程序。

; HookDll.def : 声明 DLL 的模块参数。

LIBRARY "HookMessageBox"

EXPORTS

; 此处可以是显式导出

    StartHook

    StopHook

MFC DLL的InitInstance()函数

 

/*
    dll程序入口,当程序加载dll时,会执行InitInstance()
*/

BOOL CHookDllApp::InitInstance(){

    CWinApp::InitInstance();
    g_hInstance = AfxGetInstanceHandle();//    获取当前DLL实例句柄

    AdjustPrivileges();    //    提高权限
    DWORD dwPid = ::GetCurrentProcessId();
    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);
    if (hProcess == NULL){
        CString str;
        str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError());
        AfxMessageBox(str);
        return FALSE;
    }

    Inject();    // 开始注入
    return TRUE;
}

MFC DLL的ExitInstance()函数

 

int CHookDllApp::ExitInstance(){

    /*
        dll退出时,一定要记得恢复原API的入口!!!
        我们编写的dll会被注入到所有目标进程中,若dll退出时,没有恢复原API入口,
        那么被挂钩的程序再次调用该API时,会发生错误。
        因为我们的dll程序已经退出,但原API的入口仍为我们所定义的API的入口,这
        时被挂钩的程序无法找到我们实现的API,然而原API的地址又没有被恢复,也就
        调用不到原API,这时程序自然会发生崩溃了。
    */

    HookOff();
    return CWinApp::ExitInstance();
}

HOOK API实现

  1. 注入函数,保存新的,原来的API的入口

该函数的主要功能是保存新的和原来的API入口,并且在最后启动HOOK。需要注意的是,这个函数只能被调用一次,即只能进行一次注入操作。

/*
    注入
*/
void Inject(){

    if ( TRUE == bIsInJected){
        return;
    }

    bIsInJected = TRUE;    // 保证只调用一次

    //
    // 获取函数
    //
    HMODULE hmodle = ::LoadLibrary(_T("User32.dll"));
    oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA");
    pfMsgBoxA = (FARPROC)oldMsgBoxA;

    oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW");
    pfMsgBoxW = (FARPROC)oldMsgBoxW;

    if (pfMsgBoxA == NULL){
        AfxMessageBox(_T("获取 MessageBoxA 函数失败"));
        return;
    }

    if ( pfMsgBoxW == NULL){

        AfxMessageBox(_T("获取 MessageBoxW 函数失败"));
        return;
    }

    // 保存原API地址
    _asm
    {
        lea edi,oldCodeA    // 取数组基地址
        mov esi,pfMsgBoxA    // API地址
        cld                    // 设置方向
        mov ecx,CODE_LENGTH
        rep movsb
    }

    _asm{
        lea edi,oldCodeW
        mov esi,pfMsgBoxW
        cld
        mov ecx,CODE_LENGTH
        rep movsb
    }

    // 将新地址复制到入口
    newCodeA[0] = newCodeW [0] = 0xe9;    // jmp 指定代码
    _asm
    {
        lea eax,MyMessageBoxA        // 新API地址
        mov ebx,pfMsgBoxA            // 原API地址
        sub eax,ebx                
        sub eax,CODE_LENGTH            // 跳转地址 = 新API地址 - 原API地址 - 指令长度
        mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE
    }

    _asm
    {
        lea eax,MyMessageBoxW
        mov ebx,pfMsgBoxW
        sub eax,ebx
        sub eax,CODE_LENGTH
        mov dword ptr [newCodeW + 1],eax
    }

    HookOn();    //    开始HOOK
 
}
写内存函数

该函数主要完成向进程控制块写写指令的任务。供HookOn()和HookOff()调用,用来将原API入口,或新的API入口写入到进程的地址空间中。

/*
    将长度为length的pcode写入到地址lpAddress中。
*/
void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length){

    //    保证本进程句柄不为NULL
    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

    // 修改API入口前length个字节为 jmp xxxx
    VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect);

    dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited);
    if ( 0 == dwRet || 0 == dwWrited){
        AfxMessageBox(_T("哭!!写入失败"));
    }
    VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp);
}
用新API地址替换原API地址
/*
    用新API地址替换原API地址
*/
void HookOn(){

    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

    WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);
    WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);
}
恢复原API地址
/*  
    恢复原API地址
*/
void HookOff(){
    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
    WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);
    WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);
}
新API定义
/*
    自己用于替换的API
*/

int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType){

    int nRet = 0;
    HookOff();

    nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType);
    nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType);

    HookOn();
    return nRet;
}


int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType){

    int nRet = 0;
    HookOff();

    nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType);
    nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType);

    HookOn();

    return nRet;
}
提升权限函数

这段代码并不是必须的,但有些时候会出现程序权限不足以获取进程句柄的情况,这个时候需要在代码执行前调用该函数来提高程序的权限。

/*
     提升权限
*/
bool AdjustPrivileges() {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    TOKEN_PRIVILEGES oldtp;
    DWORD dwSize=sizeof(TOKEN_PRIVILEGES);
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true;
        else return false;
    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
        CloseHandle(hToken);
        return false;
    }

    ZeroMemory(&tp, sizeof(tp));
    tp.PrivilegeCount=1;
    tp.Privileges[0].Luid=luid;
    tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;

    /* Adjust Token Privileges */
    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) {
        CloseHandle(hToken);
        return false;
    }

    // close handles
    CloseHandle(hToken);

    return true;
}

0x02 HOOK 窗体实现

StartHook
HINSTANCE g_hinstDll = NULL;

// 开始 HOOK
void CHookWindowDlg::OnBnClickedButtonStart(){

    // TODO: 在此添加控件通知处理程序代码

    g_hinstDll = LoadLibrary(_T("HookDll.dll"));
    if ( NULL == g_hinstDll){
        AfxMessageBox(_T("加载 HookDll.dll 失败"));
    }

    typedef BOOL (CALLBACK *HookStart)(HWND hwnd);
    HookStart hookStart = NULL;
    hookStart = (HookStart)::GetProcAddress(g_hinstDll,"StartHook");
    if ( NULL == hookStart){
        AfxMessageBox(_T("获取 StartHook 函数失败"));
        return;
    }

    bool ret = hookStart(m_hWnd);
    if (ret){
        m_list.InsertItem(m_list.GetItemCount(),_T("启动钩子成功"));
        m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE);
    }else{
        m_list.InsertItem(m_list.GetItemCount(),_T("启动钩子失败"));
        m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE);
    }
}

 

StopHook
// 终止 HOOK
void CHookWindowDlg::OnBnClickedButtonStop(){

    // TODO: 在此添加控件通知处理程序代码
    typedef BOOL (CALLBACK* HookStop)();
    HookStop hookStop = NULL;
    if (NULL == g_hinstDll) // 一定要加这个判断,若不为空的话就不需要在重新加载,否则会是不同的实例
    {
        g_hinstDll = LoadLibrary(_T("HookDll.dll"));
        if (g_hinstDll == NULL){
            AfxMessageBox(_T("加载 HookDll.dll 失败"));
            return;
        }
    }

    hookStop = ::GetProcAddress(g_hinstDll,"StopHook");
    if (hookStop == NULL){
        AfxMessageBox(_T("获取 StopHook 失败"));
        FreeLibrary(g_hinstDll);
        g_hinstDll=NULL;
        return;
    }

    hookStop();
    if (g_hinstDll!= NULL){
        ::FreeLibrary(g_hinstDll);
    }

    m_list.InsertItem(m_list.GetItemCount(),_T("终止HOOK成功"));

}
MessageBoxA
// MessageBoxA
void CHookWindowDlg::OnBnClickedButtonMsga(){

    // TODO: 在此添加控件通知处理程序代码
    MessageBoxA(m_hWnd,"这是正常的MessageBoxA...","哈哈",0);
}
MessageBoxW
// MessageBoxW
void CHookWindowDlg::OnBnClickedButtonMsgw(){

    // TODO: 在此添加控件通知处理程序代码
    MessageBoxW(_T("这是正常的MessageBoxW..."),_T("呵呵"),0);
}

0x03 测试

本实例在自己实现的API中打印一句自己的话,然后再弹出原本的对话框。测试结果如下:

启动钩子

单击"MessageBoxA"按钮,调用MessageBoxA函数

可以看到,先弹出了我们自己的对话框,然后才弹出真正的对话框。

单击"MessageBoxW"按钮,调用MessageBoxW函数。

可以看到,先弹出我们的对话框,然后才弹出真正的对话框。

记事本的对话框也被HOOK了。

打开技术本,打开查找对话框,然后输入一个字符串,"查找一下",这个时候同样先弹出我们的对话框,然后才弹出原来的,找不到对话框。

0x04 附录——HOOK DLL关键源码

// HookDll.cpp : 定义 DLL 的初始化例程。

#include "stdafx.h"
#include "HookDll.h"
#include <Windows.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

/*
     全局共享变量
*/
#pragma data_seg("Share")
HWND g_hWnd = NULL ;            // 主窗口句柄
HINSTANCE g_hInstance = NULL;    // 本dll实例句柄
HHOOK hhk = NULL;                // 鼠标钩子句柄
#pragma data_seg()
#pragma comment(linker,"/section:Share,rws")

HANDLE hProcess = NULL;                //    当前进程
BOOL bIsInJected = FALSE;            //    是否已注入标记
TCHAR* msgToMain = new TCHAR[200];    //    发给主调程序的信息

/*
    原函数定义
*/

typedef int (WINAPI *TypeMsgBoxA)(HWND hWnd,LPCSTR lpText, LPCSTR lpCaption,UINT uType);

typedef int (WINAPI *TypeMsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);

TypeMsgBoxA oldMsgBoxA = NULL;    // 用于保存原函数地址
TypeMsgBoxW oldMsgBoxW = NULL;    // 用于保存原楷书地址
FARPROC pfMsgBoxA = NULL;        // 指向原函数地址的远指针
FARPROC pfMsgBoxW = NULL;        // 指向原函数地址的远指针

#define CODE_LENGTH 5
BYTE oldCodeA[CODE_LENGTH];    // 保存原来API入口代码
BYTE oldCodeW[CODE_LENGTH];    // 保存原来API入口代码
BYTE newCodeA[CODE_LENGTH];    // 保存新API入口代码,jmp xxxx
BYTE newCodeW[CODE_LENGTH];    // 保存新API入口代码,jmp xxxx

/*
    自己编写的API
*/

int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType);
int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType);

/*
    其它函数原型声明
*/

void HookOn();            //    开始HOOK
void HookOff();            //    关闭HOOK
void Inject();            //    注入
BOOL WINAPI StartHook(HWND hWnd);    // 加载钩子
BOOL WINAPI StopHook();                // 卸载钩子
bool AdjustPrivileges();            // 提升权限

 
//
//TODO: 如果此 DLL 相对于 MFC DLL 是动态链接的,
//        则从此 DLL 导出的任何调入
//        MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到
//        该函数的最前面。
//
//        例如:
//
//        extern "C" BOOL PASCAL EXPORT ExportedFunction()
//        {
//            AFX_MANAGE_STATE(AfxGetStaticModuleState());
//            // 此处为普通函数体
//        }
//
//        此宏先于任何 MFC 调用
//        出现在每个函数中十分重要。这意味着
//        它必须作为函数中的第一个语句
//        出现,甚至先于所有对象变量声明,
//        这是因为它们的构造函数可能生成 MFC
//        DLL 调用。
//
//        有关其他详细信息,

//        请参阅 MFC 技术说明 33 和 58。
//

// CHookDllApp

BEGIN_MESSAGE_MAP(CHookDllApp, CWinApp)
END_MESSAGE_MAP()

// CHookDllApp 构造

CHookDllApp::CHookDllApp(){

    // TODO: 在此处添加构造代码,
    // 将所有重要的初始化放置在 InitInstance 中
}

// 唯一的一个 CHookDllApp 对象
CHookDllApp theApp;

// CHookDllApp 初始化

/*
    dll程序入口,当程序加载dll时,会执行InitInstance()
*/

BOOL CHookDllApp::InitInstance(){

    CWinApp::InitInstance();
    g_hInstance = AfxGetInstanceHandle();//    获取当前DLL实例句柄

    AdjustPrivileges();    //    提高权限
    DWORD dwPid = ::GetCurrentProcessId();
    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

    if (hProcess == NULL){
        CString str;
        str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError());
        AfxMessageBox(str);
        return FALSE;
    }
    Inject();    // 开始注入
    return TRUE;
}

int CHookDllApp::ExitInstance(){

    /*
        dll退出时,一定要记得恢复原API的入口!!!
        我们编写的dll会被注入到所有目标进程中,若dll退出时,没有恢复原API入口,
        那么被挂钩的程序再次调用该API时,会发生错误。
        因为我们的dll程序已经退出,但原API的入口仍为我们所定义的API的入口,这
        时被挂钩的程序无法找到我们实现的API,然而原API的地址又没有被恢复,也就
        调用不到原API,这时程序自然会发生崩溃了。
    */

    HookOff();
    return CWinApp::ExitInstance();
}

/*
     提升权限
*/
bool AdjustPrivileges() {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    TOKEN_PRIVILEGES oldtp;
    DWORD dwSize=sizeof(TOKEN_PRIVILEGES);
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true;
        else return false;
    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
        CloseHandle(hToken);
        return false;
    }

    ZeroMemory(&tp, sizeof(tp));
    tp.PrivilegeCount=1;
    tp.Privileges[0].Luid=luid;
    tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;

    /* Adjust Token Privileges */
    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) {
        CloseHandle(hToken);
        return false;
    }

    // close handles
    CloseHandle(hToken);
    return true;
}

/*
     鼠标钩子子过程,目的是加载本dll到使用鼠标的程序中。
     鼠标钩子的作用:当鼠标在某程序窗口中时,就会加载我们这个dll。
*/
LRESULT CALLBACK MouseProc(
                        int nCode,     // hook code
                        WPARAM wParam,// message identifier
                        LPARAM lParam // mouse coordinates
                        )
{
    return CallNextHookEx(hhk,nCode,wParam,lParam);
}

 
/*
    将长度为length的pcode写入到地址lpAddress中。
*/
void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length){

    //    保证本进程句柄不为NULL
    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

    // 修改API入口前length个字节为 jmp xxxx
    VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect);
    dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited);
    if ( 0 == dwRet || 0 == dwWrited){
        AfxMessageBox(_T("哭!!写入失败"));
    }
    VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp);
}

/*
    用新API地址替换原API地址
*/
void HookOn(){
    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
    WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);
    WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);
}

 

/*    
    恢复原API地址
*/
void HookOff(){

    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
    WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);
    WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);

}
 
/*
    注入
*/
void Inject(){

    if ( TRUE == bIsInJected){
        return;
    }
    bIsInJected = TRUE;    // 保证只调用一次

    //
    // 获取函数
    //
    HMODULE hmodle = ::LoadLibrary(_T("User32.dll"));
    oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA");
    pfMsgBoxA = (FARPROC)oldMsgBoxA;

    oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW");
    pfMsgBoxW = (FARPROC)oldMsgBoxW;

    if (pfMsgBoxA == NULL){
        AfxMessageBox(_T("获取 MessageBoxA 函数失败"));
        return;
    }

    if ( pfMsgBoxW == NULL){
        AfxMessageBox(_T("获取 MessageBoxW 函数失败"));
        return;
    }

    //
    // 保存原API地址
    //
    _asm
    {
        lea edi,oldCodeA    // 取数组基地址
        mov esi,pfMsgBoxA    // API地址
        cld                    // 设置方向
        mov ecx,CODE_LENGTH
        rep movsb
    }

    _asm
    {
        lea edi,oldCodeW
        mov esi,pfMsgBoxW
        cld
        mov ecx,CODE_LENGTH
        rep movsb
    }

    //
    // 将新地址复制到入口
    //
    newCodeA[0] = newCodeW [0] = 0xe9;    // jmp 指定代码
    _asm
    {
        lea eax,MyMessageBoxA        // 新API地址
        mov ebx,pfMsgBoxA            // 原API地址
        sub eax,ebx                
        sub eax,CODE_LENGTH            // 跳转地址 = 新API地址 - 原API地址 - 指令长度
        mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE

    }
_asm { lea eax,MyMessageBoxW mov ebx,pfMsgBoxW sub eax,ebx sub eax,CODE_LENGTH mov dword ptr [newCodeW
+ 1],eax } HookOn(); // 开始HOOK } // // 安装钩子 // BOOL WINAPI StartHook(HWND hWnd){ g_hWnd = hWnd; hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0); if (hhk == NULL){ return FALSE; } else{ return TRUE; } } // // 卸载钩子 // BOOL WINAPI StopHook(){ /* 卸载钩子时,一定要记得恢复原API入口。 这里恢复的只是主程序的原API入口,其它程序的API入口还没有被恢复。 因此我们必须处理dll退出过程,即在函数ExitInstance()中,调用恢复 API入口的函数HookOff(),只有这样,其它程序再次调用原API时,才不 会发生错误。 当我们HOOK所有程序的某个系统API时,千万要注意在ExitInstance()中 调用HookOff()!!!!! */ HookOff(); if (hhk!=NULL){ UnhookWindowsHookEx(hhk); FreeLibrary(g_hInstance); } return TRUE; } /* 自己用于替换的API */ int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType); nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType); HookOn(); return nRet; } int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType); nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType); HookOn(); return nRet; }
 
原文地址:https://www.cnblogs.com/fanling999/p/4595035.html