首页
社区
课程
招聘
[原创]Win8 32位中SSDT Shadow Hook的实现方法
发表于: 2013-12-9 17:31 58661

[原创]Win8 32位中SSDT Shadow Hook的实现方法

2013-12-9 17:31
58661
一、        XP 中SSDT Shadow Hook方法在win8 32中失败
SSDT Shadow hook 不是一个新话题了, 早在 XP系统时就有人对其进行了研究。目前在各大安全技术论坛公布的方法都是基于针对KeAddSystemServiceTable 内核函数的遍历来达到找到SSDT Shadow 表地址的。
这种方法在XP中是可以实现的,因为在XP系统的KeAddSystemServiceTable函数中,SSDT Shadow 地址是明文记录的。但是在WIN8中这种方法却失败了!

我们来看下面反汇编代码。

lkd> u KeAddSystemServiceTable l 40
    nt!KeAddSystemServiceTable:
    805ba589 8bff            mov    edi,edi
    805ba58b 55              push    ebp
    805ba58c 8bec            mov    ebp,esp
    805ba58e 837d1803        cmp    dword ptr [ebp+18h],3
    805ba592 774e            ja      nt!KeAddSystemServiceTable+0x6b (805ba5e2)
    805ba594 8b4518          mov    eax,dword ptr [ebp+18h]
    805ba597 c1e004          shl    eax,4
    805ba59a 83b880a6558000  cmp    dword ptr nt!KeServiceDescriptorTable (8055a680)[eax],0
    805ba5a1 753f            jne    nt!KeAddSystemServiceTable+0x6b (805ba5e2)
    805ba5a3 8d8840a65580    lea    ecx,nt!KeServiceDescriptorTableShadow (8055a640)[eax]          //【注意这里,可以看出这个SSDT Shadow表比SSDT表小40】
    805ba5a9 833900          cmp    dword ptr [ecx],0
    805ba5ac 7534            jne    nt!KeAddSystemServiceTable+0x6b (805ba5e2)
    805ba5ae 837d1801        cmp    dword ptr [ebp+18h],1
    805ba5b2 8b5508          mov    edx,dword ptr [ebp+8]
    805ba5b5 56              push    esi
    805ba5b6 8b7510          mov    esi,dword ptr [ebp+10h]
    805ba5b9 57              push    edi
    805ba5ba 8b7d14          mov    edi,dword ptr [ebp+14h]
    805ba5bd 8911            mov    dword ptr [ecx],edx
    805ba5bf 8b4d0c          mov    ecx,dword ptr [ebp+0Ch]
    805ba5c2 898844a65580    mov    dword ptr nt!KeServiceDescriptorTableShadow+0x4 (8055a644)[eax],ecx
    805ba5c8 89b048a65580    mov    dword ptr nt!KeServiceDescriptorTableShadow+0x8 (8055a648)[eax],esi
    805ba5ce 89b84ca65580    mov    dword ptr nt!KeServiceDescriptorTableShadow+0xc (8055a64c)[eax],edi
    805ba5d4 0f855a3e0300    jne    nt!KeAddSystemServiceTable+0x4d (805ee434)
    805ba5da 5f              pop    edi
    805ba5db b001            mov    al,1
    805ba5dd 5e              pop    esi
    805ba5de 5d              pop    ebp
    805ba5df c21400          ret    14h
    805ba5e2 32c0            xor    al,al
    805ba5e4 ebf8            jmp    nt!KeAddSystemServiceTable+0x6d (805ba5de)
    805ba5e6 90              nop
    805ba5e7 90              nop
    805ba5e8 90              nop
    805ba5e9 90              nop
    805ba5ea 90              nop

我们再来看Win8 系统的KeAddSystemServiceTable函数:
kd> u nt!KeAddSystemServiceTable  l 40
nt!KeAddSystemServiceTable:
819d0690 8bff             mov     edi,edi
819d0692 55              push    ebp
819d0693 8bec            mov     ebp,esp
819d0695 837d1801        cmp     dword ptr [ebp+18h],1
819d0699 7750            ja      nt!KeAddSystemServiceTable+0x5b (819d06eb)
819d069b 8b4d18          mov     ecx,dword ptr [ebp+18h]
819d069e c1e104          shl     ecx,4

//------注意这几句,Win8已经改变了写法。-------------------------------------------------------------
819d06a1 83b900a4878100  cmp     dword ptr nt!KeServiceDescriptorTable (8187a400)[ecx],0
819d06a8 7541            jne     nt!KeAddSystemServiceTable+0x5b (819d06eb)
819d06aa 83b9c0a3878100  cmp     dword ptr nt!KeNumberProcessors+0x209 (8187a3c0)[ecx],0
819d06b1 7538            jne     nt!KeAddSystemServiceTable+0x5b (819d06eb)

//-------XP的写法是-------------------------------------------------------------------------------------------------
    805ba59a 83b880a6558000  cmp    dword ptr nt!KeServiceDescriptorTable (8055a680)[eax],0
    805ba5a1 753f            jne    nt!KeAddSystemServiceTable+0x6b (805ba5e2)
    805ba5a3 8d8840a65580    lea    ecx,nt!KeServiceDescriptorTableShadow (8055a640)[eax]        
    805ba5a9 833900          cmp    dword ptr [ecx],0
    805ba5ac 7534            jne    nt!KeAddSystemServiceTable+0x6b (805ba5e2)
//---------------------------------------------------------------------------------------------------------------------------

