我曾经写过一编文章,名字叫"汇编ring3下实现HOOK API",里面详细介绍了汇编ring3下实现HOOK API的几种方法,文章中着重介

绍了介绍了"改写内存地址JMP法"的方法,这也是比较通用的一种方法,让我们再来回顾一下改写内存地址JMP法的具体方法::

  直接跳转,改变API函数的入口或出口的几个字节,使程序跳转到自己的函数,该方法不受程序加壳的限制。这种技术,说起来也不

复杂,就是改变程序流程的技术。在CPU的指令里,有几条指令可以改变程序的流程:JMP,CALL,INT,RET,RETF,IRET等指令。理

论上只要改变API入口和出口的任何机器码,都可以HOOK,下面我就说说常用的改写API入口点的方法:

   
   因为工作在Ring3模式下,我们不能直接修改物理内存,只能一个一个打开修改,但具体的方法又分成好几种,我给大家介绍几种操

作思路:

 <1>首先改写API首字节,要实现原API的功能需要调用API时先还原被修改的字节,然后再调用原API,调用完后再改回来,这样实现有

点麻烦,但最简单,从理论上说有漏HOOK的可能,因为我们先还原了API,如果在这之前程序调用了API,就有可能逃过HOOK的可能!



 (2)把被覆盖的汇编代码保存起来,在替代函数里模拟被被覆盖的功能,然后调用原函数(原地址+被覆盖长度).但这样会产生一个问

