您的位置:首页 > 其它

HOOK所有程序的MessageBox

2016-03-20 22:19 295 查看


HOOK所有程序的MessageBox

标签: HOOKHOOK
APIAPIDLLMFC
2013-10-01 22:31 4749人阅读 评论(12) 收藏 举报


分类:

MFC(43)

VC(100)

C++(44)

HOOK(7)


版权声明:本文为博主原创文章,未经博主允许不得转载。

让我学会HOOK的一篇文章:http://blog.sina.com.cn/s/blog_628821950100xmuc.html //感激不尽呀

文章出处,好像是这篇:http://blog.csdn.net/glliuxueke/article/details/2702608 //我后来才看到的

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

这篇文章用到的HOOK代码,跟我的前一篇文章【HOOK API入门之Hook自己程序的MessageBoxW】差不多,

其地址是:http://blog.csdn.net/friendan/article/details/12222651

因为这次HOOK的是系统所有用到MessageBox的程序,所以我们必须把代码写在dll文件中,

这里我用的是MFC DLL

-------------------------------------------------------------------------------------------------------------------------------------------------------------

熟悉API的都知道,系统中没有MessageBox,有的只是MessageBoxA和MessageBoxW,

因此HOOK MessageBox,其实是HOOK MessageBoxA和MessageBoxW。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

//老规矩,先看看我们的程序及效果截图,后面再进行分析,文章后面附有VS2008源码下载

//程序主界面



//HOOK 程序本身的MessageBoxA



///HOOK 程序本身的MessageBoxW



//启动HOOK后,切换到记事本的查找功能,其调用的MessageBoxW也被我们HOOK了



-------------------------------------------------------------------------------------------------------------------------------------

关于dll如何和主程序对话框进行通信,请看我的另一篇文章【低级鼠标钩子WH_MOUSE_LL

文章地址:http://blog.csdn.net/friendan/article/details/12168273

-------------------------------------------------------------------------------------------------------------------------------------

下面说一下HOOK所有程序的MessageBox的思路。

首先必须明确我们的HOOK代码是写在dll文件中的,要HOOK一个程序的MessageBox,则必须

让其加载我们的dll文件,如何才能让一个程序加载我们的dll文件呢?这里我用的是鼠标钩子,

即我们安装一个全局的鼠标钩子WH_MOUSE,这样当任何一个程序响应鼠标消息时,其就会

加载我们的dll文件,按理说,窗口程序都会响应鼠标消息的,不然我们怎么能移动一个窗口呢。

当然,不响应鼠标消息的程序,如果你也想HOOK它,换其它类型的钩子即可。

---------------------------------------------------------------------------------------------------------------------------------------------------

下面说一下该dll文件的编写过程:

1.打开VS 2008,新建一个MFC DLL工程,dll类型我选择的是【带静态链接MFC的规则DLL(R)】



---------------------------------------------------------------------------------------------------------------------------------------------------

2.在dll文件中编写安装鼠标钩子的函数StartHook(HWND hWnd)和卸载鼠标钩子的函数StopHook(),

这里说的只是个大概的过程,变量定义什么的,我就忽略了,具体请看原工程源码,

我们这里只说重点。

相关代码如下:

[cpp] view
plain copy

print?

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

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

LRESULT CALLBACK MouseProc(

int nCode, // hook code

WPARAM wParam, // message identifier

LPARAM lParam // mouse coordinates

)

{

if (nCode==HC_ACTION)

{

//将钩子所在窗口句柄发给主程序

::SendMessage(g_hWnd,UM_WNDTITLE,wParam,(LPARAM)(((PMOUSEHOOKSTRUCT)lParam)->hwnd));

}

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

}

//安装钩子

BOOL WINAPI StartHook(HWND hWnd)

{

g_hWnd=hWnd;

hhk=::SetWindowsHookEx(WH_MOUSE,MouseProc,hInst,0);

if (hhk==NULL)

{

return FALSE;

}

else

{

return TRUE;

}

}

//卸载钩子

VOID WINAPI StopHook()

{

HookOff();//记得恢复原API入口哈

//主程序调用该函数时,恢复的只是主程序原API的入口,

//其它程序的API入口还没有被恢复,所以我们必须处理

//dll退出过程,即在函数ExitInstance()中,调用恢复

//API入口的函数HookOff(),只有这样,其它程序再次调用

//原API时,才不会发生错误喔。

//当我们HOOK所有程序的某个系统API时,千万要注意在

//ExitInstance()中调用HookOff(),血的教训哈。

if (hhk!=NULL)

{

UnhookWindowsHookEx(hhk);

FreeLibrary(hInst);

}

}

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

