JMP方法HOOK

 JMP  HOOK  IAT  detours

 

Win9x   系统中,系统DLL被装入实际的物理存储器,然后映射到每个进程的0x80000000~0xBFFFFFFF共享内存区,如果修改这段区域的DLL代码,则对于所有进程都有效(实际Win98对主要的系统DLL作了保护,除非进入ring0才能修改)。      
  Win2000/NT   的进程空间不存在共享内存区,尽管DLL被装入之初在实际的物理存储器只有一份拷贝,但是Win2000/NT对DLL映射的内存页面采用copy-on-write保护机制,如果任何进程试图写入DLL所在的页面,系统将在实际的物理存储器创建一份该页面的拷贝,然后修改该进程的地址映射,使之指向拷贝的页面,这样进程对DLL页面的修改将仅仅在此进程有效。

 

本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me   下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,     
  在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,    
  因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:    
  其中Dll文件为:    
                      HHOOK   g_hHook;    
                      HINSTANCE   g_hinstDll;    
                      FARPROC   pfMessageBoxA;    
                      int   WINAPI   MyMessageBoxA(HWND   hWnd,   LPCTSTR   lpText,LPCTSTR   lpCaption,UINT   uType);    
                      BYTE   OldMessageBoxACode[5],NewMessageBoxACode[5];    
                      HMODULE   hModule   ;    
                      DWORD   dwIdOld,dwIdNew;    
                      BOOL   bHook=false;    
                      void   HookOn();    
                      void   HookOff();    
                      BOOL   init();    
  LRESULT   WINAPI   MousHook(int   nCode,WPARAM   wParam,LPARAM   lParam);    
  BOOL   APIENTRY   DllMain(   HANDLE   hModule,    
                                              DWORD     ul_reason_for_call,    
                                              LPVOID   lpReserved    
                                          )    
  {    
          switch   (ul_reason_for_call)    
          {    
                  case   DLL_PROCESS_ATTACH:    
                          if(!init())    
                          {    
                                                      MessageBoxA(NULL,"Init","ERROR",MB_OK);    
                                                      return(false);    
                          }    
                  case   DLL_THREAD_ATTACH:    
                  case   DLL_THREAD_DETACH:    
                  case   DLL_PROCESS_DETACH:    
                                              if(bHook)   UnintallHook();      
                                          break;    
          }    
          return   TRUE;    
  }    
  LRESULT   WINAPI   Hook(int   nCode,WPARAM   wParam,LPARAM   lParam)//空的钩子函数    
  {    
           
          return(CallNextHookEx(g_hHook,nCode,wParam,lParam));    
  }    
  HOOKAPI2_API   BOOL   InstallHook()//输出安装空的钩子函数    
  {      
      g_hinstDll=LoadLibrary("HookApi2.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);    
  }    
  HOOKAPI2_API   BOOL   UninstallHook()//输出御在钩子函数    
  {    
       
          return(UnhookWindowsHookEx(g_hHook));    
  }    
   
  BOOL   init()//初始化得到MessageBoxA的地址,并生成Jmp   XXX(MyMessageBoxA)的跳转指令    
  {    
          hModule=LoadLibrary("user32.dll");    
          pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");    
          if(pfMessageBoxA==NULL)    
              return   false;    
          _asm    
          {    
                  lea   edi,OldMessageBoxACode    
                  mov   esi,pfMessageBoxA    
                  cld    
                  movsd    
                  movsb    
          }    
          NewMessageBoxACode[0]=0xe9;//jmp   MyMessageBoxA的相对地址的指令    
          _asm    
          {    
                  lea   eax,MyMessageBoxA    
                  mov   ebx,pfMessageBoxA    
                  sub   eax,ebx    
                  sub   eax,5    
                  mov   dword   ptr   [NewMessageBoxACode+1],eax    
          }    
          dwIdNew=GetCurrentProcessId();   //得到所属进程的ID    
          dwIdOld=dwIdNew;    
          HookOn();//开始拦截    
          return(true);    
  }    
   
  int   WINAPI   MyMessageBoxA(HWND   hWnd,   LPCTSTR   lpText,LPCTSTR   lpCaption,   UINT   uType   )//首先关闭拦截,然后才能调用被拦截的Api   函数    
  {      
          int   nReturn=0;    
          HookOff();    
          nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);    
          HookOn();    
          return(nReturn);    
  }    
  void   HookOn()    
  {    
          HANDLE   hProc;    
          dwIdOld=dwIdNew;    
          hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄    
          VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写    
          WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP   到MyMessageBoxA    
          VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性    
          bHook=true;    
  }    
  void   HookOff()//将所属进程中JMP   MyMessageBoxA的代码改为Jmp   MessageBoxA    
  {    
          HANDLE   hProc;    
          dwIdOld=dwIdNew;    
          hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);    
          VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);    
          WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);    
          VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);    
          bHook=false;    
  }    
  //测试文件:    
  int   APIENTRY   WinMain(HINSTANCE   hInstance,    
                                          HINSTANCE   hPrevInstance,    
                                          LPSTR         lpCmdLine,    
                                          int             nCmdShow)    
  {    
           
          if(!InstallHook())    
          {    
                  MessageBoxA(NULL,"Hook   Error!","Hook",MB_OK);    
                  return   1;    
          }    
          MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见    
          if(!UninstallHook())    
          {    
                  MessageBoxA(NULL,"Uninstall   Error!","Hook",MB_OK);    
                  return   1;    
          }    
          return   0;    
  }   
 

