我的学习笔记之五——inline_HOOK完美篇(ring3_inline_EXE_hook_Messagebox完美篇)


2008-12-25 12:50:30|  分类: 编程与电脑技术|字号 订阅

以下内容转载自看雪
标 题: 【原创】RING3代码HOOK的原理实现 (学习笔记1)
作 者: bzhkl
时 间: 2008-12-10,14:13
链 接: http://bbs.pediy.com/showthread.php?t=78418

最初看见俄国一份DELPHI代码这样实现,他的优点在于
   1, 在代理函数的内部不用先UNHOOK,再调用,再重新HOOK,否则多线程下会出问题
   2, 没有硬编码,结构性比较好。


bool AfxHookCode(void* TargetProc, void* NewProc,void ** l_OldProc, int bytescopy = 5)
{

   DWORD dwOldProtect;

   ::VirtualProtect((LPVOID)TargetProc, bytescopy, PAGE_EXECUTE_READWRITE, &dwOldProtect);

   *l_OldProc = new unsigned char[bytescopy+5];           // 为拷贝执行被覆盖的指令申请空间 


   memcpy(*l_OldProc, TargetProc, bytescopy);            // 事先保存被破坏的指令

   *((unsigned char*)(*l_OldProc) + bytescopy) = 0xe9;     // 我的内存的代码执行完 跳到原来的 代码 + 破坏的代码的长度 上去

                             //被破坏指令的长度      //E9 opcode长度           //算出偏移的OPCODE     = 被HOOK函数地址的地址 + 破坏指令的长度 - 我分配内存的结束地址                            
     *(unsigned int *)((unsigned char*)(*l_OldProc) +bytescopy           +      1)           =    (unsigned int)(TargetProc) + bytescopy - ( (unsigned int)((*l_OldProc)) + 5 + bytescopy ) ;   // 我内存代码跳到原来代码上的偏移


   *(unsigned char*)TargetProc =(unsigned char)0xe9;              //被HOOK的函数头改为jmp


                                   //算出偏移的OPCODE   = 代理函数地址 - 被HOOK函数地址
   *(unsigned int*)((unsigned int)TargetProc +1) = (unsigned int)NewProc - ( (unsigned int)TargetProc + 5) ; //被HOOK的地方跳到我的新过程 接受过滤


   ::VirtualProtect((LPVOID)TargetProc, bytescopy, dwOldProtect, 0);
   return true;
}


bool AfxUnHookCode(void* TargetAddress, void * l_SavedCode, unsigned int len)
{
     DWORD dwOldProtect;

     ::VirtualProtect((LPVOID)TargetAddress, len, PAGE_EXECUTE_READWRITE, &dwOldProtect);   

     // 恢复被破坏处的指令 
     memcpy(TargetAddress, l_SavedCode, len);

     ::VirtualProtect((LPVOID)TargetAddress, len, dwOldProtect, 0);

     return true;
}



unsigned int *   OldProc;
typedef 
int 
(__stdcall * MYMESSAGEBOX)      //用于调用自己分配内存处的代码强制转换
    (
     IN HWND hWnd,
     IN LPCSTR lpText,
     IN LPCSTR lpCaption,
     IN UINT uType);


int 
__stdcall        // 这里不声明成stdcall的话 编译器认为是C声明方式 要自己平衡堆栈  
MyMessageBox(
     IN HWND hWnd,
     IN LPCSTR lpText,
     IN LPCSTR lpCaption,
     IN UINT uType)
{

   // 这里可以执行一些过滤行为 比如改变参数 或者 直接模拟返回正确的结果
   if ( strcmp(lpText, "sample") == 0)
   {
     printf("filter");
     return 1;
   }


       //强制转换成API函数类型 调用原来的函数
    return ( (MYMESSAGEBOX) OldProc)(hWnd, lpText, lpCaption, uType);

}




int main()
{
   MessageBox(0, "sample", "caption", MB_OK);    //正常调用MSG

                                                                 // 这里一定要传地址变量的地址   直接传地址的话 地址变量是一份拷贝 根本不能保存分配的内存的地址(在我看来 指针就是地址变量)
                                   //当初写的时候调了3遍才知道这个原因- -
   AfxHookCode((void*)MessageBox, (void*)MyMessageBox, (void**)&OldProc, 5);


   MessageBox(0, "sample", "caption", MB_OK);   //被过滤掉了

   AfxUnHookCode((void*)MessageBox, OldProc, 5); // 恢复被hook的代码

   getchar();

   return 0;
}

我理解其中跳转关系为下图

你可能感兴趣的:(我的学习笔记之五——inline_HOOK完美篇(ring3_inline_EXE_hook_Messagebox完美篇))