本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与HOOK API(二)中介绍的基本类似,唯一不同的是,本实例要实现对所有程序的HOOK MessageBox,即无论系统中哪一个程序调用MessageBox都会被重定向到我们实现的新的API中。
之前说过,在Windows中,每个进程都有自己的地址空间,进程不能调用别的进程中的函数。这里涉及到一个关键,如何让我们实现的新的API调用地址存在于所有进程的地址空间中呢?如果这无法实现的话,其他进程就无法调用到我们所实现的API。这里涉及到的关键就是,如何将我们的代码注入到别的进程中。
这里有一个实现手段,就是将我们实现的代码随着系统钩子注入到目标进程中,我们在HOOK API (一)中讲过鼠标钩子,鼠标钩子一旦启动,就会存在于每个当前运行的进程中,实现对屏幕坐标的定位。还有一个关键就是,这样的钩子需要注入到多个目标进程中,那么这就要在动态链接库(DLL)中实现,然后启动某一主调进程将这样一个DLL注入到目标进程中,从而实现HOOK API。
本实例介绍如何将实现了HOOK MessageBox的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
/*
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();
}
注入函数,保存新的,原来的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 地址
*/
void HookOff()
{
ASSERT(hProcess != NULL);
DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);
WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);
}
/*
自己用于替换的 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 ;
}
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);
}
}
//
// 终止 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
void CHookWindowDlg::OnBnClickedButtonMsga()
{
// TODO: 在此添加控件通知处理程序代码
MessageBoxA(m_hWnd, " 这是正常的 MessageBoxA..." , " 哈哈 " ,0);
}
// MessageBoxW
void CHookWindowDlg::OnBnClickedButtonMsgw()
{
// TODO: 在此添加控件通知处理程序代码
MessageBoxW(_T( " 这是正常的 MessageBoxW..." ),_T( " 呵呵 " ),0);
}
本实例在自己实现的API中打印一句自己的话,然后再弹出原本的对话框。测试结果如下:
单击"MessageBoxA"按钮,调用MessageBoxA函数
可以看到,先弹出了我们自己的对话框,然后才弹出真正的对话框。
单击"MessageBoxW"按钮,调用MessageBoxW函数。
可以看到,先弹出我们的对话框,然后才弹出真正的对话框。
记事本的对话框也被HOOK了。
打开技术本,打开查找对话框,然后输入一个字符串,"查找一下",这个时候同样先弹出我们的对话框,然后才弹出原来的,找不到对话框。
// 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;
}