不用汇编实现HOOK MessageBoxW

66 篇文章 0 订阅
51 篇文章 3 订阅

参考文章:http://blog.csdn.net/masefee/article/details/5664416

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

关于HOOK的跳转地址,网上流传着一条公式:

int nAddr= UserFunAddr – SysFunAddr - (我们定制的这条指令的大小,一般为5);
Jmp nAddr;

有篇文章谈了jmp的计算方法:jmp 偏移地址的计算方法

http://blog.csdn.net/twtzw/article/details/3436443

想说的是,一开始我就是按着上述公式来进行HOOK的,然而却HOOK失败,

调试跟踪了很久,发现上述公式不适合我这篇文章说的HOOK,后来我将公式

修改如下,就HOOK成功了:

int nAddr= UserFunAddr – SysFunAddr;
Jmp nAddr;

说这些,目的是想让大家学会灵活应变吧。

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

接下来,进入正题,无汇编代码HOOK MessageBoxW

先看下MessageBoxW的反汇编代码:

75C2EA5A 90               nop              
75C2EA5B 90               nop              
75C2EA5C 90               nop              
75C2EA5D 90               nop              
75C2EA5E 90               nop              
75C2EA5F 8B FF            mov         edi,edi 
75C2EA61 55               push        ebp  
75C2EA62 8B EC            mov         ebp,esp 
75C2EA64 83 3D 74 9A C3 75 00 cmp         dword ptr ds:[75C39A74h],0 
75C2EA6B 74 24            je          75C2EA91 
75C2EA6D 64 A1 18 00 00 00 mov         eax,dword ptr fs:[00000018h] 
75C2EA73 6A 00            push        0    
75C2EA75 FF 70 24         push        dword ptr [eax+24h] 
75C2EA78 68 A4 9E C3 75   push        75C39EA4h 
75C2EA7D FF 15 34 14 BD 75 call        dword ptr ds:[75BD1434h] 
75C2EA83 85 C0            test        eax,eax 
75C2EA85 75 0A            jne         75C2EA91 
75C2EA87 C7 05 A0 9E C3 75 01 00 00 00 mov         dword ptr ds:[75C39EA0h],1 
75C2EA91 6A 00            push        0    
75C2EA93 FF 75 14         push        dword ptr [ebp+14h] 
75C2EA96 FF 75 10         push        dword ptr [ebp+10h] 
75C2EA99 FF 75 0C         push        dword ptr [ebp+0Ch] 
75C2EA9C FF 75 08         push        dword ptr [ebp+8] 
75C2EA9F E8 49 FF FF FF   call        75C2E9ED 
75C2EAA4 5D               pop         ebp  
75C2EAA5 C2 10 00         ret         10h  
...

如何得到以上汇编代码呢?很简单,在VS2008中,在调用MessageBoxW的地方下调试断点,

断下来后,在MessageBoxW上面,点鼠标右键,选择【转到汇编代码】,然后单步跟踪就可以看到了。

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

HOOK的原理很简单,就是修改API的入口,使其跳转到我们的假API,观察上述汇编代码,注意红色的

代码:

75C2EA5A 90               nop              
75C2EA5B 90               nop              
75C2EA5C 90               nop              
75C2EA5D 90               nop              
75C2EA5E 90               nop              
75C2EA5F 8B FF            mov         edi,edi 

如果你单步跟踪过MessageBoxW时,你会发现,进入MessageBoxW函数时的首地址是75C2EA5F,

MessageBoxW的入口代码是这一行:75C2EA5F      8B FF            mov         edi,edi 

不难得出MessageBoxW的入口指令是:mov    edi,edi  该指令的机器码是:8B FF  共占两个字节的内存空间。

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

假设我们的假API函数地址为addr=12345678,该地址占用四个字节的内存空间,实际上无论是我们的函数还

是系统API,它们的地址都占用4个字节的内存空间。

我们知道Jmp指令的机器码为E9,占一个字节的内存空间,所以Jmp  12345678占用5个字节的内存空间,

前面说了MessageBoxW的入口指令是:mov    edi,edi只有两个字节的内存空间,而我们的跳转指令却有5个

字节,我们改如何修改MessageBoxW的入口使其跳转到我们的假API函数呢?想呀想...

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

再看看MessageBoxW的入口反汇编代码:

75C2EA5A 90               nop              
75C2EA5B 90               nop              
75C2EA5C 90               nop              
75C2EA5D 90               nop              
75C2EA5E 90               nop              
75C2EA5F 8B FF            mov         edi,edi 
75C2EA61 55               push        ebp  
75C2EA62 8B EC            mov         ebp,esp 

...

你注意到了没,MessageBoxW入口的前5条汇编指令都是nop,机器码为90,

