Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1276848
  • 博文数量: 185
  • 博客积分: 50
  • 博客等级: 民兵
  • 技术积分: 3934
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-11 13:11
个人简介

iihero@ChinaUnix, ehero.[iihero] 数据库技术的痴迷爱好者. 您可以通过iihero AT qq.com联系到我 以下是我的三本图书: Sybase ASE in Action, Oracle Spatial及OCI高级编程, Java2网络协议内幕

文章分类

全部博文(185)

文章存档

2014年(4)

2013年(181)

分类: 数据库开发技术

2013-11-16 19:55:16

生病并调养近半年了,也好久没有写博文了,真是有些抱歉,总有心有余力不足的感觉。

最近,遇到一种使用情形,需要覆盖Windows系统API的默认行为,而且可能不光涉及到Win32 x86,x64,可能还要涉及到wince平台。

本文只是一个简要的技术介绍,有兴趣的朋友可以一步步摸索下去。

首先是Win32 x86/x64下边,比如,我要覆盖'MessageBoxA'的调用(e.g.只是举例,实际可能更复杂一些)

典型的,效率也蛮高的方法是通过改写原API的函数地址,从而达到”覆盖“的目的。

示例如下:

  1. // hookdemo.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. #define FLATJMPCODE_LENGTH 5            //x86 平坦内存模式下,绝对跳转指令长度  
  7. #define FLATJMPCMD_LENGTH  1            //机械码0xe9长度  
  8. #define FLATJMPCMD         0xe9  
  9.   
  10.   
  11. //HOOK函数  
  12. BOOL HookApi(LPVOID ApiFun,LPVOID HookFun)  
  13. {  
  14.     BOOL    IsSuccess = FALSE;  
  15.     DWORD   TempProtectVar;              //临时保护属性变量  
  16.     MEMORY_BASIC_INFORMATION MemInfo;    //内存分页属性信息  
  17.      
  18.     VirtualQuery(ApiFun,&MemInfo,sizeof(MEMORY_BASIC_INFORMATION));   
  19.      
  20.     if(VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize,  
  21.         PAGE_READWRITE,&MemInfo.Protect))                            //修改页面为可写  
  22.     {  
  23.         *(BYTE*)ApiFun = FLATJMPCMD;                                       
  24.         *(DWORD*)((BYTE*)ApiFun + FLATJMPCMD_LENGTH) = (DWORD)HookFun -  
  25.             (DWORD)ApiFun - FLATJMPCODE_LENGTH;  
  26.          
  27.         VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize,  
  28.             MemInfo.Protect,&TempProtectVar);                               //改回原属性  
  29.          
  30.         IsSuccess = TRUE;  
  31.     }  
  32.      
  33.     return IsSuccess;  
  34. }  
  35.   
  36. //我的新API函数  
  37. int __stdcall MyHookFn(HWND hwnd,char* sztext,char* szTitle,int stly)  
  38. {            
  39.      
  40.     return printf("%s - %s\n",sztext,"原API函数已被HOOK!");   //  
  41. }  
  42.   
  43. void* MyMalloc(int size)  
  44. {  
  45.     printf("size = %d\n", size);  
  46.     return NULL;  
  47. }  
  48.   
  49. //我的新私有桩函数  
  50. void MyHookFn2(char* szTxt)  
  51. {  
  52.     char* pBuf = (char*)malloc(strlen(szTxt) + sizeof(char*) * 32);  
  53.      
  54.     __try  
  55.     {  
  56.         sprintf(pBuf,"%s - %s",szTxt," 原函数已被HOOK!");  
  57.         printf("%s\n",pBuf);  
  58.     }  
  59.     __finally  
  60.     {  
  61.         free(pBuf);  
  62.     }  
  63. }  
  64.   
  65. //私有测试函数  
  66. void TestFn(char* szTitle)  
  67. {  
  68.     printf("%s",szTitle);  
  69. }  
  70.   
  71. int _tmain(int argc, _TCHAR* argv[])  
  72. {  
  73.     printf("hello\n");  
  74.   
  75.   
  76.     HMODULE hDll, hDll2;  
  77.     LPVOID  OldFun, of2;    
  78.   
  79.   
  80.   
  81.     __try  
  82.     {  
  83.         hDll = GetModuleHandle("User32.dll");  
  84.         OldFun = GetProcAddress(hDll,"MessageBoxA");  //要HOOK的API函数  
  85.         hDll2 = GetModuleHandle("msvcr90.dll");  
  86.         of2 = GetProcAddress(hDll2, "malloc");  
  87.         if(OldFun)  
  88.         {  
  89.             if(HookApi(OldFun,MyHookFn))  //如果HOOK成功  
  90.                 MessageBoxA(0,"call Api MessageBox","Is Hookd?",MB_OK); //调用原API,测试HOOK  
  91.   
  92.             if (HookApi(of2, MyMalloc))  
  93.                 malloc(1);  
  94.   
  95.             if(HookApi(TestFn,MyHookFn2))  
  96.                 TestFn("Private Function Hook Test");  //调用私有函数,测试HOOK     
  97.         }  
  98.     }  
  99.     __finally  
  100.     {  
  101.         if(hDll)  
  102.             FreeLibrary(hDll);  
  103.     }  
  104.      
  105.     return 0;  
在release模式下,malloc也会被覆盖。


这样,我的目的还真能达到,我可以随心所欲的覆盖malloc和free,从而让当前进程使用我定制的malloc和free。

这种方式是通过改写函数调用地址的方式来实现的,在x86/x64下边运行没什么障碍,可惜在WinCE平台下边,无法实现。

WinCE下边,上边那些API函数的地址并不是明确固定的。需要专门的Hook API来控制。多年前微软自行开发了套Hook工具库detour,相信这个可以在系统API的拦截和覆盖应用里派上用场。

由于我的场景里头,只需要定制new和delete,所以还没有使用专门的Hook API来实现,而是使用了全局重载操作符new 和 delete来实现,虽然有一定风险,但最终也还是可行的。

在Unix平台下,可以使用PRE_LOAD DLL的相关编译指令,优先加载你定制的DLL(在这个DLL里实现要覆盖的API)来简单实现API覆盖,那是非常简单的技术。有兴趣的可以GOOGLE一下。

阅读(4537) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~