819d06b3 837d1801        cmp     dword ptr [ebp+18h],1
819d06b7 8b5508          mov     edx,dword ptr [ebp+8]
819d06ba 8b4514          mov     eax,dword ptr [ebp+14h]
819d06bd 56              push    esi
819d06be 8b750c          mov     esi,dword ptr [ebp+0Ch]
819d06c1 57              push    edi
819d06c2 8b7d10          mov     edi,dword ptr [ebp+10h]
819d06c5 8991c0a38781    mov     dword ptr nt!KeNumberProcessors+0x209 (8187a3c0)[ecx],edx
819d06cb 89b1c4a38781    mov     dword ptr nt!KeNumberProcessors+0x20d (8187a3c4)[ecx],esi
819d06d1 89b9c8a38781    mov     dword ptr nt!KeNumberProcessors+0x211 (8187a3c8)[ecx],edi
819d06d7 8981cca38781    mov     dword ptr nt!KeNumberProcessors+0x215 (8187a3cc)[ecx],eax
819d06dd 0f85cd240d00    jne     nt!PcwCloseInstance+0x4da89 (81aa2bb0)
819d06e3 5f              pop     edi
819d06e4 b001            mov     al,1
819d06e6 5e              pop     esi
819d06e7 5d              pop     ebp
819d06e8 c21400          ret     14h

二、        WIN8中SSDT Shadow定位原理

1.        代码讲解与调试
系统是如何得到或者区分SSDT ,SSDT SHADOW 地址的呢?我们来反汇编KiFastCallEntry看看:
nt!KiFastCallEntry:
815701d0 b923000000      mov     ecx,23h
815701d5 6a30            push    30h
815701d7 0fa1            pop     fs
815701d9 8ed9            mov     ds,cx
815701db 8ec1            mov     es,cx
815701dd 648b0d40000000  mov     ecx,dword ptr fs:[40h]
815701e4 8b6104          mov     esp,dword ptr [ecx+4]
815701e7 6a23            push    23h
815701e9 52              push    edx
815701ea 9c              pushfd
815701eb 6a02            push    2
815701ed 83c208          add     edx,8
815701f0 9d              popfd
815701f1 804c240102      or      byte ptr [esp+1],2
815701f6 6a1b            push    1Bh
815701f8 ff35f81d5f81    push    dword ptr [nt!KeI386FastSystemCallReturn (815f1df8)]  
815701fe 6a00            push    0
81570200 55              push    ebp
81570201 53              push    ebx
81570202 56              push    esi
81570203 57              push    edi
81570204 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]     
8157020b 6a3b            push    3Bh
8157020d 8bb324010000    mov     esi,dword ptr [ebx+124h]   
81570213 ff33            push    dword ptr [ebx]
81570215 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh
8157021b 8b6e20          mov     ebp,dword ptr [esi+20h]
8157021e 83ec4c          sub     esp,4Ch
81570221 c644244801      mov     byte ptr [esp+48h],1
81570226 81ed8c000000    sub     ebp,8Ch
8157022c c6865a01000001  mov     byte ptr [esi+15Ah],1
81570233 3bec            cmp     ebp,esp
81570235 7593            jne     nt!KiFastCallEntry2+0x49 (815701ca)
81570237 c6451302        mov     byte ptr [ebp+13h],2
8157023b 83652c00        and     dword ptr [ebp+2Ch],0
8157023f f64603df        test    byte ptr [esi+3],0DFh
81570243 896e6c          mov     dword ptr [esi+6Ch],ebp
81570246 0f8530feffff    jne     nt!Dr_FastCallDrSave (8157007c)
8157024c 8b5d60          mov     ebx,dword ptr [ebp+60h]
8157024f 8b7d68          mov     edi,dword ptr [ebp+68h]
81570252 89550c          mov     dword ptr [ebp+0Ch],edx                 
81570255 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h
8157025c 895d00          mov     dword ptr [ebp],ebx
8157025f 897d04          mov     dword ptr [ebp+4],edi
81570262 fb              sti
81570263 8bf8            mov     edi,eax
81570265 c1ef08          shr     edi,8
81570268 83e710          and     edi,10h
8157026b 8bcf            mov     ecx,edi
8157026d 037e3c          add     edi,dword ptr [esi+3Ch]                //是KTHREAD中的成员ServiceTable(ds:0023:8ea9e6bc={nt!KeServiceDescriptorTableShadow (816193c0)}),
                                                                         //那么esi就是KTHREAD结构。这是esi=8ea9e680。edi也是_KSERVICE_TABLE_DESCRIPTOR结构体第一个成员地址。