题,不同的汇编指令长度是不一样的(比如说我们写入的JMP指令占用5个字节,而我们写入的这5个字节占用的位置不一定正好是一个或

多个完整的指令,有可能需要保存7个字节,才不能打乱程序原有的功能,需要编写一个庞大的判断体系来判断指令长度,网上已经有这

样的汇编程序(Z0MBiE写的LDE32),非常的复杂!


 (3)把被HOOK的函数备份一下,调用时在替代函数里调用备份函数.为了避免麻烦,可以直接备份整个DLL缺点就是太牺牲内存!


 上期我给大家介绍了上面的是第一种方法,最简单但有漏HOOK的可能,今天我们就来说说第3种方法:备份函数法.

 我们来看看具体流程:

1.通过GetModuleInformation取得模块信息,也就是DLL的信息,我们来看看它的参数:
  
 invoke  GetModuleInformation,WProcess,ModuleHwnd,addr ModuleInformation,size MODULEINFO

 <1> WProcess是进程句柄,在本进程可以由GetCurrentProcess返回
 <2> ModuleHwnd是模块句柄,由"invoke GetModuleHandle,DllName"取得
 <3> ModuleInformation是模块结构,提供一个变量用来装载模块信息

         MODULEINFO struct
           lpBaseOfDll dword 0           ;模块的地址
           SizeOfImage dword 0           ;大小
           EntryPoint dword 0            ;入口
         MODULEINFO ends
  <4>MODULEINFO的大小

 2.通过HeapAlloc分配内存块来保存DLL

   invoke  HeapAlloc, hMainHeap , 0 , ModuleInformation.SizeOfImage  ;分配内存块来保存DLL
 
  调用前通过 GetProcessHeap取得 hMainHeap

 3.通过WriteProcessMemory拷贝DLL到分配的内存

       invoke  WriteProcessMemory,WProcess,lpBuffer, \

       ModuleInformation.lpBaseOfDll,ModuleInformation.SizeOfImage,0

 4.计算用到的API在备份DLL中的地址
  
   备份API地址=分配空间地址+原API地址-DLL模块的地址

 5.HOOK API

  这个就不说了,和上期一样,我就不重复了.下面是DLL部分的源码:


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
;           Programmed by hacker0058, nohacks@163.com                      ;
;               Website: http://nohacks.ys168.com                          ;
;                       Blog:http://sina.com.cn.nohacks                         ;
;                       汇编(MASM):进程防杀 v1.0                             ;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;


.486 
.model flat,stdcall 
option casemap:none 
include debug.inc
include windows.inc

include  psapi.inc
include windows.inc 
include kernel32.inc 
includelib kernel32.lib 
include user32.inc 
includelib user32.lib 
includeLib psapi.lib


HOOKAPI struct 
a  byte 0B8h 
PMyapi DWORD 0   
d BYTE 0FFh  
e BYTE 0E0h 
HOOKAPI ends


MODULEINFO struct

lpBaseOfDll dword 0
SizeOfImage dword 0
EntryPoint dword 0

 
MODULEINFO ends


;子程序声明

HookApi proto :DWORD ,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
WriteApi proto :DWORD ,:DWORD,:DWORD,:DWORD
NowOpenProcess proto  :DWORD  ,:DWORD,:DWORD
GetApi proto  :DWORD,:DWORD
BakDll proto  :DWORD,:DWORD

;已初始化数据
.data 
hInstance dd 0
WProcess dd 0


Papi1 DWORD ? 
WritBak1 HOOKAPI <> 
ApiBak1 db 10 dup(?) 
DllName1  db "kernel32.dll",0 
ApiName1  db "OpenProcess",0 


Dllbase1 DWORD ? 
NowDllbase1 DWORD ? 

;Dllbase2 DWORD ? 
;NowDllbase2 DWORD ? 

;未初始化数据

.data? 


hHook dd ? 
hPid dd ?
;hHwnd dd ? 


;程序代码段

.code 


;****************************************************************

;DLL入口点

DllEntry proc hInst:HINSTANCE, reason:DWORD, reserved1:DWORD 
  
 
.if reason==DLL_PROCESS_ATTACH     ;当DLL加载时产生此事件
       push hInst 
       pop hInstance 

  ;invoke GetCommandLine

 ; mov CommandLine,eax                                         ;取程序命令行
  
  
       invoke   GetCurrentProcess                                   ;取进程伪句柄

          mov WProcess ,eax


invoke BakDll,addr DllName1,addr Dllbase1        ;备份"kernel32.dll"


 mov NowDllbase1,eax


 ; invoke BakDll,addr DllName2,addr Dllbase2                   ;备份 "ueer32.dll"

  ;  mov NowDllbase2,eax


invoke HookApi,addr DllName1,addr ApiName1,addr Papi1,addr NowOpenProcess,addr ApiBak1,addr WritBak1   ;HOOK OpenProcess


.endif 

.if  reason==DLL_PROCESS_DETACH 

invoke WriteApi,WProcess,Papi1, addr ApiBak1 ,8               ;还原API

invoke   GetProcessHeap

invoke  HeapFree ,eax,0,NowDllbase1                           ;释放内存


; invoke VirtualFree,NowDllbase1,0,MEM_RELEASE

.endif 

mov  eax,TRUE 
   ret 
DllEntry Endp 


;****************************************************************


GetMsgProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD 
   invoke CallNextHookEx,hHook,nCode,wParam,lParam 
    mov eax,TRUE
    
     ret 
GetMsgProc endp 

;****************************************************************


InstallHook proc dwProcessId:dword 
push dwProcessId

pop hPid 

   invoke SetWindowsHookEx,WH_GETMESSAGE,addr GetMsgProc,hInstance,NULL 
   mov hHook,eax 
   ret 
InstallHook endp 

UninstallHook proc  

   invoke UnhookWindowsHookEx,hHook    
   push eax
       
invoke WriteApi,WProcess,Papi1, addr ApiBak1 ,8               ;还原API

  pop eax 
 ret 
UninstallHook endp 


;*****************************************************************

GetApi proc DllNameAddress:DWORD,ApiNameAddress:DWORD

invoke  GetModuleHandle,DllNameAddress     ;取DLL模块句柄
  
 .if eax==NULL
 
 invoke LoadLibrary ,DllNameAddress    ;加载DLL
 
  .endif
 
invoke GetProcAddress,eax,ApiNameAddress  ;取API地址
  

mov eax,eax
 
ret

GetApi endp

;*********************************下面是核心部分*****************
HookApi proc DllName:dword,ApiName:dword ,Papi:dword , MyApi:dword ,ApiBak:dword ,WritBak:dword 

 LOCAL ApiDz


invoke GetApi,DllName,ApiName                  ;取API地址

  .if eax==0
    
  ret  
  
.endif


 mov ApiDz,eax                               ;下面几行是保存API地址 
mov ebx,Papi
mov [ebx], eax


invoke ReadProcessMemory,WProcess,ApiDz,ApiBak,8,NULL  ;备份原API的前8字节

.if eax==0
  
ret  
  
.endif

mov eax,WritBak

assume eax:ptr HOOKAPI

push MyApi

pop  [eax].PMyapi                 ;要替代API的函数地址
                                 
.if [eax].PMyapi == 0

mov eax,0

ret

.endif
             
invoke WriteApi,WProcess,ApiDz,  WritBak ,size HOOKAPI    ;HOOK API

ret

HookApi endp


WriteApi proc Process:DWORD ,Papi:DWORD,Ptype:DWORD,Psize:DWORD

LOCAL mbi:MEMORY_BASIC_INFORMATION
LOCAL msize:DWORD


;返回页面虚拟信息
invoke VirtualQueryEx,Process, Papi,addr mbi,SIZEOF MEMORY_BASIC_INFORMATION

;修改为可读写模式

invoke VirtualProtectEx,Process, mbi.BaseAddress,8h,PAGE_EXECUTE_READWRITE,addr mbi.Protect

;开始写内存

invoke  WriteProcessMemory,Process, Papi, Ptype,Psize ,NULL

PUSH eax

;改回只读模式

invoke VirtualProtectEx,Process,mbi.BaseAddress,8h,PAGE_EXECUTE_READ,addr mbi.Protect

pop eax


 

ret

WriteApi endp

;*******************************************************************


;替代的API,参数要和原来一样

NowOpenProcess proc  dwDesiredAccess:DWORD  ,bInheritHandle:DWORD  ,dwProcessId:DWORD

LOCAL  NowApiBase
mov eax,hPid
.if   eax==dwProcessId

mov eax,0
ret

 .endif
   
;计算备份DLL中的API地址


mov eax,Papi1
sub eax,Dllbase1
add eax,NowDllbase1
mov NowApiBase,eax


;调用备份DLL中的API


push dwProcessId
push bInheritHandle
push dwDesiredAccess
call NowApiBase
ret

NowOpenProcess endp

BakDll proc  DllName:DWORD,Dllbase:DWORD 

LOCAL ModuleHwnd,hMainHeap,lpBuffer

LOCAL ModuleInformation: MODULEINFO


invoke GetModuleHandle,DllName

mov ModuleHwnd,eax

.if  ModuleHwnd==0

ret

.endif 

 invoke GetModuleInformation,WProcess,ModuleHwnd,addr ModuleInformation,size MODULEINFO
   
     .if   eax ==0
                      
       jmp   UninstallHook
       
         ret
         
     .endif


 ;原DLL的基地址
 mov eax,Dllbase 
 assume eax:ptr 
 push ModuleInformation.lpBaseOfDll
 pop [eax]
 
invoke   GetProcessHeap

mov hMainHeap,eax

 invoke HeapAlloc, hMainHeap , 0 , ModuleInformation.SizeOfImage  ;分配内存块来保存DLL
 
 ;invoke VirtualAlloc, 0,ModuleInformation.SizeOfImage,4096,PAGE_EXECUTE_READWRITE 
 
     mov lpBuffer,eax     
       
       .if lpBuffer==0

        jmp   UninstallHook
 
         ret
  
.endif


;备份DLL


invoke  WriteProcessMemory,WProcess,lpBuffer, ModuleInformation.lpBaseOfDll,ModuleInformation.SizeOfImage,0

     .if eax==0
           jmp   UninstallHook
           ret  
  
    .endif
   
mov eax,lpBuffer
     
 ret

BakDll endp


;*******************************************************************

End DllEntry
文件地址:
http://58.61.33.167/cgi-bin/dl?05625AAC461A20099976CC6B08831C517786FD8B7CF2BD28F1F3BDA108335D93F42388863B8910137742F54BA1BEDE054DB8763C70CEDF82A4DAE5ABD2227AEA461B034BF69F07BE1A71113AB31A3BA56F35F1B5DCBE90D2103E5/counter-log.rar