我的学习笔记之三——inline使用DLL进行全局HOOK(ring3_inline_dll_hook_Messagebox)

前一篇学习了修改导入表来HOOK  API,虽然是自己HOOK自己,但稍改一下,变成DLL就可以全局HOOK,因为windows有数据执行保护会拦截,所以就不再深入。
还有一种HOOK  API法叫INLINE  HOOK就是采用JMP法。长话短说,所谓的API  HOOK指的就是  :系统函数接口的钩子。当系统函数进行调用时,首先进入我们指定的函数,然后再执行系统的函数。IAT是修改EXE的导入地址,而JMP修改的是DLL中函数中的内容。我们知道,系统函数都是以DLL封装起来的,应用程序应用到系统函数时,应首先把该DLL加载到当前的进程空间中,调用的系统函数的入口地址,可以通过GetProcAddress函数进行获取。当系统函数进行调用的时候,首先把所必要的信息保存下来(包括参数和返回地址,等一些别的信息),然后就跳转到函数的入口地址,继续执行。其实函数地址,就是系统函数“可执行代码”的开始地址。那么怎么才能让函数首先执行我们的函数呢?呵呵,应该明白了吧,把开始的那段可执行代码替换为我们自己定制的一小段可执行代码,这样系统函数调用时,不就按我们的意图乖乖行事了吗?其实,就这么简单。
也就是说:如果我们已经挂钩好了系统函数。那么当系统进行系统调用时,进入DLL对应的函数,首先就碰到我们的Jmp  XXXX指令,而这条指令作用就是跳到我们的函数中去执行。总体流程应该如下:

保存系统函数入口-等待进入我们的函数-恢复系统函数入口-可以做一些我们想做的操作-调用系统函数  -挂接系统函数-保存系统函数入口

有几点很重要(1)JMP后面是我们函数的地址,此处要准确,计算公式为XXXX  =  我的函数入口指针(地址)-  系统函数入口指针(地址)-  sizeof  (Jmp  XXXX指令的大小);(2)替换掉的代码一定要保存好,以便随时恢复,否则肯定出错(3)拦截函数中返回值要和正确调用正确函数一至,以无逢提交给系统
下面给出具体的DLL代码
#include  <windows.h>

HHOOK  g_hHook; 
HINSTANCE  g_hinstDll; 
FARPROC  fpMessageBoxA;

HMODULE  hModule; 
BYTE  OldMessageBoxACode[5],NewMessageBoxACode[5]; 
DWORD  dwIdOld,dwIdNew; 
BOOL  bHook=false;

void  HookOn(); 
void  HookOff(); 
BOOL  Init(); 
int  WINAPI  MyMessageBoxA(HWND  hWnd,LPCTSTR  lpText,LPCTSTR  lpCaption,UINT  uType); 
//--------------------------------------------------------------------------- 
//  空的钩子函数 
LRESULT  WINAPI  Hook(int  nCode,WPARAM  wParam,LPARAM  lParam) 

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

//--------------------------------------------------------------------------- 
//  输出,安装空的钩子函数 
extern"C"__declspec(dllexport)  bool  InstallHook() 

          g_hinstDll=LoadLibrary("dll.dll");  //  这里的文件名为Dll本身的文件名 
          g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); 
        if  (!g_hHook) 
          { 
            MessageBoxA(NULL,"SET  ERROR","ERROR",MB_OK); 
        return(false); 
          } 
        return(true); 

//--------------------------------------------------------------------------- 
//  输出,Uninstall钩子函数 
extern"C"__declspec(dllexport)  bool  UninstallHook() 

          HookOff() 
        return(UnhookWindowsHookEx(g_hHook)); 