81570270 8bd8            mov     ebx,eax
81570272 25ff0f0000      and     eax,0FFFh
81570277 3b4708          cmp     eax,dword ptr [edi+8]
8157027a 0f8332fdffff    jae     nt!KiBBTUnexpectedRange (8156ffb2)
81570280 83f910          cmp     ecx,10h
81570283 7521            jne     nt!KiFastCallEntry+0xd6 (815702a6)
81570285 8b8ea8000000    mov     ecx,dword ptr [esi+0A8h]
8157028b 33f6            xor     esi,esi
8157028d 0bb1700f0000    or      esi,dword ptr [ecx+0F70h]
81570293 7411            je      nt!KiFastCallEntry+0xd6 (815702a6)
81570295 52              push    edx
81570296 50              push    eax
81570297 6a00            push    0
81570299 6a00            push    0
8157029b 6a00            push    0
8157029d 6a07            push    7
8157029f e8f0911700      call    nt!PsInvokeWin32Callout (816e9494)
815702a4 58              pop     eax                                       //得到了shadow表中对应的函数序列号。
815702a5 5a              pop     edx
815702a6 64ff05b0060000  inc     dword ptr fs:[6B0h]
815702ad 8bf2            mov     esi,edx
815702af 33c9            xor     ecx,ecx
815702b1 8b570c          mov     edx,dword ptr [edi+0Ch]                   //开始计算ssdt shadow函数表地址
815702b4 8b3f            mov     edi,dword ptr [edi]                      //SSDT  shadow基地址。
815702b6 8a0c10          mov     cl,byte ptr [eax+edx]
815702b9 8b1487          mov     edx,dword ptr [edi+eax*4]                 //edi是ssdt shadow基地址,eax是函数号,要调用的SSDT shadow 函数放入到edx中。
815702bc 2be1            sub     esp,ecx
815702be c1e902          shr     ecx,2
815702c1 8bfc            mov     edi,esp
815702c3 3b358c946181    cmp     esi,dword ptr [nt!MmUserProbeAddress (8161948c)]
815702c9 0f8316020000    jae     nt!KiSystemCallExit2+0xa5 (815704e5)
815702cf f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
815702d1 f6456c01        test    byte ptr [ebp+6Ch],1
815702d5 7410            je      nt!KiFastCallEntry+0x117 (815702e7)
815702d7 648b0d24010000  mov     ecx,dword ptr fs:[124h]         
815702de 8b3c24          mov     edi,dword ptr [esp]
815702e1 895964          mov     dword ptr [ecx+64h],ebx
815702e4 897968          mov     dword ptr [ecx+68h],edi
815702e7 8bda            mov     ebx,edx                                  //要调用的ssdt shadow函数放入到ebx中
815702e9 f60548a1618140  test    byte ptr [nt!PerfGlobalGroupMask+0x8 (8161a148)],40h
815702f0 0f954512        setne   byte ptr [ebp+12h]
815702f4 0f856f030000    jne     nt!KiServiceExit2+0x170 (81570669)
815702fa ffd3            call    ebx                                        //调用ssdt shadow服务函数
815702fc f6456c01        test    byte ptr [ebp+6Ch],1
81570300 7434            je      nt!KiFastCallEntry+0x166 (81570336)
81570302 8bf0            mov     esi,eax
81570304 ff1580026181    call    dword ptr [nt!_imp__KeGetCurrentIrql (81610280)]
8157030a 0ac0            or      al,al
8157030c 0f851e030000    jne     nt!KiServiceExit2+0x137 (81570630)
81570312 8bc6            mov     eax,esi
81570314 648b0d24010000  mov     ecx,dword ptr fs:[124h]
8157031b f68166010000ff  test    byte ptr [ecx+166h],0FFh
81570322 0f8526030000    jne     nt!KiServiceExit2+0x155 (8157064e)
81570328 8b913c010000    mov     edx,dword ptr [ecx+13Ch]
8157032e 0bd2            or      edx,edx
81570330 0f8518030000    jne     nt!KiServiceExit2+0x155 (8157064e)
81570336 8be5            mov     esp,ebp
81570338 807d1200        cmp     byte ptr [ebp+12h],0
8157033c 0f8533030000    jne     nt!KiServiceExit2+0x17c (81570675)
81570342 648b0d24010000  mov     ecx,dword ptr fs:[124h]
81570349 8b553c          mov     edx,dword ptr [ebp+3Ch]
8157034c 89516c          mov     dword ptr [ecx+6Ch],edx
nt!KiServiceExit:
8157034f fa              cli
81570350 f6457202        test    byte ptr [ebp+72h],2
81570354 7506            jne     nt!KiServiceExit+0xd (8157035c)
81570356 f6456c01        test    byte ptr [ebp+6Ch],1
8157035a 7468            je      nt!KiServiceExit+0x75 (815703c4)
8157035c 648b1d24010000  mov     ebx,dword ptr fs:[124h]
81570363 f6430201        test    byte ptr [ebx+2],1
81570367 7408            je      nt!KiServiceExit+0x22 (81570371)
81570369 50              push    eax
8157036a 53              push    ebx
8157036b e8e36cfbff      call    nt!KiCopyCounters (81527053)
81570370 58              pop     eax
81570371 c6435600        mov     byte ptr [ebx+56h],0
81570375 80bb8600000000  cmp     byte ptr [ebx+86h],0
8157037c 7446            je      nt!KiServiceExit+0x75 (815703c4)
8157037e 8bdd            mov     ebx,ebp
81570380 894344          mov     dword ptr [ebx+44h],eax
81570383 c743503b000000  mov     dword ptr [ebx+50h],3Bh
8157038a c7433823000000  mov     dword ptr [ebx+38h],23h
81570391 c7433423000000  mov     dword ptr [ebx+34h],23h
81570398 c7433000000000  mov     dword ptr [ebx+30h],0
8157039f b901000000      mov     ecx,1
815703a4 ff157c026181    call    dword ptr [nt!_imp_KfRaiseIrql (8161027c)]
815703aa 50              push    eax
815703ab fb              sti
815703ac 53              push    ebx
815703ad 6a00            push    0
815703af 6a01            push    1
815703b1 e8ffb5ecff      call    nt!KiDeliverApc (8143b9b5)
815703b6 59              pop     ecx
815703b7 ff1578026181    call    dword ptr [nt!_imp_KfLowerIrql (81610278)]
815703bd 8b4344          mov     eax,dword ptr [ebx+44h]
815703c0 fa              cli
815703c1 eb99            jmp     nt!KiServiceExit+0xd (8157035c)
815703c3 90              nop
815703c4 8b54244c        mov     edx,dword ptr [esp+4Ch]
815703c8 64891500000000  mov     dword ptr fs:[0],edx
815703cf 0fb64c2448      movzx   ecx,byte ptr [esp+48h]
815703d4 648b3524010000  mov     esi,dword ptr fs:[124h]
815703db 888e5a010000    mov     byte ptr [esi+15Ah],cl
815703e1 f744242cff23ffff test    dword ptr [esp+2Ch],0FFFF23FFh
815703e9 7571            jne     nt!KiSystemCallExit2+0x1c (8157045c)
815703eb f744247000000200 test    dword ptr [esp+70h],20000h
815703f3 0f85b70b0000    jne     nt!KiExceptionExit+0x124 (81570fb0)
815703f9 66f744246cf9ff  test    word ptr [esp+6Ch],0FFF9h
81570400 0f84ac000000    je      nt!KiSystemCallExit2+0x72 (815704b2)
81570406 66837c246c1b    cmp     word ptr [esp+6Ch],1Bh
8157040c 660fba64246c00  bt      word ptr [esp+6Ch],0
81570413 f5              cmc
81570414 0f8786000000    ja      nt!KiSystemCallExit2+0x60 (815704a0)
8157041a 66837d6c08      cmp     word ptr [ebp+6Ch],8
8157041f 7405            je      nt!KiServiceExit+0xd7 (81570426)
81570421 8d6550          lea     esp,[ebp+50h]
81570424 0fa1            pop     fs
81570426 8d6554          lea     esp,[ebp+54h]
81570429 5f              pop     edi
8157042a 5e              pop     esi
8157042b 5b              pop     ebx
8157042c 5d              pop     ebp
8157042d 83c404          add     esp,4
81570430 f744240401000000 test    dword ptr [esp+4],1
nt!KiSystemCallExitBranch:
81570438 7506            jne     nt!KiSystemCallExit2 (81570440)
8157043a 5a              pop     edx
8157043b 59              pop     ecx
8157043c 9d              popfd
8157043d ffe2            jmp     edx
nt!KiSystemCallExit:
8157043f cf              iretd
nt!KiSystemCallExit2:
81570440 f744240800010000 test    dword ptr [esp+8],100h
81570448 75f5            jne     nt!KiSystemCallExit (8157043f)
8157044a 5a              pop     edx
8157044b 83c404          add     esp,4
8157044e 812424fffdffff  and     dword ptr [esp],0FFFFFDFFh
81570455 9d              popfd
81570456 59              pop     ecx
81570457 fb              sti
81570458 0f35            sysexit
8157045a cf              iretd
8157045b 90              nop
8157045c f7457000000200  test    dword ptr [ebp+70h],20000h
81570463 750d            jne     nt!KiSystemCallExit2+0x32 (81570472)
81570465 f7456c01000000  test    dword ptr [ebp+6Ch],1
8157046c 0f8479ffffff    je      nt!KiServiceExit+0x9c (815703eb)
81570472 33db            xor     ebx,ebx
81570474 8b7518          mov     esi,dword ptr [ebp+18h]
81570477 8b7d1c          mov     edi,dword ptr [ebp+1Ch]
8157047a 0f23fb          mov     dr7,ebx
8157047d 0f23c6          mov     dr0,esi
81570480 8b5d20          mov     ebx,dword ptr [ebp+20h]
81570483 0f23cf          mov     dr1,edi
81570486 0f23d3          mov     dr2,ebx
81570489 8b7524          mov     esi,dword ptr [ebp+24h]
8157048c 8b7d28          mov     edi,dword ptr [ebp+28h]
8157048f 8b5d2c          mov     ebx,dword ptr [ebp+2Ch]
81570492 0f23de          mov     dr3,esi
81570495 0f23f7          mov     dr6,edi
81570498 0f23fb          mov     dr7,ebx
8157049b e94bffffff      jmp     nt!KiServiceExit+0x9c (815703eb)
815704a0 8b442444        mov     eax,dword ptr [esp+44h]
815704a4 83c430          add     esp,30h
815704a7 0fa9            pop     gs
815704a9 07              pop     es
815704aa 1f              pop     ds
815704ab 5a              pop     edx
815704ac 59              pop     ecx
815704ad e96fffffff      jmp     nt!KiServiceExit+0xd2 (81570421)
815704b2 0fb75c2410      movzx   ebx,word ptr [esp+10h]
815704b7 895c246c        mov     dword ptr [esp+6Ch],ebx
815704bb 8b5c2414        mov     ebx,dword ptr [esp+14h]
815704bf 83eb0c          sub     ebx,0Ch
815704c2 895c2464        mov     dword ptr [esp+64h],ebx
815704c6 8b742470        mov     esi,dword ptr [esp+70h]
815704ca 897308          mov     dword ptr [ebx+8],esi
815704cd 8b74246c        mov     esi,dword ptr [esp+6Ch]
815704d1 897304          mov     dword ptr [ebx+4],esi
815704d4 8b742468        mov     esi,dword ptr [esp+68h]
815704d8 8933            mov     dword ptr [ebx],esi
815704da 83c454          add     esp,54h
815704dd 5f              pop     edi
815704de 5e              pop     esi
815704df 5b              pop     ebx
815704e0 5d              pop     ebp
815704e1 8b2424          mov     esp,dword ptr [esp]
815704e4 cf              iretd
815704e5 f6456c01        test    byte ptr [ebp+6Ch],1
815704e9 0f84e0fdffff    je      nt!KiFastCallEntry+0xff (815702cf)
815704ef b8050000c0      mov     eax,0C0000005h
815704f4 e903feffff      jmp     nt!KiFastCallEntry+0x12c (815702fc)
nt!KiServiceExit2:
815704f9 fa              cli
815704fa f6457202        test    byte ptr [ebp+72h],2
815704fe 7506            jne     nt!KiServiceExit2+0xd (81570506)
81570500 f6456c01        test    byte ptr [ebp+6Ch],1
81570504 7446            je      nt!KiServiceExit2+0x53 (8157054c)
81570506 648b1d24010000  mov     ebx,dword ptr fs:[124h]
8157050d f6430201        test    byte ptr [ebx+2],1
81570511 7406            je      nt!KiServiceExit2+0x20 (81570519)
81570513 53              push    ebx
81570514 e83a6bfbff      call    nt!KiCopyCounters (81527053)
81570519 c6435600        mov     byte ptr [ebx+56h],0
8157051d 80bb8600000000  cmp     byte ptr [ebx+86h],0
81570524 7426            je      nt!KiServiceExit2+0x53 (8157054c)
81570526 8bdd            mov     ebx,ebp
81570528 b901000000      mov     ecx,1
8157052d ff157c026181    call    dword ptr [nt!_imp_KfRaiseIrql (8161027c)]
81570533 50              push    eax
81570534 fb              sti
81570535 53              push    ebx
81570536 6a00            push    0
81570538 6a01            push    1
8157053a e876b4ecff      call    nt!KiDeliverApc (8143b9b5)
8157053f 59              pop     ecx
81570540 ff1578026181    call    dword ptr [nt!_imp_KfLowerIrql (81610278)]
81570546 fa              cli
81570547 ebbd            jmp     nt!KiServiceExit2+0xd (81570506)
81570549 8d4900          lea     ecx,[ecx]
8157054c 8b54244c        mov     edx,dword ptr [esp+4Ch]
81570550 64891500000000  mov     dword ptr fs:[0],edx
81570557 0fb64c2448      movzx   ecx,byte ptr [esp+48h]
8157055c 648b3524010000  mov     esi,dword ptr fs:[124h]
81570563 888e5a010000    mov     byte ptr [esi+15Ah],cl
81570569 f744242cff23ffff test    dword ptr [esp+2Ch],0FFFF23FFh
81570571 7541            jne     nt!KiServiceExit2+0xbb (815705b4)
81570573 f744247000000200 test    dword ptr [esp+70h],20000h
8157057b 0f852f0a0000    jne     nt!KiExceptionExit+0x124 (81570fb0)
81570581 66f744246cf9ff  test    word ptr [esp+6Ch],0FFF9h
81570588 7467            je      nt!KiServiceExit2+0xf8 (815705f1)
8157058a 8b54243c        mov     edx,dword ptr [esp+3Ch]
8157058e 8b4c2440        mov     ecx,dword ptr [esp+40h]
81570592 8b442444        mov     eax,dword ptr [esp+44h]
81570596 66837d6c08      cmp     word ptr [ebp+6Ch],8
8157059b 740c            je      nt!KiServiceExit2+0xb0 (815705a9)
8157059d 8d6530          lea     esp,[ebp+30h]
815705a0 0fa9            pop     gs
815705a2 07              pop     es
815705a3 1f              pop     ds
815705a4 8d6550          lea     esp,[ebp+50h]
815705a7 0fa1            pop     fs
815705a9 8d6554          lea     esp,[ebp+54h]
815705ac 5f              pop     edi
815705ad 5e              pop     esi
815705ae 5b              pop     ebx
815705af 5d              pop     ebp
815705b0 83c404          add     esp,4
815705b3 cf              iretd
815705b4 f7457000000200  test    dword ptr [ebp+70h],20000h
815705bb 7509            jne     nt!KiServiceExit2+0xcd (815705c6)
815705bd f7456c01000000  test    dword ptr [ebp+6Ch],1
815705c4 74ad            je      nt!KiServiceExit2+0x7a (81570573)
815705c6 33db            xor     ebx,ebx
815705c8 8b7518          mov     esi,dword ptr [ebp+18h]
815705cb 8b7d1c          mov     edi,dword ptr [ebp+1Ch]
815705ce 0f23fb          mov     dr7,ebx
815705d1 0f23c6          mov     dr0,esi
815705d4 8b5d20          mov     ebx,dword ptr [ebp+20h]
815705d7 0f23cf          mov     dr1,edi
815705da 0f23d3          mov     dr2,ebx
815705dd 8b7524          mov     esi,dword ptr [ebp+24h]
815705e0 8b7d28          mov     edi,dword ptr [ebp+28h]
815705e3 8b5d2c          mov     ebx,dword ptr [ebp+2Ch]
815705e6 0f23de          mov     dr3,esi
815705e9 0f23f7          mov     dr6,edi
815705ec 0f23fb          mov     dr7,ebx
815705ef eb82            jmp     nt!KiServiceExit2+0x7a (81570573)
815705f1 0fb75c2410      movzx   ebx,word ptr [esp+10h]
815705f6 895c246c        mov     dword ptr [esp+6Ch],ebx
815705fa 8b5c2414        mov     ebx,dword ptr [esp+14h]
815705fe 83eb0c          sub     ebx,0Ch
81570601 895c2464        mov     dword ptr [esp+64h],ebx
81570605 8b742470        mov     esi,dword ptr [esp+70h]
81570609 897308          mov     dword ptr [ebx+8],esi
8157060c 8b74246c        mov     esi,dword ptr [esp+6Ch]
81570610 897304          mov     dword ptr [ebx+4],esi
81570613 8b742468        mov     esi,dword ptr [esp+68h]
81570617 8933            mov     dword ptr [ebx],esi
81570619 8b442444        mov     eax,dword ptr [esp+44h]
8157061d 8b54243c        mov     edx,dword ptr [esp+3Ch]
81570621 8b4c2440        mov     ecx,dword ptr [esp+40h]
81570625 83c454          add     esp,54h
81570628 5f              pop     edi
81570629 5e              pop     esi
8157062a 5b              pop     ebx
8157062b 5d              pop     ebp
8157062c 8b2424          mov     esp,dword ptr [esp]
8157062f cf              iretd
81570630 64ff3524000000  push    dword ptr fs:[24h]
81570637 64c6052400000000 mov     byte ptr fs:[24h],0
8157063f fa              cli
81570640 55              push    ebp
81570641 6a00            push    0
81570643 6a00            push    0
81570645 50              push    eax
81570646 53              push    ebx
81570647 6a4a            push    4Ah
81570649 e87ec6f8ff      call    nt!KiBugCheck2 (814fcccc)
8157064e 0fb68166010000  movzx   eax,byte ptr [ecx+166h]
81570655 8b913c010000    mov     edx,dword ptr [ecx+13Ch]
8157065b 55              push    ebp
8157065c 6a00            push    0
8157065e 52              push    edx
8157065f 50              push    eax
81570660 53              push    ebx
81570661 6a01            push    1
81570663 e864c6f8ff      call    nt!KiBugCheck2 (814fcccc)
81570668 c3              ret
81570669 8bcb            mov     ecx,ebx
8157066b e83343ffff      call    nt!PerfInfoLogSysCallEntry (815649a3)
81570670 e985fcffff      jmp     nt!KiFastCallEntry+0x12a (815702fa)
81570675 50              push    eax
81570676 8bc8            mov     ecx,eax
81570678 e8ca42ffff      call    nt!PerfInfoLogSysCallExit (81564947)
8157067d 58              pop     eax
8157067e e9bffcffff      jmp     nt!KiFastCallEntry+0x172 (81570342)