3.导出我们的StartHook(HWND hWnd)和StopHook()函数,给外部程序调用,如果不导出,我们的主程序是调用不到

这两个函数的哦。如何导出呢?找到dll工程中的,后缀为def的文件,打开它,然后在里面写上要导出

的函数的名字即可,如:

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

LIBRARY "HookMessageBox"

EXPORTS

StartHook //导出StartHook

StopHook //导出StopHook

; 此处可以是显式导出

//截图如下



--------------------------------------------------------------------------------------------------------------------------------------------------------------

4.在MFC dll的入口函数InitInstance()编写代码,写什么代码好呢?

因为HOOK一个程序的API,我们必须知道它的进程句柄,既然程序加载我们的dll时,会

执行dll入口函数,我们就在这里获取该程序的进程句柄。

也因为我们要HOOK加载我们dll程序的API,因此我们就在dll入口处HOOK MessageBox,

即程序一记载我们的dll文件时,我们就HOOK其API。

主要代码如下:

[cpp] view
plain copy

print?

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

BOOL CHookMessageBoxApp::InitInstance()

{

CWinApp::InitInstance();

hInst=AfxGetInstanceHandle();

DWORD dwPid=::GetCurrentProcessId();

hProcess=::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

Inject();//开始注入,即HOOK

return TRUE;

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

5.接下我们要特别处理dll的退出函数ExitInstance(),注意呀,我们一定要在dll的退出函数ExitInstance()里面,

写上恢复原API入口的代码或函数,不然程序再次调用该API时,会崩溃,因为dll退出后,假API函数也就不存在了。

[cpp] view
plain copy

print?

//dll退出时

int CHookMessageBoxApp::ExitInstance()

{

HookOff();//dll退出时,记得恢复原API入口哈,血的教训呀。

//当我们钩所有程序的API,且dll退出没有恢复原API入口时,

//那么当被钩程序再次调用该API时,会发生错误,因为我们的

//dll程序已经退出了,原来API入口被修改的前五个字节还是

//指向我们dll中的自己定义的函数地址,现在dll退出,该地址

//自然也就不存在了,程序调用该地址时,自然会发生崩溃了。

return CWinApp::ExitInstance();

}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

6.在主程序中调用dll文件导出的两个函数StartHook(HWND hWnd)和StopHook(),

代码如下:

[cpp] view
plain copy

print?

//安装钩子

HINSTANCE g_hInst=NULL;

void CHookTestDlg::OnBnClickedBtnStartHook()

{

g_hInst=::LoadLibrary(_T("HookMessageBox.dll"));//加载dll文件

if (g_hInst==NULL)

{

AfxMessageBox(_T("Load HookMessageBox.dll Failed"));

return;

}

typedef BOOL (WINAPI* StartHook)(HWND hWnd);//函数原型定义

StartHook Hook;

Hook=(StartHook)::GetProcAddress(g_hInst,"StartHook");//获取函数地址

if (Hook==NULL)

{

AfxMessageBox(_T("GetFunction StartHook Failed"));

return;

}

if (Hook(m_hWnd))//调用函数

{

AfxMessageBox(_T("Hook Ok"));

}

else

{

AfxMessageBox(_T("Hook Failed"));

}

}

//卸载钩子

void CHookTestDlg::OnBnClickedBtnStopHook()

{

if (g_hInst==NULL)

{

return;

}

typedef VOID (WINAPI* StopHook)();//函数原型定义

StopHook UnHook;

UnHook=(StopHook)::GetProcAddress(g_hInst,"StopHook");//获取函数地址

if (UnHook==NULL)

{

AfxMessageBox(_T("GetFunction StopHook Failed"));

FreeLibrary(g_hInst);

g_hInst=NULL;

return;

}

UnHook();//调用函数

FreeLibrary(g_hInst);

g_hInst=NULL;

AfxMessageBox(_T("StopHook ok"));

}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以上就是HOOK系统所有程序MessageBox的大致流程了,前面说了HOOK的代码跟我写的前一篇文章的HOOK代码差别不大,

灵活应变一下即可,看不明白的盆友,请结合源码和文章来看,希望有助于你的理解。这里还是要特别强调一下,要在dll的

退出函数中恢复原API入口,千万别忘记哦。

本工程源码下载地址:Hook所有程序的MessageBox.zip

http://download.csdn.net/detail/friendan/6347041

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

接下来贴一下本工程dll文件的主要代码:

[cpp] view
plain copy

print?

#define UM_WNDTITLE WM_USER+100 //自定义消息

//全局共享变量

#pragma data_seg(".Share")

HWND g_hWnd=NULL;//主窗口句柄;

HHOOK hhk=NULL; //鼠标钩子句柄;

HINSTANCE hInst=NULL;//本dll实例句柄;

#pragma data_seg()

#pragma comment(linker, "/section:.Share,rws")

HANDLE hProcess=NULL;

BOOL bIsInjected=FALSE;

//原函数定义

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

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

MsgBoxA oldMsgBoxA=NULL; //用于保存原函数地址

MsgBoxW oldMsgBoxW=NULL; //用于保存原函数地址

FARPROC pfMsgBoxA=NULL;//指向原函数地址的远指针

FARPROC pfMsgBoxW=NULL;//指向原函数地址的远指针

BYTE OldCodeA[5]; //老的系统API入口代码

BYTE NewCodeA[5]; //要跳转的API代码 (jmp xxxx)

BYTE OldCodeW[5]; //老的系统API入口代码

BYTE NewCodeW[5]; //要跳转的API代码 (jmp xxxx)

int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);