这5条什么都不做的nop指令,刚好占5个字节,这是巧合吗?还是上天的安排O(∩_∩)O哈!

实际上很多系统的API入口都是上面这个样子,感谢MS留给我们的5个字节哈\(^o^)/~

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

这下HOOK的思路就出来啦,我们将Jmp  12345678写到MessageBoxW入口的前五个字节,

MessageBoxW入口的前两个字节8B  FF改为EB  F9,为什么要改成EB  F9呢?

哈哈,机器码EB  F9可以实现跳转,只是其跳转的距离比较短,

机器码EB表示short  jmp,即短跳转了。

机器码F9表示向后偏移7个字节,相当于负数7了。

EB  F9连起来,就是跳转到MessageBoxW入口前面的第5个地址处了,即去执行我们的Jmp  12345678,

为什么是跳转到MessageBoxW入口前面的第5个地址处呢?不是第7个?F9不是负7吗?

答案是:EB  F9占用的2个字节也要算哦,即从F9的地址开始跳。

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

好,有了以上的知识,就可以开始编写程序了,也有助于我们理解代码,

文章后面我会给本程序的源码下载地址,先看下程序截图:


//未HOOK前


//HOOK后


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

主要代码如下:

//函数原型及变量定义
typedef int (WINAPI *MsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);
MsgBoxW OldMsgBoxW=NULL;//保存API函数入口地址
BYTE *pfApiFunc=NULL;//用于修改API函数入口

//函数声明
int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);

//开始HOOK
void HookOn()
{
	//获取API入口地址
	HINSTANCE hInst=LoadLibrary(_T("User32.dll"));
	OldMsgBoxW=(MsgBoxW)::GetProcAddress(hInst,"MessageBoxW");
	if (OldMsgBoxW==NULL)
	{
		AfxMessageBox(_T("获取原API地址出错!"));
		return;
	}
	pfApiFunc=( BYTE* )OldMsgBoxW- 5;

	//获取进程句柄
	HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,0,GetCurrentProcessId());
	if (hProcess==NULL)
	{
		return;
	}

	//修改API入口前7个字节
	DWORD dwOldProtect=0;
	VirtualProtectEx(hProcess,pfApiFunc,7,PAGE_EXECUTE_READWRITE,&dwOldProtect);
	//(int&)pfSrcFunc[1]=(int)MyMessageBoxW-(int)OldMsgBoxW-5;//经测试减5会HOOK失败
	pfApiFunc[0]=0xE9;//机器码E9,表示Jmp
	(int&)pfApiFunc[1]=(int)MyMessageBoxW-(int)OldMsgBoxW;//API地址占4个字节空间
	pfApiFunc[5]=0xEB;//机器码EB,表示short jmp
	pfApiFunc[6]=0xF9;//机器码F9表示向后偏移7个字节,相当于负数7了
					  //EB F9连起来表示:short jmp offset: -7  即往后跳7步
	VirtualProtectEx(hProcess,pfApiFunc,7,dwOldProtect,NULL);
}

//停止HOOK
void HookOff()
{
	//获取进程句柄
	HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,0,GetCurrentProcessId());
	if (hProcess==NULL)
	{
		return;
	}

	//恢复API前7个字节
	DWORD dwOldProtect=0;
	VirtualProtectEx(hProcess,pfApiFunc,7,PAGE_EXECUTE_READWRITE,&dwOldProtect); 
	memset(pfApiFunc,0x90,5);  //机器码90,表示nop 
	pfApiFunc[ 5 ] = 0x8B;  //8B FF表示:mov edi,edi 
	pfApiFunc[ 6 ] = 0xFF;  //8B FF表示:mov edi,edi  
	VirtualProtectEx(hProcess,pfApiFunc,7,dwOldProtect,NULL);
}

//我们的假API函数
int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
	int nRet=0;
	HookOff();//恢复真API入口
	nRet=::MessageBoxW(NULL,L"MessageBoxW被钩了吧!",L"测试",0);//调用真API
	HookOn();//再次HOOK真API
	return nRet;
}



//开始HOOK MessageBoxW
void CHookNoAsmDlg::OnBnClickedBtnStartHook()
{
	HookOn();
}

//停止HOOK MessageBoxW
void CHookNoAsmDlg::OnBnClickedBtnStopHook()
{
	HookOff();
}

//调用MessageBoxW
void CHookNoAsmDlg::OnBnClickedBtnCallMsgw()
{
	::MessageBoxW(m_hWnd,L"这是真正的MessageBoxW",L"测试",0);
}

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

本例子VS2008+MFC源码下载:不用汇编实现HOOK.zip

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

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

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

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





  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

friendan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值