从上面KiFastCallEntry分析可以得出结论 ssdt Shadow 表只有在GUI线程使用时才加入到内存中,当KTHREAD中的成员Win32Thread域由0变成非0,说明这个线程是一个GUI线程。如果是GUI线程KTHREAD中的成员ServiceTable域就指向SSDT Shadow表;反之,如果是非GUI线程KTHREAD中的成员ServiceTable域将执行SSDT表。
_KPROCESS结构中成员ThreadListHead是指向_KTHREAD结构中成员ThreadListEntry链表。通过它可以定位_KTHREAD结构了,就可判断这个线程是否是GUI线程了。
在_EPROCESS结构的第一个成员Pcb域指向_KPROCESS结构;  同样在_ETHREAD结构中第一个成员Tcb域指向_KTHREAD结构。所以得到这些结构地址后,结构体是可以互换的。

三、        根据分析结果,代码实现过程:
typedef struct _SSDT
{
        PVOID ServiceTableBase;         //System Service Dispatch Table 的基地址  
        PVOID ServiceCounterTable;      //包含着 SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。
        PVOID NumberOfServices;         //由 ServiceTableBase 描述的服务的数目。  
        PVOID ParamTableBase;           //包含每个系统服务参数字节数表的基地址-系统服务参数表
}* pSSDT,SSDT;