int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);

//开启钩子的函数

void HookOn()

{

ASSERT(hProcess!=NULL);

DWORD dwTemp=0,dwOldProtect,dwRet=0,dwWrite;

//修改原API入口前五个字节为jmp xxxxxxxx

//Debug版本在我这里修改失败,运行Release版本成功

VirtualProtectEx(hProcess,pfMsgBoxA,5,PAGE_READWRITE,&dwOldProtect);

dwRet=WriteProcessMemory(hProcess,pfMsgBoxA,NewCodeA,5,&dwWrite);

if (0==dwRet||0==dwWrite)

{

TRACE("啊,写入失败");

}

VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,&dwTemp);

//修改原API入口前五个字节为jmp xxxxxxxx

//Debug版本在我这里修改失败,运行Release版本成功

VirtualProtectEx(hProcess,pfMsgBoxW,5,PAGE_READWRITE,&dwOldProtect);

dwRet=WriteProcessMemory(hProcess,pfMsgBoxW,NewCodeW,5,&dwWrite);

if (0==dwRet||0==dwWrite)

{

TRACE("啊,写入失败");

}

VirtualProtectEx(hProcess,pfMsgBoxW,5,dwOldProtect,&dwTemp);

}

//关闭钩子的函数

void HookOff()//将所属进程中add()的入口代码恢复

{

ASSERT(hProcess!=NULL);

DWORD dwTemp=0,dwOldProtect=0,dwRet=0,dwWrite=0;

//恢复原API入口

VirtualProtectEx(hProcess,pfMsgBoxA,5,PAGE_READWRITE,&dwOldProtect);

dwRet=WriteProcessMemory(hProcess,pfMsgBoxA,OldCodeA,5,&dwWrite);

if (0==dwRet||0==dwWrite)

{

TRACE("啊,写入失败");

}

VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,&dwTemp);

//恢复原API入口

VirtualProtectEx(hProcess,pfMsgBoxW,5,PAGE_READWRITE,&dwOldProtect);

WriteProcessMemory(hProcess,pfMsgBoxW,OldCodeW,5,&dwWrite);

if (0==dwRet||0==dwWrite)

{

TRACE("啊,写入失败");

}

VirtualProtectEx(hProcess,pfMsgBoxW,5,dwOldProtect,&dwTemp);

}

void Inject()

