;filename:shadow_ssdt_hook_2.asm
;made by correy
;QQ:112426112
;Email:leguanyuan at 126 dot com
;HomePage:http://correy.webs.com
;不足之处敬请指点

;顺便说一下编译方式:
;rc me.rc >error.txt ;这个可有可无。
;ml /nologo /c /coff /Zp4 shadow_ssdt_hook_2.asm >>error.txt
;link /nologo /driver /base:0x10000 /align:16 /out:sys.sys /subsystem:native /section:.text,rw /MERGE:.rdata=.text shadow_ssdt_hook_2.obj me.res>>error.txt
;如果想得到调试信息,在ml命令行中加入,/Cp /Zi,在link中加入 /DEBUG /DEBUGTYPE:CV.不过本人,不喜欢这两个参数。很少使用。
;出错信息在error.txt中查看。

.386
.model flat,stdcall
option casemap:none
include ntstatus.inc 
include ntddk.inc 
include ntoskrnl.inc 
includelib ntoskrnl.lib 

.code

GetServiceDescriptorTableShadowAddress proc uses esi edi ebx
;本函数摘自kmdkit。本人加一些注释,及自己的理解。
local dwThreadId:DWORD

  xor ebx, ebx        ; = NULL. Assume ServiceDescriptorTableShadow will be not found

  mov eax, KeServiceDescriptorTable
  mov esi, [eax]

  ; Find KTHREAD.ServiceTable field
  ; For non-GUI threads this field == KeServiceDescriptorTable
  ; and it points to ServiceDescriptorTable
  ; For GUI threads
  ; ServiceDescriptorTableShadow

  invoke KeGetCurrentThread  ;得到KTHREAD的结构。
  mov edi, 200h-4;1;200h-4            ;为什么是这个数呢?换成1,inc edi呢?
  .while edi
    .break .if dword ptr [eax][edi] == esi ;经查资料0x0e0 ServiceTable : Ptr32 Void。
    dec edi;inc edi;dec edi
  .endw

  .if edi != 0
    ; edi = offset to ServiceTable field in KTHREAD structure
    mov dwThreadId, 080h      ;为什么是这个数呢?
    .while dwThreadId < 400h  ;为什么是这个数呢?
      push eax          ; reserve DWORD on stack
      invoke PsLookupThreadByThreadId, dwThreadId, esp
      pop ecx            ; -> ETHREAD/KTHREAD
      .if eax == STATUS_SUCCESS
        push dword ptr [ecx][edi] ;这就是那个表,ssdt或者shadow.
        fastcall ObfDereferenceObject, ecx
        pop eax ;这儿就应该是返回值。
        .if eax != esi ;如果这是一个GUI线程。就返回结束吧!
        
          mov edx, MmSystemRangeStart ;这三行,得到的数是80000000,特殊的可能是c0000000h.
          mov edx, [edx]
          mov edx, [edx]
          
          .if eax > edx    ; some stupid error checking  真是!这里的判断太多余。
            mov ebx, eax
            ;invoke DbgPrint, $CTA0("FindShadowTable: Found in thread with ID: %X\n"), dwThreadId
            .break
          .endif
          
        .endif
      .endif
      add dwThreadId, 4 ;为什么加4呢?
    .endw
  .endif

  mov eax, ebx
  ret

GetServiceDescriptorTableShadowAddress endp

y dd 0
szNtUserFindWindowEx db "NtUserFindWindowEx is called!",0

myhookapi proc x1,x2,x3,x4,x5
;要hook的是NtUserFindWindowEx
;要加啥功能,就在这里设置吧!
;本人只显示一个信息。
invoke DbgPrint,addr szNtUserFindWindowEx

push x5
push x4
push x3
push x2
push x1
call y

ret 
myhookapi endp

szcsrss db "csrss.exe",0

DriverEntry proc pDriverObject: PDRIVER_OBJECT,pRegistryPath: PUNICODE_STRING
local temp:dword
local x:dword

pushad
  
  invoke IoGetCurrentProcess ;其实这段代码还可以再优化。那就交给看官你吧!
  lea eax,[eax+0b8h] ;windwos 7-32下用0b8h,widnows xp-32下用88h
  mov esi,dword ptr [eax]
  .while esi != 0
    lea edi,[esi-0b8h] ;windwos 7-32下用0b8h,widnows xp-32下用88h
    mov x, edi
    lea eax,[edi+16ch] ;windwos 7-32下用16ch,widnows xp-32下用174h 
    invoke _strnicmp,eax, addr szcsrss,9
    .if eax == 0
      .break
    .endif
    mov esi,dword ptr [esi]
  .endw
  invoke KeAttachProcess,x
  
  invoke GetServiceDescriptorTableShadowAddress
  mov eax, [eax+16] 
  add eax,18ch*4 ;要挂钩的函数是:NtUserFindWindowEx,windwos 7-32下用18ch,widnows xp-32下用17ah。
                 ;无法用MmGetSystemRoutineAddress函数获得。
                 ;找不到相关的资料,只能调试反汇编了,但还得有办法。
  mov esi, [eax] 
  mov y, esi
      
  push eax
  cli
  mov eax,cr0
  mov temp,eax
  and eax,0fffeffffh
  mov cr0,eax
  pop eax

  mov dword ptr[eax],offset myhookapi
  
  push eax
  mov  eax,temp
  mov  cr0,eax
  sti  
  pop  eax
  
  invoke KeDetachProcess
  
popad

mov eax,0
ret

DriverEntry endp

end DriverEntry
;made at 2011.06.30
;没有卸载函数,你自己找工具卸载吧!或者手动卸载(下次起效)。

上传的附件 10.rar