//切换到带有UI进程的内存空间。否则shadow表将不会出现在内存中。我们使用csrss作为目标进程。
HANDLE GetCsrPid()
{
        HANDLE Process,hObject;
        HANDLE CsrId = (HANDLE)0;
        OBJECT_ATTRIBUTES obj;
        CLIENT_ID cid;
        UCHAR Buff[0x100];
        POBJECT_NAME_INFORMATION ObjName = (PVOID)&Buff;
        PSYSTEM_HANDLE_INFORMATION_EX Handles=NULL;
        ULONG i;
        ULONG nSize;
        NTSTATUS status;
        PEPROCESS pEproc;
        PETHREAD pEthr;
        PKTHREAD pKthr;
        PKPROCESS pKproc;
       
        //得到csrss.exe句柄。
        Handles = GetInfoTable(&nSize);       

        //等于null,返回0
        if(Handles==(PSYSTEM_HANDLE_INFORMATION_EX)0)
        {
                return CsrId;
        }

        for(i = 0; i < Handles->NumberOfHandles; i++)
        {
                if(Handles->Information[i].ObjectTypeNumber == 21)  //Port object  "\\Windows\\ApiPort"
                {
                        InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
                        cid.UniqueProcess = (HANDLE)Handles->Information[i].ProcessID;
                        cid.UniqueThread  = (HANDLE)0;

                        status=PsLookupProcessByProcessId(Handles->Information[i].ProcessID,&pEproc);
                        if(!NT_SUCCESS(status))
                        {
                                KdPrint(("PsLookupProcessByProcessId operation failed!\n"));
                                continue;
                        }

                       
                
                        if(CheckProcessName(pEproc))
                        {
                                CsrId = (HANDLE)Handles->Information[i].ProcessID;
                                KdPrint(("Csrss.exe PID = %d\n", CsrId));              //如果上面得不到CsrssId,这里可以。

                                ObDereferenceObject(pEproc);
                                goto Done;
                        }                       

            ObDereferenceObject(pEproc);                       
                }
        }
       

Done:
    if(Handles!=NULL) ExFreePool(Handles);
        return CsrId;    //返回进程id
}

                //得到csrss.exe的PID。根据进程Pid得到进程的PEPROCESS结构。
                status = PsLookupProcessByProcessId((ULONG)GetCsrPid(), &crsEProc);
                if (!NT_SUCCESS(status))
                {
                        DbgPrint("PsLookupProcessByProcessId() error\n");
                        return ;
                }
                else
                {
                        DbgPrint("csrss.exe PEPROCESS address 0x%8x\n",crsEProc);
                }
                ObDereferenceObject(crsEProc);
               

