安全中国首页 > 文章中心 > 黑客编程
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

汇编ring3下实现HOOK API

更新时间:2007-12-29 0:31:38
责任编辑:阿loosen
热 点:
InstallHook proc
   
    invoke SetWindowsHookEx,WH_GETMESSAGE,addr GetMsgProc,hInstance,NULL 
    mov hHook,eax 
    ret 
InstallHook endp 

UninstallHook proc 
    invoke UnhookWindowsHookEx,hHook 
   invoke WriteApi,WProcess,Papi1, addr ApiBak1 ,8
  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


;============================下面是核心部分=========================


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,参数要和原来一样

MyAPI proc  bs:DWORD  ,dwReserved:DWORD                      

invoke MessageBox, NULL,  CommandLine, addr mdb, MB_YESNO      ;弹出信息框选择是否阻止

.if eax==7                                                   ;如果选择否

 invoke WriteApi,WProcess,Papi1, addr ApiBak1 ,8              ;先还原API
 
 invoke ExitWindowsEx,bs,dwReserved                           ;再调用API
 
 invoke WriteApi,WProcess,Papi1, addr hacker ,sizeof HOOKAPI  ;调用完后再改回来
  
.endif

mov eax,TRUE 
ret

MyAPI endp

End DllEntry


===============================hookdll.def=============================

LIBRARY hookdll
EXPORTS InstallHook
EXPORTS UninstallHook


=====[ 4.2. 分析 ]==============================================

HOOKAPI struct 
a  byte ? 
PMyapi DWORD ?   
d BYTE ?  
e BYTE ?
HOOKAPI ends


   为了便于理解和使用,我定义了一个结构:这个结构有4个成员,第一个成员a,是个字节型,我用来放

0B8h(mov eax),PMyapi一个整数型,用来放我们的替代API函数的地址(0X000),第3个和第4个成员我分别

用来放JMP和EAX(jmp eax)那么连起来就是 mov,0X0000 ; jmp eax  


 .if reason==DLL_PROCESS_ATTACH     
        push hInst 
        pop hInstance 

invoke GetCommandLine   
mov CommandLine,eax                                         

;初始化

mov hacker.a,0B8h     ;mov eax,
;mov hacker.d PMyapi  ;0x0000
mov hacker.d,0FFh     ;jmp 
mov hacker.e, 0E0h    ;eax


invoke   GetCurrentProcess                                   

 mov WProcess ,eax


  当DLL加载时,我们先保存模块句柄,读取程序命令行,然后初始化HOOKAPI结构,写入我们要写到内存的

指令(PMyapi以后写入)并调用GetCurrentProcess取出进程伪句柄方便以后写内存.

invoke GetApi,addr DllName1,addr ApiName1                    
  
 mov Papi1,eax                                               

invoke ReadProcessMemory,WProcess,Papi1,addr ApiBak1,8,NULL  
 
mov hacker.PMyapi,offset MyAPI   ;0x0000   

invoke WriteApi,WProcess,Papi1, addr hacker ,size HOOKAPI    ;HOOK API


  接下来用子程GetApi取出要挂勾API的入口点,并用ReadProcessMemory读出入口点8字节备份之,写入
PMyapi调用子程WriteApi改写API的入口点,这个子程我不准备详细说了,它非常的简单,无非就是几个

API的调用.它的核心就是通过WriteProcessMemory改写内存.

.if  reason==DLL_PROCESS_DETACH 

invoke WriteApi,WProcess,Papi1, addr ApiBak1 ,8               

.endif 

 mov  eax,TRUE 
    ret 

   如果这个DLL被卸载了,那么那个在DLL里的替代函数(MyAPI)将是无效的,如果这个时候程序再调用这

个API,将出现非法操作,因此在DLL卸载前,我们必须还原API.

   总结一下,现在只要程序加载这个DLL,这个程序的ExitWindowsEx就会被我们勾住,接下来要怎样才能

让所有的程序都加载这个DLL呢?这就需要安装全局勾子:

  InstallHook proc
   
      invoke SetWindowsHookEx,WH_GETMESSAGE,addr GetMsgProc,hInstance,NULL 
    
      invoke WriteApi,WProcess,Papi1, addr hacker ,sizeof HOOKAPI

      mov hHook,eax 
     ret 
  InstallHook endp 

   通过SetWindowsHookEx安装勾子,最后一个参数可以决定该钩子是局部的还是系统范围的。如果该值