//--------------------------------------------------------------------------- 
//  初始化得到MessageBoxA的地址,并生成Jmp  XXX(MyMessageBoxA)的跳转指令 
BOOL  Init() 

          hModule=LoadLibrary("user32.dll"); 
          fpMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 
        if(fpMessageBoxA==NULL)  return  false; 
          _asm 
          { 
              pushad 
              lea  edi,OldMessageBoxACode 
              mov  esi,fpMessageBoxA 
              cld 
              movsd 
              movsb 
              popad 
          } 
          NewMessageBoxACode[0]  =  0xe9;  //  jmp  MyMessageBoxA的相对地址的指令 
          _asm 
          { 
              lea  eax,MyMessageBoxA 
              mov  ebx,fpMessageBoxA 
              sub  eax,ebx 
              sub  eax,5 
              mov  dword  ptr  [NewMessageBoxACode  +  1],eax 
          } 
          dwIdNew  =  GetCurrentProcessId();  //  得到所属进程的ID 
          dwIdOld  =  dwIdNew; 
          HookOn();  //  开始拦截 
        return(true); 

//--------------------------------------------------------------------------- 
//  首先关闭拦截,然后才能调用被拦截的Api  函数 
int  WINAPI  MyMessageBoxA(HWND  hWnd,LPCTSTR  lpText,LPCTSTR  lpCaption,UINT  uType) 

        int  nReturn; 
          HookOff(); 
          nReturn  =  MessageBoxA(hWnd,"来自钩子中的内容",lpCaption,MB_OK  |  MB_ICONINFORMATION); 
          HookOn(); 
        return(nReturn); 

void  HookOn() 

          HANDLE  hProc; 
          dwIdOld  =  dwIdNew; 
        //  得到所属进程的句柄 
          hProc  =  OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 
        //  修改所属进程中MessageBoxA的前5个字节的属性为可写 
          VirtualProtectEx(hProc,fpMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 
        //  将所属进程中MessageBoxA的前5个字节改为JMP  到MyMessageBoxA 
          WriteProcessMemory(hProc,fpMessageBoxA,NewMessageBoxACode,5,0); 
        //  修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 
          VirtualProtectEx(hProc,fpMessageBoxA,5,dwIdOld,&dwIdOld); 
          bHook=true; 

//--------------------------------------------------------------------------- 
//  将所属进程中JMP  MyMessageBoxA的代码改为Jmp  MessageBoxA 
void  HookOff() 

          HANDLE  hProc; 
          dwIdOld  =  dwIdNew; 
          hProc  =  OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 
          VirtualProtectEx(hProc,fpMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 
          WriteProcessMemory(hProc,fpMessageBoxA,OldMessageBoxACode,5,0); 
          VirtualProtectEx(hProc,fpMessageBoxA,5,dwIdOld,&dwIdOld); 
          bHook  =  false; 

//--------------------------------------------------------------------------- 
int  WINAPI  DllMain(HINSTANCE  hinst,unsigned  long  reason,void*  lpReserved) 

        switch  (reason) 
          { 
            case  DLL_PROCESS_ATTACH: 
                if(!Init()) 
                  { 
                          MessageBoxA(NULL,"Init","ERROR",MB_OK); 
                        return(false); 
                  } 
            case  DLL_PROCESS_DETACH: 
                if(bHook)  UninstallHook(); 
                break; 
          } 
        return  TRUE; 

网上有个代码和这一样,我这里有两处改了下,否则不行。
记住这个是全局HOOK  Messagebox,会挂住系统中大部分进程。关于DLL全局HOOK,我不打算再说,其实就是把DLL加载到系统的每个进程空间,HOOK住所有进程,注意说的是每个进程,你也看到了是用WH_GETMESSAGE消息加载全局钩子的,没消息循环的进程当然钩不住了,另外有和程序对进程和模块实施了保护也不行,有的程序会拦截全局钩子的加载,你可能会失败。
此法也存在明显不足,因为当有个程序使用Messagebox时,会进入我们的DLL的MyMessageBoxA中,而它在此先做了HOOKOFF又做了HOOKON,如果有个程序是多线程调用MessageBoxA,可能会出现这个写时那个读,没写完就要读从而出错,windows核心编程早就说了它的不足。最后提醒一下,有的弹出式对话框并不是调用的MessageBoxA,要HOOK住系统中所有的弹出式对话框还要HOOK另个版本MessageBoxW或更多的API。

你可能感兴趣的:(我的学习笔记之三——inline使用DLL进行全局HOOK(ring3_inline_dll_hook_Messagebox))