//根据csrss进程结构,遍历线程得到shadow地址。
ULONG  KeQueryRuntimeProcess (PKPROCESS Process)
{

        KLOCK_QUEUE_HANDLE LockHandle;
        PULONG SSDTShadowAddress=0;
        PLIST_ENTRY NextEntry;
        PKTHREAD Thread;
        ULONG TotalTime;
        PKSPIN_LOCK ProcessLock;
        PLIST_ENTRY  Thread_List_Head;

        ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
        ProcessLock = (PKSPIN_LOCK)((ULONG)Process+0x034);      // ProcessLock   
       
//_EPROCESS结构中的ThreadListHead  成员,指向进程保护的线程列表。
        Thread_List_Head=(PLIST_ENTRY)((ULONG)Process+0x02c);   
        NextEntry = Thread_List_Head->Flink;

       
        while (NextEntry != Thread_List_Head)
        {
       //循环线程列表取出每一个线程_KTHREAD结构体。
                Thread = (PKTHREAD)((ULONG)NextEntry - 0x1d4);   

        //查找每一个线程,看看这个成员是否为0。非0是gui线程表示这个线程是GUI线程。
                if(((ULONG)Thread+0x124)!=0)
                {
          //如果是GUI线程,那么_KTHREAD的ServiceTable成员将指向SSDT SHADOW table地址。
                        SSDTShadowAddress = (PULONG)((ULONG)Thread +0x03c);
                        break;
                }
                NextEntry = NextEntry->Flink;
        }

        return *SSDTShadowAddress;   //返回shadow地址。
}