void CHookClass::Init( LPCTSTR lpOldFun, FARPROC NewFun) 
{
 FARPROC OldFun;                         //被截函数的指针
 OldFun = GetFunctionAddress(lpOldFun);     //获取被截函数的地址
 if(OldFun==NULL)                      //被截函数地址获取失败返回false
 {
  return;
 }

 DWORD * pfNewFun;                         //自定义函数得临时变量
   pfOldFunction=OldFun;
 memcpy(m_OldFunctionCode,(char *)OldFun,5); //保存被截函数得前五个字节到数组m_OldFunctionCode[]中;
 m_NewFunctionCode[0]=0xe9;    
 pfNewFun=(DWORD*)&(m_NewFunctionCode[1]); //指针指向数组第二个字节;
 *pfNewFun=(DWORD)NewFun-(DWORD)OldFun-5;
 m_dwIdNew=GetCurrentProcessId();          //得到当前进程的ID
 HookChange();         //开始拦截
 return;
}


//----------------------------------------------------------------------------------------------

//HookChange(),拦截开始
void CHookClass::HookChange(void)
{
 
 m_dwIdOld=m_dwIdNew;

 //由所属进程的ID得到所属进程的句柄;
 m_hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, m_dwIdOld);
 if (m_hProc == NULL)
 {  
  OutputDebugString("拦截开始时未找到所属进程的句柄!");
  exit(-1);
 }
 
 //修改所属进程中被截函数的前五个字节的属性为可写
 VirtualProtectEx(m_hProc, pfOldFunction , 5, PAGE_READWRITE, &m_dwIdOld);

 //将所属进程中被截函数的前5个字节改为JMP (自定义函数地址)

 if( !bIsOSWin9x )
  WriteProcessMemory(m_hProc, pfOldFunction , m_NewFunctionCode, 5, 0);
 else
  WriteMemoryWithRing0((DWORD)pfOldFunction, m_NewFunctionCode, 5);

 //修改所属进程中被截函数的前5个字节的属性为原来的属性
 VirtualProtectEx(m_hProc, pfOldFunction , 5, m_dwIdOld, &m_dwIdOld);


}

//-----------------------------------------------------------------------------------------------

//HookRestore(),恢复被截函数的地址
void CHookClass::HookRestore(void)
{

 m_dwIdOld=m_dwIdNew;
 //得到所属进程的句柄
 m_hProc=OpenProcess(PROCESS_ALL_ACCESS,0,m_dwIdOld);
 if (m_hProc == NULL)
 {
  OutputDebugString("恢复被截函数时未找到进程句柄!");
  exit(-1);
 }

 //修改所属进程中被截函数的的前5个字节的属性为可写
 VirtualProtectEx(m_hProc, pfOldFunction , 5, PAGE_READWRITE, &m_dwIdOld);

 //将所属进程中被截函数的前5个字节改为JMP (被截函数的地址)
 
 if( !bIsOSWin9x )
  WriteProcessMemory(m_hProc, pfOldFunction ,m_OldFunctionCode, 5, 0);
 else
  WriteMemoryWithRing0((DWORD)pfOldFunction, m_OldFunctionCode, 5);

 //修改所属进程中的前5个字节的属性为原来的属性
 VirtualProtectEx(m_hProc, pfOldFunction , 5, m_dwIdOld, &m_dwIdOld);


}

 //下面我将利用Ring3   to   Ring0技术实现写共享内存区的代码贴出来共大家参考:

//功能:转到用Ring0级并写指定内存单元  
  //参数:  
  //     dwAddress   -   写要入数据的目的地址  
  //     lpBuf   -   源数据的缓冲区  
  //     nSize   -   源数据的大小  
  //说明:  
  //     本函数将运行级别调整至Ring0级,然后写数据到dwAddress的内存中,并返回  
  //Ring3级.  
  //     本函数只能在9x下使用  
#define   HookIntNo   5 //转到Ring0时要调用的中断号  
void   WriteMemoryWithRing0(DWORD   dwAddress,LPVOID   lpBuf,UINT   nSize)  
{  
 DWORD   OldIntHook; //保存原来的中断入口  
 BYTE   IDTR_1[6]; //保存中断描述符表寄存器    
 _asm  
 {  
  jmp   StartModifyInt  

   //新的中断处理程序  
NewIntHook:  
  push   eax;  
  push   ecx;  
  push   esi;  
  push   edi;  
  mov   esi,edx;  
  mov   edi,ebx;  

NewIntHookLoop:  
  mov   al,[esi];  
  mov   [edi],al;  
  inc   esi;  
  inc   edi;  
  loop   NewIntHookLoop;  

  pop   edi;  
  pop   esi;  
  pop   ecx;  
  pop   eax;  

  iretd  

StartModifyInt:  
  push   eax    

  //获取修改的中断的中断描述符(中断门)地址    
  sidt   IDTR_1    
  mov   eax,dword   ptr   IDTR_1+02h    
  add   eax,HookIntNo*08h+04h    

  cli    
  //保存原先的中断入口地址    
  push   ecx    
  mov   ecx,dword   ptr   [eax]    
  mov   cx,word   ptr   [eax-04h]    
  mov   dword   ptr   OldIntHook,ecx    
  pop   ecx    

  //设置修改的中断入口地址为新的中断处理程序入口地址    
  push   ebx  
  lea   ebx,NewIntHook    
  mov   word   ptr   [eax-04h],bx    
  shr   ebx,10h    
  mov   word   ptr   [eax+02h],bx    
  pop   ebx  

  //执行中断,转到Ring   0(与CIH   病毒原理相似!)    
  push   ebx  
  push   ecx  
  push   edx  
  mov   ebx,dword   ptr   dwAddress //目的地址  
  mov   edx,dword   ptr   lpBuf //源地址  
  mov   ecx,dword   ptr   nSize  
  int   HookIntNo //执行中断,转到Ring0  
  pop   edx  
  pop   ecx  
  pop   ebx  

  //操作结束  
  sti  
  pop   eax  
 }  
}
  
     在Ring0状态下修改系统共享的代码  
    
#define   HookExceptionNo   5  

void   Ring0WriteMemory(void   *   dst,void   *src,int   copySize)  
{  
 BYTE   IDTR_1[6];  
 DWORD   OldExceptionHook;  
 __asm  
 {  
  JMP   __Continue  

Ring0Proc:  

  PUSHAD  

   MOV   AX,30h   //   定义一个系统级别的数据段选择子    

   MOV   BX,DS   //   保存原DS与ES  
   MOV   DX,ES  

   MOV   DS,AX   //   修改DS与ES  
   MOV   ES,AX  

   REP   MOVSB   //   插入指令  

   MOV   DS,BX   //   复原DS与ES  
   MOV   ES,DX  

   POPAD  

   IRETD   //返回  

__Continue:  


  SIDT   FWORD   PTR   IDTR_1   //   修改中断门  
   MOV   EAX,DWORD   PTR   IDTR_1+02h  
   ADD   EAX,HookExceptionNo*08h+04h  
   CLI  


   MOV   ECX,DWORD   PTR   [EAX]   //   保存原异常处理例程入口  
  MOV   CX,WORD   PTR   [EAX-04h]  
  MOV   OldExceptionHook,ECX  

   LEA   EBX,Ring0Proc   //   指定新入口    
   MOV   WORD   PTR   [EAX-04h],BX  
   SHR   EBX,10h  
   MOV   WORD   PTR[EAX+02h],BX  

   PUSHAD   //   配置参数  
   MOV   EDI,dst  
   MOV   ESI,src  
   MOV   ECX,copySize  

   INT   HookExceptionNo   //   激活Ring0代码  
   POPAD  

   MOV   ECX,OldExceptionHook   //   复原入口  
   MOV   WORD   PTR[EAX-04h],CX  
   SHR   ECX,10h  
   MOV   WORD   PTR[EAX+02h],CX  

   STI  
 }    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值