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; }
希望本文所述程序实例能对大家有所帮助。