Inline Hook(ring3)的简单C++实现方法
C++的InlineHook代码,采用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要把函数头部改来改去。用SetWindowsHookEx程序的稳定性应该会增加许多。
需要注意的是,例子中没有把原函数的头部几个字节改回去是因为,程序很简单,仅仅测试了效果后便可以退出,没有其他的功能。实际应用中,还要在你注入的dll模块卸载时,把原函数的头几个字节改回去,以免影响到程序继续运行的稳定性。(因为注入的程序不是自己的,我们当然不可能知道它到底在何时、有多少个我们所Hook的函数的调用)。
具体实现代码如下:
#include<ntifs.h>
#include<windef.h>
#include<stdio.h>
#pragmacomment(lib,"psapi.lib")
//BYTEOrg_Code[7];//备份dll法,因此就可以不需要
BYTENew_Code[7];
HMODULEhDllHandle=NULL;//被Hook的DLL句柄
HANDLEhProcess=NULL;//进程句柄
LPVOID_MessageBoxA=NULL;//MessageBoxA()原地址
DWORD_ShowMessage=NULL;//自定义函数地址
voidInlineHook();
//voidUnInlineHook();//备份dll法,因此就可以不需要
voidBackupDll();
//自定义函数
intWINAPIShowMessage(HWND,LPTSTR,LPTSTR,UINT);
voidmain()
{
hProcess=::GetCurrentProcess();
hDllHandle=::LoadLibrary("user32.dll");
if(hDllHandle==NULL)
return;
_MessageBoxA=(LPVOID)::GetProcAddress(hDllHandle,"MessageBoxA");
if(_MessageBoxA==NULL)
return;
BackupDll();
InlineHook();
charszText[256];
charszTitle[256];
memset(szText,0x0,sizeof(szText));
memset(szTitle,0x0,sizeof(szTitle));
//下列循环接收来自于用户输入的字符,并使用MessageBoxA()
//来显示,尝试下,看看发生了什么.:)
while(TRUE)
{
printf("MessageText:");
scanf("%s",szText);
printf("MessageTitle:");
scanf("%s",szTitle);
MessageBoxA(NULL,szText,szTitle,0);
printf("\n");
}
return;
}
voidInlineHook()
{
DWORD_JmpAddr=(DWORD)ShowMessage;
//构造新头部代码
New_Code[0]=0xB8;//
memcpy(&New_Code[1],&_JmpAddr,4);//moveax,_JmpAddr
New_Code[5]=0xFF;//
New_Code[6]=0xE0;//jmpeax
DWORDdwOldProtect=0;
//去内存保护
::VirtualProtect(_MessageBoxA,7,PAGE_EXECUTE_READWRITE,&dwOldProtect);
//把新代码写入MessageBoxA()的头部,这也是InlineHook
//的核心所在.
::WriteProcessMemory(
hProcess,
_MessageBoxA,
New_Code,
sizeof(New_Code),
NULL
);
//写内存保护
::VirtualProtect(_MessageBoxA,7,dwOldProtect,&dwOldProtect);
return;
}
/*
voidUnInlineHook()//备份dll法,因此就可以不需要
{
return;
}
*/
intWINAPIShowMessage(HWNDhWnd,LPTSTRlpText,LPTSTRlpTitle,UINTuType)
{
typedefintWINAPISHOWMSG(HWNDhWnd,LPTSTRlpText,LPTSTRlpTitle,UINTuType);
SHOWMSG*pShowMsg=(SHOWMSG*)_ShowMessage;
//废弃原先传入的参数,自己定义对话框文本
charbuf[1024];
::wsprintf(buf,"TheText:"%s"washackedbymiku_fl",lpText);
returnpShowMsg(hWnd,buf,lpTitle,MB_ICONINFORMATION|MB_TOPMOST);
}
voidBackupDll()
{
MODULEINFOMdl_Info;
LPVOIDlpNewDLL=NULL;
//获取模块信息
::GetModuleInformation(hProcess,hDllHandle,&Mdl_Info,sizeof(Mdl_Info));
//分配内存空间,用于备份dll(这样一来就不需要恢复原头部代码,调用
//完之后再重新写自定义的头部代码).
lpNewDLL=::VirtualAllocEx(
hProcess,
NULL,
Mdl_Info.SizeOfImage,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
if(lpNewDLL==NULL)
return;
//在分配的内存中写入dll文件的内容
::WriteProcessMemory(hProcess,lpNewDLL,Mdl_Info.lpBaseOfDll,Mdl_Info.SizeOfImage,NULL);
//计算自定义函数的地址.
//公式:自定义地址=原API函数地址-模块基址+分配内存的基址
_ShowMessage=(DWORD)_MessageBoxA-(DWORD)Mdl_Info.lpBaseOfDll+(DWORD)lpNewDLL;
return;
}
希望本文所述程序实例能对大家有所帮助。