在32位Windows中我们有很多定位SSDT的方法,最直接的就是利用导出符号来找到SSDT。再有就是通过在nt!KeAddSystemServiceTable函数中进行反汇编搜索。可是在64位WINDOWS中这两种方法都行不通。在64位Windows中不在导出SSDT了,同时nt!KeAddSystemServiceTable中也不再出SSDT了(此处说明有误,应该为不出现直接的SSDT地址了,个人水平有限感觉计算太麻烦。)。这样要HOOK SSDT表就出现了第一个问题如何找到它?我想了三种思路。
思路1:
对每种版本的系统确定一个ntoskrnl到SSDT的硬编码偏移。呵呵,这种方法可能比较傻但最简单直接有效。就是维护起来比较非常麻烦,要对每一个版本进单独处理,如果不同补丁版本有变化也要处理。
思路2:
64位WINDOWS中存放着每个服务例程的入口偏移(这个偏移是相对于SSDT的开始地址的)。我取一个一般不被HOOK的服务例程入口偏移,然后从ntoskrnl的开始地址一直搜索到结束来查找这四个字节,然后根据服务例程的索引定位到SSDT的开始位置。可能对不同版本的操作系统其偏移和索引是不同的需要分别进行处理,但是相比第一种思路要通用一些。
思路3:
还是利用反汇编的方法,但是nt!KeAddSystemServiceTable函数中已经找不到直接的SSDT地址了。后来我想能不能映像搜索到SSDT的地址。
kd> dq nt!KeServiceDescriptorTable
fffff800`03eab840  fffff800`03c75b00 00000000`00000000
fffff800`03eab850  00000000`00000191 fffff800`03c7678c
fffff800`03eab860  00000000`00000000 00000000`00000000
fffff800`03eab870  00000000`00000000 00000000`00000000
fffff800`03eab880  fffff800`03c75b00 00000000`00000000
fffff800`03eab890  00000000`00000191 fffff800`03c7678c
fffff800`03eab8a0  fffff960`00111c00 00000000`00000000
fffff800`03eab8b0  00000000`0000033b fffff960`0011391c
kd> lm m nt
start             end                 module name
fffff800`03c03000 fffff800`041e0000   nt         (pdb symbols)
kd> s -q fffff800`03c03000 l600000 fffff800`03eab840
很不幸我没有找到任何相关的信息。呵呵,但是我贼心不是死,相信肯定在某处会有引用的。于是我搜索了一下所有名称中含有Service单词的符号。
kd> x nt!Ki*Service*
fffff800`03c73e40 nt!KiServiceInternal = <no type information>
fffff800`03c7415b nt!KiSystemServiceExit = <no type information>
fffff800`03c73fde nt!KiSystemServiceStart = <no type information>
fffff800`03c76788 nt!KiServiceLimit = <no type information>
fffff800`03c73b00 nt!KiDebugServiceTrap = <no type information>
fffff800`03c74140 nt!KiSystemServiceCopyEnd = <no type information>
fffff800`03c75b00 nt!KiServiceTable = <no type information>
fffff800`03c74037 nt!KiSystemServiceGdiTebAccess = <no type information>
fffff800`03c73ff2 nt!KiSystemServiceRepeat = <no type information>
fffff800`03c740d0 nt!KiSystemServiceCopyStart = <no type information>
fffff800`03c706f0 nt!KiServiceLinkage = <no type information>
fffff800`03c73d40 nt!KiSystemServiceHandler = <no type information>
终于在nt!KiSystemServiceRepeat 中找到SSDT的信息。
nt!KiSystemServiceRepeat:
fffff800`03c73ff2 4c8d1547782300  lea     r10,[nt!KeServiceDescriptorTable (fffff800`03eab840)]
fffff800`03c73ff9 4c8d1d80782300  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff800`03eab880)]
fffff800`03c74000 f7830001000080000000 test dword ptr [rbx+100h],80h
fffff800`03c7400a 4d0f45d3        cmovne  r10,r11
fffff800`03c7400e 423b441710      cmp     eax,dword ptr [rdi+r10+10h]
fffff800`03c74013 0f83e9020000    jae     nt!KiSystemServiceExit+0x1a7 (fffff800`03c74302)
fffff800`03c74019 4e8b1417        mov     r10,qword ptr [rdi+r10]
fffff800`03c7401d 4d631c82        movsxd  r11,dword ptr [r10+rax*4]
但是一个新的问题也同时产生了,nt!KiSystemServiceRepeat并不是系统的一个导出函数。那我怎么找到它呢?后来一想虽然它不导出但应该至少存在一条从外部到它的一个调用路径吧!那我就通过这条路径找到它不就行了。想到此就对它下了个断点看看都是谁会调用它。结果和我想的一样,不过发现我真是一个菜鸟,找到SSDT值太高兴竟没有仔细看它的汇编代码。nt!KiSystemServiceRepeat就是完成根据调用号从SSDT中获得服务例程入口并调用的。那就说每一个ZwXXX类的函数都会调用到它,而Zw类的函数是系统导出的这样我们可以通过任何一个Zw类的函数来找到nt!KiSystemServiceRepeat从而定位到SSDT。于是我手工尝试了一下。下面是尝试的过程。
kd> u nt!ZwClose l20
nt!ZwClose:
fffff800`03c6d640 488bc4          mov     rax,rsp
fffff800`03c6d643 fa              cli
fffff800`03c6d644 4883ec10        sub     rsp,10h
fffff800`03c6d648 50              push    rax
fffff800`03c6d649 9c              pushfq
fffff800`03c6d64a 6a10            push    10h
fffff800`03c6d64c 488d059d300000  lea     rax,[nt!KiServiceLinkage (fffff800`03c706f0)]
fffff800`03c6d653 50              push    rax
fffff800`03c6d654 b80c000000      mov     eax,0Ch
fffff800`03c6d659 e9e2670000      jmp     nt!KiServiceInternal (fffff800`03c73e40)
fffff800`03c6d65e 6690            xchg    ax,ax
在ZwClose中(其它类似)跳转到了nt!KiServiceInternal 我们再跟踪nt!KiServiceInternal 
nt!KiServiceInternal:
fffff800`03c73e40 4883ec08        sub     rsp,8
fffff800`03c73e44 55              push    rbp
fffff800`03c73e45 4881ec58010000  sub     rsp,158h
fffff800`03c73e4c 488dac2480000000 lea     rbp,[rsp+80h]
fffff800`03c73e54 48899dc0000000  mov     qword ptr [rbp+0C0h],rbx
fffff800`03c73e5b 4889bdc8000000  mov     qword ptr [rbp+0C8h],rdi
fffff800`03c73e62 4889b5d0000000  mov     qword ptr [rbp+0D0h],rsi
fffff800`03c73e69 fb              sti
fffff800`03c73e6a 65488b1c2588010000 mov   rbx,qword ptr gs:[188h]
fffff800`03c73e73 0f0d8bd8010000  prefetchw [rbx+1D8h]
fffff800`03c73e7a 0fb6bbf6010000  movzx   edi,byte ptr [rbx+1F6h]
fffff800`03c73e81 40887da8        mov     byte ptr [rbp-58h],dil
fffff800`03c73e85 c683f601000000  mov     byte ptr [rbx+1F6h],0
fffff800`03c73e8c 4c8b93d8010000  mov     r10,qword ptr [rbx+1D8h]
fffff800`03c73e93 4c8995b8000000  mov     qword ptr [rbp+0B8h],r10
fffff800`03c73e9a 4c8d1d3d010000  lea     r11,[nt!KiSystemServiceStart (fffff800`03c73fde)]
fffff800`03c73ea1 41ffe3          jmp     r11
fffff800`03c73ea4 666666666666660f1f840000000000 nop word ptr [rax+rax]
fffff800`03c73eb3 66666666660f1f840000000000 nop word ptr [rax+rax]

在这个函数中又跳转到了nt!KiSystemServiceStart,这里4c8d1d3d010000 这条指令需要参考一下x64汇编中有关Rex.w前缀及Mod r/m寻址方面的知识来解释这个偏移。在这里就是fffff800`03c73ea1+013d就是nt!KiSystemServiceStart入口地址。接下来再从这个地址开始反汇编。
nt!KiSystemServiceStart:
fffff800`03c73fde 4889a3d8010000  mov     qword ptr [rbx+1D8h],rsp
fffff800`03c73fe5 8bf8            mov     edi,eax
fffff800`03c73fe7 c1ef07          shr     edi,7
fffff800`03c73fea 83e720          and     edi,20h
fffff800`03c73fed 25ff0f0000      and     eax,0FFFh
nt!KiSystemServiceRepeat:
fffff800`03c73ff2 4c8d1547782300  lea     r10,[nt!KeServiceDescriptorTable (fffff800`03eab840)]
fffff800`03c73ff9 4c8d1d80782300  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff800`03eab880)]
fffff800`03c74000 f7830001000080000000 test dword ptr [rbx+100h],80h
fffff800`03c7400a 4d0f45d3        cmovne  r10,r11
fffff800`03c7400e 423b441710      cmp     eax,dword ptr [rdi+r10+10h]
fffff800`03c74013 0f83e9020000    jae     nt!KiSystemServiceExit+0x1a7 (fffff800`03c74302)
fffff800`03c74019 4e8b1417        mov     r10,qword ptr [rdi+r10]
fffff800`03c7401d 4d631c82        movsxd  r11,dword ptr [r10+rax*4]
fffff800`03c74021 498bc3          mov     rax,r11
fffff800`03c74024 49c1fb04        sar     r11,4
fffff800`03c74028 4d03d3          add     r10,r11
fffff800`03c7402b 83ff20          cmp     edi,20h
fffff800`03c7402e 7550            jne     nt!KiSystemServiceGdiTebAccess+0x49 (fffff800`03c74080)
fffff800`03c74030 4c8b9bb8000000  mov     r11,qword ptr [rbx+0B8h]
终于找到我们要找到函数了,4c8d1547782300,4c8d1d80782300根据这两条指令我就可以定位到SSDT的位置了。终于拨云见日了。这两条指令都加了REX.W前缀的根据具体字段的意义解释它就可找到SSDT,4c8d1547782300这条指令的64立即数寻址应该是fffff800`03c73ff9+237847这样来扩展,就是RIP+偏移。相类似4c8d1d80782300指令中的立即数应该被扩展成fffff800`03c74000+237880,通过DQ命令查看就是SSDT的内容。
kd> dq fffff800`03c74000+237880
fffff800`03eab880  fffff800`03c75b00 00000000`00000000
fffff800`03eab890  00000000`00000191 fffff800`03c7678c
fffff800`03eab8a0  fffff960`00111c00 00000000`00000000
fffff800`03eab8b0  00000000`0000033b fffff960`0011391c
fffff800`03eab8c0  00000000`7771fdd6 00000000`00000000
fffff800`03eab8d0  fffff800`00a01400 fffff800`00a013b0
fffff800`03eab8e0  00000000`00000002 00000000`00005bdb
fffff800`03eab8f0  00000000`00023f05 00000000`00000000
kd> dq nt!KeServiceDescriptorTableShadow
fffff800`03eab880  fffff800`03c75b00 00000000`00000000
fffff800`03eab890  00000000`00000191 fffff800`03c7678c
fffff800`03eab8a0  fffff960`00111c00 00000000`00000000
fffff800`03eab8b0  00000000`0000033b fffff960`0011391c
fffff800`03eab8c0  00000000`7771fdd6 00000000`00000000
fffff800`03eab8d0  fffff800`00a01400 fffff800`00a013b0
fffff800`03eab8e0  00000000`00000002 00000000`00005bdb
fffff800`03eab8f0  00000000`00023f05 00000000`00000000
两种方法找到位置一样。我这里的输出都针对WIN7 64位系统的调用,通过对2003进行调试发现这样的方法也适用。因为没有暂时没有其它版本操作系统。在其它操作系统上的适用性怎么样就无从知道了。个人推测XP,VISTA也应该差不多但需要事实证明。不过Win7与2003中SSDT表项内容略有不同,虽然都是四个节最后四位是例程的参数个数,但在2003上偏移的计算是SSDT基址+表项值&0xFFFFFFF0,而win7上则变成了SSDT基址+表项值>>4。如果HOOK表项还是要做一个分别对待。我是第一次发帖,大家轻拍啊。上面阐述如有错误请个位大侠多多指教,小弟不胜感激。

  • 标 题:答复
  • 作 者:liangdong
  • 时 间:2010-12-06 23:53:34

转一个老外给的:
Get Win x64 Nt syscall from its number: ln nt!KiServiceTable+((poi(nt!KiServiceTable+4*<syscall nbr>)&0x00000000`ffffffff)>>4) 

Win x64 Win32k syscall: ln win32k!W32pServiceTable+((poi(win32k!W32pServiceTable+4*(<syscall nbr>-1000))&0x00000000`ffffffff)>>4)-10000000

  • 标 题:答复
  • 作 者:半道出家
  • 时 间:2010-12-07 10:16:12

引用:
最初由 lcz发布 查看帖子
...
再有就是通过在nt!KeAddSystemServiceTable函数中进行反汇编搜索。可是在64位WINDOWS中这两种方法都行不通...
KeAddSystemServiceTable不访问SystemServiceTable如何实现Add?下面是Vista64的KeAddSystemServiceTable代码:
PAGE:0000000000753DF0 KeAddSystemServiceTable proc near
PAGE:0000000000753DF0
PAGE:0000000000753DF0 arg_20          = dword ptr  28h
PAGE:0000000000753DF0
PAGE:0000000000753DF0                 mov     eax, [rsp+arg_20]
PAGE:0000000000753DF4                 cmp     eax, 1
PAGE:0000000000753DF7                 ja      short loc_753E65
PAGE:0000000000753DF7
PAGE:0000000000753DF9                 mov     r10, rax
PAGE:0000000000753DFC                 lea     r11, cs:400000h
PAGE:0000000000753E03                 shl     r10, 5
PAGE:0000000000753E07                 cmp     qword ptr [r10+r11+KeServiceDescriptorTable.ServiceTable-400000h], 0
PAGE:0000000000753E10                 jnz     short loc_753E65
PAGE:0000000000753E10
PAGE:0000000000753E12                 cmp     qword ptr [r10+r11+KeServiceDescriptorTableShadow.ServiceTable-400000h], 0
PAGE:0000000000753E1B                 jnz     short loc_753E65
PAGE:0000000000753E1B
PAGE:0000000000753E1D                 cmp     eax, 1
PAGE:0000000000753E20                 mov     [r10+r11+KeServiceDescriptorTableShadow.ServiceTable-400000h], rcx
PAGE:0000000000753E28                 mov     [r10+r11+KeServiceDescriptorTableShadow.ServiceBase-400000h], rdx
PAGE:0000000000753E30                 mov     [r10+r11+KeServiceDescriptorTableShadow.ServiceLimit-400000h], r8d
PAGE:0000000000753E38                 mov     [r10+r11+KeServiceDescriptorTableShadow.ArgumentTable-400000h], r9
PAGE:0000000000753E40                 jz      short loc_753E62
PAGE:0000000000753E40
PAGE:0000000000753E42                 mov     [r10+r11+KeServiceDescriptorTable.ServiceTable-400000h], rcx
PAGE:0000000000753E4A                 mov     [r10+r11+KeServiceDescriptorTable.ServiceBase-400000h], rdx
PAGE:0000000000753E52                 mov     [r10+r11+KeServiceDescriptorTable.ServiceLimit-400000h], r8d
PAGE:0000000000753E5A                 mov     [r10+r11+KeServiceDescriptorTable.ArgumentTable-400000h], r9
PAGE:0000000000753E5A
PAGE:0000000000753E62
PAGE:0000000000753E62 loc_753E62:                             ; CODE XREF: KeAddSystemServiceTable+50
PAGE:0000000000753E62                 mov     al, 1
PAGE:0000000000753E64                 retn
PAGE:0000000000753E64
PAGE:0000000000753E65 ; ---------------------------------------------------------------------------
PAGE:0000000000753E65
PAGE:0000000000753E65 loc_753E65:                             ; CODE XREF: KeAddSystemServiceTable+7
PAGE:0000000000753E65                                         ; KeAddSystemServiceTable+20
PAGE:0000000000753E65                                         ; KeAddSystemServiceTable+2B
PAGE:0000000000753E65                 xor     al, al
PAGE:0000000000753E67                 retn
PAGE:0000000000753E67
PAGE:0000000000753E67 KeAddSystemServiceTable endp

WIN7会如何实现呢?希望楼主能上传一份64位WIN7的NTOSKRNL.EXE。

  • 标 题:我文中的描述确实不对。谢谢,大侠指点。
  • 作 者:lcz
  • 时 间:2010-12-07 10:50:47

小弟汇编能力有限对于
4b898c1a80882a00 mov     qword ptr [r10+r11+2A8880h],rcx
不会解析所以觉得在这个函数里搜索不太方便。我文中的描述确实不对。谢谢,大侠指点。
nt!KeAddSystemServiceTable:
fffff800`03fe5cd0 8b442428        mov     eax,dword ptr [rsp+28h]
fffff800`03fe5cd4 83f801          cmp     eax,1
fffff800`03fe5cd7 776c            ja      nt!KeAddSystemServiceTable+0x75 (fffff800`03fe5d45)
fffff800`03fe5cd9 4c8bd0          mov     r10,rax
fffff800`03fe5cdc 4c8d1d1dd3c1ff  lea     r11,[nt!MmIsSessionAddress <PERF> (nt+0x0) (fffff800`03c03000)]
fffff800`03fe5ce3 49c1e205        shl     r10,5
fffff800`03fe5ce7 4b83bc1a40882a0000 cmp   qword ptr [r10+r11+2A8840h],0
fffff800`03fe5cf0 7553            jne     nt!KeAddSystemServiceTable+0x75 (fffff800`03fe5d45)
fffff800`03fe5cf2 4b83bc1a80882a0000 cmp   qword ptr [r10+r11+2A8880h],0
fffff800`03fe5cfb 7548            jne     nt!KeAddSystemServiceTable+0x75 (fffff800`03fe5d45)
fffff800`03fe5cfd 4b898c1a80882a00 mov     qword ptr [r10+r11+2A8880h],rcx
fffff800`03fe5d05 4b89941a88882a00 mov     qword ptr [r10+r11+2A8888h],rdx
fffff800`03fe5d0d 4789841a90882a00 mov     dword ptr [r10+r11+2A8890h],r8d
fffff800`03fe5d15 4f898c1a98882a00 mov     qword ptr [r10+r11+2A8898h],r9
fffff800`03fe5d1d 83f801          cmp     eax,1
fffff800`03fe5d20 7420            je      nt!KeAddSystemServiceTable+0x72 (fffff800`03fe5d42)
fffff800`03fe5d22 4b898c1a40882a00 mov     qword ptr [r10+r11+2A8840h],rcx
fffff800`03fe5d2a 4b89941a48882a00 mov     qword ptr [r10+r11+2A8848h],rdx
fffff800`03fe5d32 4789841a50882a00 mov     dword ptr [r10+r11+2A8850h],r8d
fffff800`03fe5d3a 4f898c1a58882a00 mov     qword ptr [r10+r11+2A8858h],r9
fffff800`03fe5d42 b001            mov     al,1
fffff800`03fe5d44 c3              ret
fffff800`03fe5d45 32c0            xor     al,al
fffff800`03fe5d47 c3              ret
fffff800`03fe5d48 90              nop
fffff800`03fe5d49 90              nop
fffff800`03fe5d4a 90              nop
fffff800`03fe5d4b 90              nop
fffff800`03fe5d4c 90              nop
fffff800`03fe5d4d 90              nop
fffff800`03fe5d4e 90              nop
fffff800`03fe5d4f 90              nop

上传的附件 ntoskrnl.rar
ntoskrnl00.rar
ntoskrnl01.rar
ntoskrnl1_rev.rar