//取得SSDT Shadow表地址
KeServiceDescriptorTableShadow = (pSSDTShadow)GetSSDTShadowTableAddress(&ModuleID);  
        if(KeServiceDescriptorTableShadow==NULL)
                return NULL;

  //根据_SSDT 结构体,算出目标函数地址,然后HOOK。
        pTempSSDT = & KeServiceDescriptorTableShadow->win32k;
        t_addr=(ULONG)pTempSSDT->ServiceTableBase;
        Module_Adr=(PULONG)(t_addr+ModuleID*4);
        return Module_Adr;

这个Demo目前可以屏蔽 画图, 写字板,计算器窗口弹出
源码附件密码:huihai-it

学驱动安全的朋友关注 驱动培训
http://bbs3.driverdevelop.com/read.php?tid-125833.html

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
免费 5
支持
分享
最新回复 (61)
雪    币: 97
活跃值: (43)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
我就当一把沙发吧,虽然看不懂,但是顶起来吧
2013-12-9 17:43
0
雪    币: 49
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
还没见过win8啥样子了
下个 学习下新系统的HOOK
2013-12-9 17:43
0
雪    币: 2664
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
4
没装过win8系统的飘过...
2013-12-9 17:50
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
5
粗看一下没明白。
win32k.sys因为会话空间的原因直接在非GUI线程下访问可能未在地址空间中被映射到问题是老生常谈了,XP下也得这样处理呀
2013-12-9 19:46
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
但是在使用KeAddSystemServiceTable函数搜索shadow地址在win8中不成功了。
这个方法是全新的,根据系统定位shadow方法,搜索线程来定位shadow。全新方法。
2013-12-9 19:51
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
7
粗看一下没明白。就是取SSDT Shadow的方式不一样。
而且……规范的做法是通过调试符号寻找win32k!W32pServiceTable

win32k.sys因为会话空间的原因直接在非GUI线程下访问可能未在地址空间中被映射到问题是老生常谈了,XP下也得这样处理呀
2013-12-9 19:54
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
我在KiFastCallEntry函数中看系统是,查找KTHREAD!ServiceTable成员得到shadow地址的。
我这个方法模仿了系统的查找方法。
2013-12-9 19:58
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
9
额,一开始看标题还以为win8 32位里有PG还是啥的
2013-12-9 21:27
0
雪    币: 623
活跃值: (40)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
mark
2013-12-9 21:50
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
11
从线程KTHREAD里找服务表的方法早就有了啊,只不过大家一般都用别的方法了,这种用得少而已,XP里也是这么干的,真不是什么新方法。。。。至少四年前在DebugMan就看过了

还有win32k.sys访问的问题,与GUI无关,是Session的原因,只要不是smss.exe或System,其它进程都可以访问的
2013-12-9 22:34
0
雪    币: 213
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
感谢楼主分享好方法!
2013-12-10 08:12
0
雪    币: 293
活跃值: (287)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
粗略的看了下,说了KeServiceDescriptorTableShadow 在win8 x86中位置变了。不过有多少人用win8  x86呢?
2013-12-10 08:44
0
雪    币: 84
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
从GUI ethread的ServiceTable取这个方法不是一直都有??只不过在之前的系统上。。不如搜索出来的好罢了。。ethread的servicetable毕竟是可以被很简单的就改了的。。
2013-12-10 08:50
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
这个是我自己研究的,从来没看见谁公布过。系统取SSDT或者ssdt shadow 基地址 并不是搜索KeAddSystemServiceTable函数。 哈哈
2013-12-10 09:31
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
为什么我在同一个session下,换一个带GUI的线程就可以在内存空间中访问到Win32k?
看来session不是必要条件,带GUI的进程,线程才是必要条件。
系统在查找Shadow时,也是先看KTHREAD的 Win32Thread成员,确定其是否是gui线程。然后才取得ServiceTable成员。
非GUI线程的Win32Thread成员是0,当然ServiceTable指向的是SSDT,而非Shadow。   这个可以请各位自行验证。
2013-12-10 09:37
0
雪    币: 458
活跃值: (306)
能力值: ( LV12,RANK:400 )
在线值:
发帖
回帖
粉丝
17
顶大牛
2013-12-10 10:45
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
18
这个我早就验证过了,不然不会随便说这些~
你确定你切换进程之前不是在System进程里? 要不你切换到csrss看看? 切换到lsass看看? 或者随便哪个你认为没有GUI的看看? 看到底能不能访问?
2013-12-10 11:54
0
雪    币: 225
活跃值: (134)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
19
我以前也在这方面有疑惑,能详细介绍一下Session吗
2013-12-10 12:01
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
20
另外你说的系统取服务表的过程,跟GUI不GUI的只不过是巧合而已吧,因为System和smss这两个Session之外的进程根本不会调用Shadow表里的服务,而其它进程的线程才区分这两种情况,但是那都是在Session内的进程~  另外,我觉得系统完全可以不必要在KTHREAD里区分SSDT和SSDT Shadow,统一换成SSDT Shadow就可以了,反正调用的时候有索引可以判断来使用哪张表~
2013-12-10 12:02
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
21
刚又看了下KiFastCallEntry的代码,证实了我刚才的说法~

一、系统创建线程时,默认Thread->ServiceTable填充的都是KeServiceDescriptorTable,具体可参考KeInitThread函数
二、在KeFastCallEntry中,系统根本不是在判断这个线程是不是GUI线程,它只是判断这个服务的Index是不是超出了SSDT表的范围而已,因为SSDT Shadow的服务项数比SSDT多,所以如果发现服务的Index超出了SSDT表的范围,就认为这是一个SSDT Shadow的调用,然后调用PsConvertToGuiThread把Thread->ServiceTable切换为KeServiceDescriptorTableShadow,另外就是切换一下内核栈,使线程可以使用更大的内核栈空间,就这两个动作~

