首页
论坛
课程
招聘
[原创]汇编ring3下实现HOOK API续之备份函数法
2007-5-11 17:07 8696

[原创]汇编ring3下实现HOOK API续之备份函数法

2007-5-11 17:07
8696
标 题: 汇编ring3下实现HOOK API续之备份函数法
作 者: 非安全
时 间: 2007-05-11,17:20
链 接: http://bbs.pediy.com/showthread.php?t=308009

汇编ring3下实现HOOK API续之备份函数法

【文章标题】汇编ring3下实现HOOK API续之备份函数法
【文章作者】nohacks(非安全,hacker0058)
【作者主页】nohacks.ys168.com
【文章出处】看雪论坛(bbs.pediy.com)

    我曾经写过一编文章,名字叫"汇编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

代码里面已经写的很详细了,我就不多说了,希望对大家有帮助!

来源: 看雪论坛

参考文章:汇编ring3下实现HOOK API

[注意] 欢迎加入看雪团队!base上海,招聘安全工程师、逆向工程师多个坑位等你投递!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (13)
雪    币: 235
活跃值: 活跃值 (350)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
4st0ne 活跃值 4 2007-5-11 17:19
2
0
第一个来支持
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bdw0212 活跃值 2007-5-11 17:28
3
0
我要好好补补汇编呀  我目前只能在ring3下hook OpenProcess来实现防杀,并且那个RELEASE还报木马,晕   我来好好学习学习;)
雪    币: 235
活跃值: 活跃值 (350)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
4st0ne 活跃值 4 2007-5-11 17:34
4
0
在XP,VISTA下均测试失败.
vista下HOOK以后,无法打开任务管理器,任务管理器出错.
xp_sp2_En下Hook以后,尝试打开任务管理失败,explorer一直重启,unhook以后恢复正常.
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2007-5-11 17:38
5
0
啊,我的是XP+SP2的,可能是 HeapAlloc的问题

换VirtualAlloc试下
雪    币: 655
活跃值: 活跃值 (57)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
elance 活跃值 6 2007-5-11 17:43
6
0
没来的及测试,不过还是先要支持一下!
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2007-5-11 17:52
7
0
请大家帮忙测试一下,谢谢大家的支持!
雪    币: 211
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
NaX 活跃值 2007-5-11 18:30
8
0
只对任务管理器有效
这个例子用来说明HOOK API的方法道理还不错,但是防杀就差远了。ring0都很难防 何况ring3?
随便就能让上面的例子失效
1,不要GUI 钩子dll就进入不了
2,防全局钩子
3,我的全局钩子进入你的程序然后ExitProcess,呵呵
4,TerminateThread,如天网,防了NtOpenProcess,却忘了TerminateThread一样可以最终把进程关闭,唉高手都这么失策
5,调用ntdll的ZwOpenProcess
6,呵呵,最神奇 OpenProcess(PID+1,...)
....
雪    币: 379
活跃值: 活跃值 (22)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
toetoe 活跃值 2007-5-11 18:43
9
0
好文章!

值得学习一下!
雪    币: 347
活跃值: 活跃值 (11)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
xPLK 活跃值 3 2007-5-11 20:27
10
0
不错
8楼分析得很好。。
学习了
雪    币: 578
活跃值: 活跃值 (31)
能力值: ( LV9,RANK:780 )
在线值:
发帖
回帖
粉丝
非安全 活跃值 17 2007-5-11 21:00
11
0
恩,只能做技术探讨,实用就差了,呵呵
雪    币: 205
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
scship 活跃值 2007-5-12 17:42
12
0
飞过来支持一下
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
nuke 活跃值 2007-5-15 04:16
13
0
支持非安全大侠,拜读了您的大作受益不少,网站也很个性,HOHO~

我在枚举控制系统中钩子的时候碰到些问题,
之前看过1块3大侠用的是Ring0读系统中的HOOK链结构,
这个结构的THREADINFO地址相对HOOK的基地址偏移与系统有关。

小弟本来想用HOOKAPI的方法HOOK住建立钩子的相关函数,可以HOOK住一部分,
但是HOOKAPI的动态修改函数入口方法通过设置钩子将DLL注入进程空间来修改API的入口,
有点小问题是只有当系统与相关进程有钩子相关消息交互时钩子才被加载,
一个只有实例没有消息的进程钩子HOOK不被加载,这就漏掉一些API的拦截。
对每个进程手动CreateRemoteThread注入可能不够彻底,毕竟一些以线程状态调用的API无法拦截。

看来还是ring0下的inline hook更彻底些,
现在只了解些皮毛,再学习下搞一搞~
雪    币: 2624
活跃值: 活跃值 (574)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
kagayaki 活跃值 2007-5-26 02:27
14
0
学习了!!!
游客
登录 | 注册 方可回帖
返回