为NULL,那么该钩子将被解释成系统范围内的,那它就可以监控所有的进程及它们的线程。

如果该函数调用成功的话,将在eax中返回钩子的句柄,否则返回NULL。我们必须保存该句柄,因为后

面我们还要它来卸载钩子,可以看出,我们创建的Hook类型是WH_CALLWNDPROC类型,该类型的Hook在进程

与系统一通信时就会被加载到进程空间,从而调用dll的初始化函数完成真正的Hook,值得一提的是:因

为要调用SetWindowsHookEx来安装钩子,我们GUI程序的这个DLL不会被

UnhookWidowHookEx卸载,也就只有一次DLL_PROCESS_ATTACH事件,因此这里再要

HOOK API一次!

我们回头来看看钩子回调函数:

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

   可以看到这里只是调用CallNextHookEx将消息交给Hook链中下一个环节处理,因为这里API函数
SetWindowsHookEx的唯一作用就是让进程加载我们的dll。

  UninstallHook proc 
     invoke UnhookWindowsHookEx,hHook 
     invoke WriteApi,WProcess,Papi1, addr ApiBak1 ,8
   ret 
  UninstallHook endp 

要卸载一个钩子时调用UnhookWidowHookEx函数,该函数仅有一个参数,就是欲卸载的钩子的句柄。钩

子卸载后我们也要还原我们GUI程序的API.

  LIBRARY hookdll
  EXPORTS InstallHook
  EXPORTS UninstallHook

   我们公开DLL里的InstallHook和UninstallHook函数,方便程序调用,这样我们只要在另外的程序中调

用InstallHook便可安装全局勾子,勾住所有程序中的API:ExitWindowsEx,执行我们自定的子程!

如果不需要了,可以调用UninstallHook卸载全局勾子.

   请注意:对于远程钩子,钩子函数必须放到DLL中,它们将从DLL中映射到其它的进程空间中去。当

WINDOWS映射DLL到其它的进程空间中去时,不会把数据段也进行映射。简言之,所有的进程仅共享DLL

的代码,至于数据段,每一个进程都将有其单独的拷贝。这是一个很容易被忽视的问题。您可能想当然

的以为,在DLL中保存的值可以在所有映射该DLL的进程之间共享。在通常情况下,由于每一个映射该

DLL的进程都有自己的数据段,所以在大多数的情况下您的程序运行得都不错。但是钩子函数却不是如

此。对于钩子函数来说,要求DLL的数据段对所有的进程也必须相同。这样您就必须把数据段设成共享

的:

 一般来说, 目标文件有三个段, 分别是 text/data/bss 段.

.text 段放置代码, 是只读且可运行段 

.data 段放置静态数据, 这些数据会被放置入 exe 文件. 这个段是可读写, 但是不能运行的. 

.bss 段放置动态数据, 这些数据不被放入 exe 文件, 在exe文件被加载入内存后才分配的空间.

你可以通过在链接开关中指定段的属性来实现:

/SECTION:name,[E][R][W][S][D][K][L][P][X]

其中S表示共享,已初期化的段名是.data,未初始化的段名是.bss。假如您想要写一个包含钩子函数的

DLL,而且想使它的未初始化的数据段在所有进程间共享,您必须这么做:
 
link /section:.bss[S]  /DLL  /SUBSYSTEM:WINDOWS ..........

否则,您的全局勾子将不能正常工作!

=====[ 5. 结束语 ]================================================

    我欢迎任何人提出更多的这里没有提到的挂钩方法,我肯定那会有很多。同样欢迎补充我介绍得不

是很详细的方法。也可以把我懒得写的其它方法完成,把源代码发给我。这篇文档的目的是演示挂钩技

术的细节,我希望我做到了。
    
============================[ End ]========================

    水平有限,欢迎大家指出错漏之处。QQ:23453161 Email:kker.cn@163.com 

    例子源程序(MASM+RadASM和Windows XP2系统下编译通过):

上一页 1 2 

 
相关文章
一日一文章
 
一日一软件
一日一动画