所以,理论上来讲,如果系统创建线程的时候就把Thread->ServiceTable填充为KeServiceDescriptorTableShadow并且使用更大的内核栈,完全不会有问题,因为GUI线程和非GUI线程需要的条件都满足了~  只不过这样做会消耗更大的内核空间,所以才做了GUI线程和非GUI线程的区分,只给GUI线程以必要的资源,但是对于访问win32k.sys这个,GUI和非GUI并没有不同~~

所以,你首先确认下win32k.sys的访问问题,到底是除smss和System外的所有进程都可以访问,还是只有GUI进程可以访问,这个不难吧?
2013-12-10 12:35
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
22
发现几篇不错的文章,关于Session Space的

http://www.cnblogs.com/kkindof/archive/2012/07/01/2571538.html

http://www.cnblogs.com/kkindof/archive/2012/07/01/2571782.html

http://www.cnblogs.com/kkindof/archive/2012/07/01/2571799.html

http://www.blogbus.com/debug-sai-logs/109178332.html

初始情况下,smss不属于任何session,然后它自己创建了一个Session,然后创建csrss和winlogon继承了该Session,之后加载win32k.sys,最后又调用NtSetSystemInformation从Session中Detach了,而win32k.sys加载的位置是在MmSessionSpace范围内的(32位系统的SessionSpace范围是bc000000到c0000000,这就是为什么win32k.sys的默认基址是bf800000),所以从Session中脱离之后就访问不到SessionSpace范围内的内存了~~

由于SmpStartCsr是在SmpApiLoop中被调用的,所以从理论上分析,smss继续创建一个新的Session的时候(比如另一个用户登录到系统),依然会重复“创建Session”->"启动csrss、winlogon和加载win32k.sys"->“从Session中脱离”这个动作,只不过win32k.sys也是有加载记数的,后面再加载和卸载的时候只会改变记数(这是MmLoadSystemImage内部处理的),从Session中脱离的时候就会把SessionSpace对应的PTE清零,所以访问不到win32k了~

以下是xp的smss.exe中的部分代码:

int __stdcall SmpStartCsr(int a1, int a2, int a3)
{
  signed int v3; // ebx@1
  int v4; // esi@1
  int v5; // ecx@1
  int v6; // eax@1
  int v8; // eax@3
  int v9; // edi@3
  __int16 *v10; // eax@5
  int v11; // eax@7
  CHAR *v12; // [sp-Ch] [bp-34h]@4
  int v13; // [sp-8h] [bp-30h]@4
  char v14; // [sp+8h] [bp-20h]@3
  __int16 v15; // [sp+10h] [bp-18h]@1
  __int16 v16; // [sp+12h] [bp-16h]@1
  int v17; // [sp+14h] [bp-14h]@1
  int v18; // [sp+18h] [bp-10h]@12
  int v19; // [sp+1Ch] [bp-Ch]@3
  int v20; // [sp+20h] [bp-8h]@7
  int v21; // [sp+24h] [bp-4h]@7

  v4 = a1;
  v5 = *(_DWORD *)(a1 + 32);
  v3 = 0;
  v15 = *(_WORD *)(a1 + 36);
  v16 = v15;
  v6 = a1 + 40;
  a1 = v5;
  v17 = v6;
  if ( !v5 )
  {
    *(_DWORD *)(v4 + 300) = SmpWindowsSubSysProcessId;
    *(_DWORD *)(v4 + 296) = SmpInitialCommandProcessId;
    return 0;
  }
  v19 = 0;
 //下面这个函数启动csrss等进程和加载win32k.sys
  [COLOR="Red"]v8 = SmpLoadSubSystemsForMuSession(&a1, (int)&v19, (int)&v14);[/COLOR]
  v9 = v8;
  if ( v8 )
  {
    v13 = v8;
    v12 = "SMSS: SmpStartCsr, SmpLoadSubSystemsForMuSession Failed. Status=%x\n";
  }
  else
  {
    v10 = (__int16 *)&v14;
    if ( v15 )
      v10 = &v15;
    v11 = SmpExecuteInitialCommand(a1, v10, &v21, &v20);
    v9 = v11;
    if ( v11 >= 0 )
    {
      NtClose(v21);
      *(_DWORD *)(v4 + 296) = v20;
      *(_DWORD *)(v4 + 300) = v19;
      *(_DWORD *)(v4 + 32) = a1;
      goto LABEL_11;
    }
    v13 = v11;
    v3 = 1;
    v12 = "SMSS: SmpStartCsr, SmpExecuteInitialCommand Failed. Status=%x\n";
  }
  DbgPrint(v12, v13);
LABEL_11:
  if ( AttachedSessionId != -1 )
  {
    [COLOR="red"]if ( SmpAcquirePrivilege(10, &v18) >= 0 )
    {
      if ( NtSetSystemInformation(48, &AttachedSessionId, 4) >= 0 )
        AttachedSessionId = -1;
      SmpReleasePrivilege(v18);
    }[/COLOR]
  }
  if ( v3 == 1 )
    SmpTerminateCSR(a1);
  return v9;
}

2013-12-10 12:53
0
雪    币: 155
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
你这个方法,至少6年前debugman上就公布了,我记得当时公布了大概有3~4种方法取shadow table。

你这个方法也不是什么大不了的东西,Ida看一下交叉引用3秒内就能想出来的。

另外,代码搜索法也不是不行,按版本换个特征码就可以了,更简单
2013-12-10 13:45
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
首先你说的那个帖子我没有看到过。你可以找出来看看它是怎么讲得?
2013-12-10 15:08
0
雪    币: 101
活跃值: (82)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
25
win8 32不会PG吗?我还以为win7 64之后都不能再用ssdt了。
2013-12-10 15:13
0
游客
登录 | 注册 方可回帖
返回
//