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

时间:2023-03-08 15:56:51
HOOK API(三)—— HOOK 所有程序的 MessageBox

HOOK API(三)

—— HOOK 所有程序的 MessageBox

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的实现

  1. 建立一个MFC DLL工程

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

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

  1. 鼠标钩子回调函数

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

/*

鼠标钩子子过程,目的是加载本dll到使用鼠标的程序中。

鼠标钩子的作用:当鼠标在某程序窗口中时,就会加载我们这个dll。

*/

LRESULT CALLBACK MouseProc(

int nCode,     // hook code

WPARAM wParam,// message identifier

LPARAM lParam // mouse coordinates

)

{

return CallNextHookEx(hhk,nCode,wParam,lParam);

}

  1. 安装鼠标钩子

调用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;

}

}

  1. 卸载鼠标钩子

//

// 卸载钩子

//

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;

}

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

.def内容如下:

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

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

LIBRARY "HookMessageBox"

EXPORTS

; 此处可以是显式导出

StartHook

StopHook

  1. 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;

}

  1. MFC DLL的ExitInstance()函数

int CHookDllApp::ExitInstance()

{

/*

dll退出时,一定要记得恢复原API的入口!!!

我们编写的dll会被注入到所有目标进程中,若dll退出时,没有恢复原API入口,

那么被挂钩的程序再次调用该API时,会发生错误。

因为我们的dll程序已经退出,但原API的入口仍为我们所定义的API的入口,这

时被挂钩的程序无法找到我们实现的API,然而原API的地址又没有被恢复,也就

调用不到原API,这时程序自然会发生崩溃了。

*/

HookOff();

return CWinApp::ExitInstance();

}

  1. 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

}

  1. 写内存函数

该函数主要完成向进程控制块写写指令的任务。供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);

}

  1. 用新API地址替换原API地址

/*

用新API地址替换原API地址

*/

void HookOn()

{

ASSERT(hProcess != NULL);

DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);

WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);

}

  1. 恢复原API地址

/*

恢复原API地址

*/

void HookOff()

{

ASSERT(hProcess != NULL);

DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);

WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);

}

  1. 新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;

}

  1. 提升权限函数

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

/*

提升权限

*/

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 窗体实现

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

  1. 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);

}

}

  1. 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成功"));

}

  1. MessageBoxA

// MessageBoxA

void CHookWindowDlg::OnBnClickedButtonMsga()

{

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

MessageBoxA(m_hWnd,"这是正常的MessageBoxA...","哈哈",0);

}

  1. MessageBoxW

// MessageBoxW

void CHookWindowDlg::OnBnClickedButtonMsgw()

{

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

MessageBoxW(_T("这是正常的MessageBoxW..."),_T("呵呵"),0);

}

0x03 测试

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

  1. 启动钩子

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

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

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

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

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

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

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

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

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

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

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

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

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

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 调用。

//

//        有关其他详细信息,

//

// 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;

}