{

if (!bIsInjected)

{

bIsInjected=TRUE;//保证只调用1次

//获取函数

HMODULE hmod=::LoadLibrary(_T("User32.dll"));

oldMsgBoxA=(MsgBoxA)::GetProcAddress(hmod,"MessageBoxA");

pfMsgBoxA=(FARPROC)oldMsgBoxA;

oldMsgBoxW=(MsgBoxW)::GetProcAddress(hmod,"MessageBoxW");

pfMsgBoxW=(FARPROC)oldMsgBoxW;

if (pfMsgBoxA==NULL)

{

MessageBox(NULL,_T("cannot get MessageBoxA()"),_T("error"),0);

return;

}

if (pfMsgBoxW==NULL)

{

MessageBox(NULL,_T("cannot get MessageBoxW()"),_T("error"),0);

return;

}

// 将原API中的入口代码保存入OldCodeA[],OldCodeW[]

_asm

{

lea edi,OldCodeA

mov esi,pfMsgBoxA

cld

movsd

movsb

}

_asm

{

lea edi,OldCodeW

mov esi,pfMsgBoxW

cld

movsd

movsb

}

NewCodeA[0]=0xe9;//实际上0xe9就相当于jmp指令

NewCodeW[0]=0xe9;//实际上0xe9就相当于jmp指令

//获取我们的API的地址

_asm

{

lea eax,MyMessageBoxA

mov ebx,pfMsgBoxA

sub eax,ebx

sub eax,5

mov dword ptr [NewCodeA+1],eax

}

_asm

{

lea eax,MyMessageBoxW

mov ebx,pfMsgBoxW

sub eax,ebx

sub eax,5

mov dword ptr [NewCodeW+1],eax

}

//填充完毕,现在NewCode[]里的指令相当于Jmp Myadd

HookOn(); //可以开启钩子了

}

}

//我们的假API函数MyMessageBoxA

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

{

int nRet=0;

HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的

//如果不恢复HOOK,就调用原函数,会造成死循环

//毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。

nRet=::MessageBoxA(hWnd,"哈哈,MessageBoxA被HOOK了吧",lpCaption,uType);

nRet=::MessageBoxA(hWnd,lpText,lpCaption,uType);

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

return nRet;

}

//我们的假API函数MyMessageBoxW

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

{

int nRet=0;

HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的

//如果不恢复HOOK,就调用原函数,会造成死循环

//毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。

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

nRet=::MessageBoxW(hWnd,lpText,lpCaption,uType);

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

return nRet;

}

// CHookMessageBoxApp

BEGIN_MESSAGE_MAP(CHookMessageBoxApp, CWinApp)

END_MESSAGE_MAP()

// CHookMessageBoxApp 构造

CHookMessageBoxApp::CHookMessageBoxApp()

{

}

// 唯一的一个 CHookMessageBoxApp 对象

CHookMessageBoxApp theApp;

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

BOOL CHookMessageBoxApp::InitInstance()

{

CWinApp::InitInstance();

hInst=AfxGetInstanceHandle();

DWORD dwPid=::GetCurrentProcessId();

hProcess=::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

Inject();//开始注入,即HOOK

return TRUE;

}

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

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

LRESULT CALLBACK MouseProc(

int nCode, // hook code

WPARAM wParam, // message identifier

LPARAM lParam // mouse coordinates

)

{

if (nCode==HC_ACTION)

{

//将钩子所在窗口句柄发给主程序

::SendMessage(g_hWnd,UM_WNDTITLE,wParam,(LPARAM)(((PMOUSEHOOKSTRUCT)lParam)->hwnd));

}

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

}

//安装钩子

BOOL WINAPI StartHook(HWND hWnd)

{

g_hWnd=hWnd;

hhk=::SetWindowsHookEx(WH_MOUSE,MouseProc,hInst,0);

if (hhk==NULL)

{

return FALSE;

}

else

{

return TRUE;

}

}

//卸载钩子

VOID WINAPI StopHook()

{

HookOff();//记得恢复原API入口哈

//主程序调用该函数时,恢复的只是主程序原API的入口,

//其它程序的API入口还没有被恢复,所以我们必须处理

//dll退出过程,即在函数ExitInstance()中,调用恢复

//API入口的函数HookOff(),只有这样,其它程序再次调用

//原API时,才不会发生错误喔。

//当我们HOOK所有程序的某个系统API时,千万要注意在

//ExitInstance()中调用HookOff(),血的教训哈。

if (hhk!=NULL)

{

UnhookWindowsHookEx(hhk);

FreeLibrary(hInst);

}

}

//dll退出时

int CHookMessageBoxApp::ExitInstance()

{

HookOff();//dll退出时,记得恢复原API入口哈,血的教训呀。

//当我们钩所有程序的API,且dll退出没有恢复原API入口时,

//那么当被钩程序再次调用该API时,会发生错误,因为我们的

//dll程序已经退出了,原来API入口被修改的前五个字节还是

//指向我们dll中的自己定义的函数地址,现在dll退出,该地址

//自然也就不存在了,程序调用该地址时,自然会发生崩溃了。

return CWinApp::ExitInstance();

}

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------




您的十分满意是我追求的宗旨。

您的一点建议是我后续的动力。




0


0

上一篇HOOK
API入门之Hook自己程序的MessageBoxW

下一篇Windows
API Hook

我的同类文章

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: