首页
论坛
课程
招聘
[原创]另类HookShadow
2011-3-22 04:21 6654

[原创]另类HookShadow

2011-3-22 04:21
6654
凌晨3点多刚加完班,来看雪看看,随便写篇文章给和我一样菜的菜鸟们
不知道取什么标题,乱取一个,可能有些夸张啦,大牛们别取笑就好,这个只为了
学习目的方法蛮简单的,HOOK SSDT和 SSDTSHADOW 这几年大牛们都玩烂啦,没什么必要讲的,本文章只当是学习中留个笔记而已,主要是想说下系统调用原理吧。
       方法是HOOK某个函数吧,又是HOOK,关键函数PsConvertToGuiThread 这个函数简单说下当线程系统调用的时候会检测系统调用号,如果超出了SSDT的范围,但是又是SSDTSHADOW范围内的就会调用这个函数.小提示(win32k.sys不是常在内存的,如果不是GUI线程,shadow ssdt地址无效),这个函数负责扩充系统堆栈,还要将当前线程的对象结构中的KTHREAD->ServiceTable(+0xe0的位置)指向SSDTSHADOW表一般到了这步就基本可以说明当前线程就是GUI线程啦。其实还可以从这个表得到SSDT表,但是不是今天的重点,我们先来看一段KiFastCallEntry函数调用先
8054257d 8bb324010000    mov     esi,dword ptr [ebx+124h] //获得CurrentThread
80542583 ff33            push    dword ptr [ebx]
80542585 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh
8054258b 8b6e18          mov     ebp,dword ptr [esi+18h]
8054258e 6a01            push    1
80542590 83ec48          sub     esp,48h
80542593 81ed9c020000    sub     ebp,29Ch
80542599 c6864001000001  mov     byte ptr [esi+140h],1
805425a0 3bec            cmp     ebp,esp
805425a2 758d            jne     nt!KiFastCallEntry2+0x49 (80542531)
805425a4 83652c00        and     dword ptr [ebp+2Ch],0
805425a8 f6462cff        test    byte ptr [esi+2Ch],0FFh
805425ac 89ae34010000    mov     dword ptr [esi+134h],ebp
805425b2 0f8538feffff    jne     nt!Dr_FastCallDrSave (805423f0)
805425b8 8b5d60          mov     ebx,dword ptr [ebp+60h]
805425bb 8b7d68          mov     edi,dword ptr [ebp+68h]
805425be 89550c          mov     dword ptr [ebp+0Ch],edx
805425c1 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h
805425c8 895d00          mov     dword ptr [ebp],ebx
805425cb 897d04          mov     dword ptr [ebp+4],edi
805425ce fb              sti
805425cf 8bf8            mov     edi,eax //eax=SSDTindex
805425d1 c1ef08          shr     edi,8  //除以256
805425d4 83e730          and     edi,30h //要就是0 要就是0X10为了判断是SSDTSHADOW还是SSDT
805425d7 8bcf            mov     ecx,edi
805425d9 03bee0000000    add     edi,dword ptr [esi+0E0h] //通过esi=KTHREAD->ServiceTable获得
当前线程使用的ServiceTable;
805425df 8bd8            mov     ebx,eax //SSDTID
805425e1 25ff0f0000      and     eax,0FFFh
805425e6 3b4708          cmp     eax,dword ptr [edi+8]
805425e9 0f8333fdffff    jae     nt!KiBBTUnexpectedRange (80542322)
/*
上面是比较系统调用号 就是调用PsConvertToGuiThread切换表啦,从0X80542322这里就可以得到
PsConvertToGuiThread的地址,通过内存搜索很容易得到的
这个函数的内部是:
  nt!KiBBTUnexpectedRange:
8053e332 83f910          cmp     ecx,10h
8053e335 7539            jne     nt!KiBBTUnexpectedRange+0x3e (8053e370)
8053e337 52              push    edx
8053e338 53              push    ebx//这个就是系统调用号啦
8053e339 e8e2530800      call    nt!PsConvertToGuiThread (805c3720)//我们要用的函数地址8053e33e+853E2=805c3720
8053e33e 0bc0            or      eax,eax
8053e340 58              pop     eax
8053e341 5a              pop     edx
8053e342 8bec            mov     ebp,esp
8053e344 89ae34010000    mov     dword ptr [esi+134h],ebp
8053e34a 0f847d020000    je      nt!KiFastCallEntry+0x8d (8053e5cd)
8053e350 8d15703f5580    lea     edx,[nt!KeServiceDescriptorTableShadow+0x10 (80553f70)]
8053e356 8b4a08          mov     ecx,dword ptr [edx+8]
8053e359 8b12            mov     edx,dword ptr [edx]
8053e35b 8d148a          lea     edx,[edx+ecx*4]
8053e35e 25ff0f0000      and     eax,0FFFh
8053e363 03d0            add     edx,eax
8053e365 0fbe02          movsx   eax,byte ptr [edx]
8053e368 0bc0            or      eax,eax
8053e36a 0f8eca020000    jle     nt!KiFastCallEntry+0xfa (8053e63a)
8053e370 b81c0000c0      mov     eax,0C000001Ch
8053e375 e9c0020000      jmp     nt!KiFastCallEntry+0xfa (8053e63a)
8053e37a 8bff            mov     edi,edi

*/

805425ef 83f910          cmp     ecx,10h //这里判断是SSDT还是SSDTSHADOW
805425f2 751b            jne     nt!KiFastCallEntry+0xcf (8054260f)
805425f4 648b0d18000000  mov     ecx,dword ptr fs:[18h]
805425fb 33db            xor     ebx,ebx
805425fd 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]
80542603 740a            je      nt!KiFastCallEntry+0xcf (8054260f)
80542605 52              push    edx
80542606 50              push    eax
80542607 ff1548d75580    call    dword ptr [nt!KeGdiFlushUserBatch (8055d748)]
8054260d 58              pop     eax
8054260e 5a              pop     edx
8054260f 64ff0538060000  inc     dword ptr fs:[638h] //使用计数
80542616 8bf2            mov     esi,edx
80542618 8b5f0c          mov     ebx,dword ptr [edi+0Ch]
8054261b 33c9            xor     ecx,ecx
8054261d 8a0c18          mov     cl,byte ptr [eax+ebx]
80542620 8b3f            mov     edi,dword ptr [edi]
80542622 8b1c87          mov     ebx,dword ptr [edi+eax*4]
8053e621 2be1            sub     esp,ecx
8053e623 c1e902          shr     ecx,2   
8054262a 8bfc            mov     edi,esp
8054262c 3b3534315680    cmp     esi,dword ptr [nt!MmUserProbeAddress (80563134)]
80542632 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (805427e0)
80542638 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
8054263a ffd3            call    ebx      //服务调用
我们再来看下PsConvertToGuiThread函数
————————————————————————————————
nt!PsConvertToGuiThread:
805c3720 6a38            push    38h
805c3722 6810ac4d80      push    offset nt!ObWatchHandles+0x3c4 (804dac10)
805c3727 e8e457f7ff      call    nt!_SEH_prolog (80538f10)
805c372c 64a124010000    mov     eax,dword ptr fs:[00000124h]
805c3732 8bf0            mov     esi,eax
805c3734 33db            xor     ebx,ebx
805c3736 389e40010000    cmp     byte ptr [esi+140h],bl
805c373c 750a            jne     nt!PsConvertToGuiThread+0x28 (805c3748)
805c373e b80d0000c0      mov     eax,0C000000Dh
805c3743 e91f010000      jmp     nt!PsConvertToGuiThread+0x147 (805c3867)
805c3748 391d180b6780    cmp     dword ptr [nt!PspW32ProcessCallout (80670b18)],ebx
805c374e 750a            jne     nt!PsConvertToGuiThread+0x3a (805c375a)
805c3750 b8220000c0      mov     eax,0C0000022h
805c3755 e90d010000      jmp     nt!PsConvertToGuiThread+0x147 (805c3867)
805c375a 81bee0000000a03f5580 cmp dword ptr [esi+0E0h],offset nt!KeServiceDescriptorTable (80553fa0)
805c3764 740a            je      nt!PsConvertToGuiThread+0x50 (805c3770)
805c3766 b81b000040      mov     eax,4000001Bh
805c376b e9f7000000      jmp     nt!PsConvertToGuiThread+0x147 (805c3867)
805c3770 8b4644          mov     eax,dword ptr [esi+44h]
805c3773 8945e0          mov     dword ptr [ebp-20h],eax
805c3776 389e42010000    cmp     byte ptr [esi+142h],bl
805c377c 756a            jne     nt!PsConvertToGuiThread+0xc8 (805c37e8)
805c377e 33c0            xor     eax,eax
805c3780 8a86df000000    mov     al,byte ptr [esi+0DFh]
805c3786 50              push    eax
805c3787 6a01            push    1
805c3789 e820b8f4ff      call    nt!MmCreateKernelStack (8050efae)
805c378e 8bf8            mov     edi,eax
805c3790 3bfb            cmp     edi,ebx
805c3792 752a            jne     nt!PsConvertToGuiThread+0x9e (805c37be)
805c3794 895dfc          mov     dword ptr [ebp-4],ebx
805c3797 64a118000000    mov     eax,dword ptr fs:[00000018h]
805c379d 8945dc          mov     dword ptr [ebp-24h],eax
805c37a0 c7403408000000  mov     dword ptr [eax+34h],8
805c37a7 eb07            jmp     nt!PsConvertToGuiThread+0x90 (805c37b0)
805c37a9 33c0            xor     eax,eax
805c37ab 40              inc     eax
805c37ac c3              ret
805c37ad 8b65e8          mov     esp,dword ptr [ebp-18h]
805c37b0 834dfcff        or      dword ptr [ebp-4],0FFFFFFFFh
805c37b4 b8170000c0      mov     eax,0C0000017h
805c37b9 e9a9000000      jmp     nt!PsConvertToGuiThread+0x147 (805c3867)
805c37be b101            mov     cl,1
805c37c0 ff15f4864d80    call    dword ptr [nt!_imp_KfRaiseIrql (804d86f4)]
805c37c6 8845e7          mov     byte ptr [ebp-19h],al
805c37c9 8d8700d0ffff    lea     eax,[edi-3000h]
805c37cf 50              push    eax
805c37d0 57              push    edi
805c37d1 e8bacff3ff      call    nt!KeSwitchKernelStack (80500790)
805c37d6 8bf8            mov     edi,eax
805c37d8 8a4de7          mov     cl,byte ptr [ebp-19h]
805c37db ff151c874d80    call    dword ptr [nt!_imp_KfLowerIrql (804d871c)]
805c37e1 53              push    ebx
805c37e2 57              push    edi
805c37e3 e8ceb9f4ff      call    nt!MmDeleteKernelStack (8050f1b6)
805c37e8 a10cbf5580      mov     eax,dword ptr [nt!PPerfGlobalGroupMask (8055bf0c)]
805c37ed 3bc3            cmp     eax,ebx
805c37ef 7447            je      nt!PsConvertToGuiThread+0x118 (805c3838)
805c37f1 f6400401        test    byte ptr [eax+4],1
805c37f5 7441            je      nt!PsConvertToGuiThread+0x118 (805c3838)
805c37f7 8b86ec010000    mov     eax,dword ptr [esi+1ECh]
805c37fd 8945d0          mov     dword ptr [ebp-30h],eax
805c3800 8b86f0010000    mov     eax,dword ptr [esi+1F0h]
805c3806 8945d4          mov     dword ptr [ebp-2Ch],eax
805c3809 8b8668010000    mov     eax,dword ptr [esi+168h]
805c380f 8945b8          mov     dword ptr [ebp-48h],eax
805c3812 8b461c          mov     eax,dword ptr [esi+1Ch]
805c3815 8945bc          mov     dword ptr [ebp-44h],eax
805c3818 895dc0          mov     dword ptr [ebp-40h],ebx
805c381b 895dc4          mov     dword ptr [ebp-3Ch],ebx
805c381e 895dc8          mov     dword ptr [ebp-38h],ebx
805c3821 895dcc          mov     dword ptr [ebp-34h],ebx
805c3824 c645d8ff        mov     byte ptr [ebp-28h],0FFh
805c3828 6a24            push    24h
805c382a 8d45b8          lea     eax,[ebp-48h]
805c382d 50              push    eax
805c382e 6823050000      push    523h
805c3833 e872ae0900      call    nt!PerfInfoLogBytes (8065e6aa)
805c3838 6a01            push    1
805c383a ff75e0          push    dword ptr [ebp-20h]
805c383d ff15180b6780    call    dword ptr [nt!PspW32ProcessCallout (80670b18)]
805c3843 3bc3            cmp     eax,ebx
805c3845 7c20            jl      nt!PsConvertToGuiThread+0x147 (805c3867)
805c3847 c786e0000000603f5580 mov dword ptr [esi+0E0h],offset nt!KeServiceDescriptorTableShadow (80553f60)
/*
  我们就在这个位置HOOK吧,第一 函数执行到这里的时候基本上可以确定是GUI线程啦
  第二 这个是个让 esi=KTHREAD->ServiceTable指向了KeServiceDescriptorTableShadow
  我们很容易得到KeServiceDescriptorTableShadow.
*/
805c3851 53              push    ebx
805c3852 56              push    esi
805c3853 ff151c0b6780    call    dword ptr [nt!PspW32ThreadCallout (80670b1c)]
805c3859 3bc3            cmp     eax,ebx
805c385b 7d0a            jge     nt!PsConvertToGuiThread+0x147 (805c3867)
805c385d c786e0000000a03f5580 mov dword ptr [esi+0E0h],offset nt!KeServiceDescriptorTable (80553fa0)
805c3867 e8df56f7ff      call    nt!_SEH_epilog (80538f4b)
805c386c c3              ret
________________________________________________________________
看了一大堆了,直接上代码吧,学习笔记 写得比较烂,大家将就着看吧 不要拍我哦
我们来HOOK MyNtUserGetForegroundWindow 吧

#include<ntddk.h>

VOID Hook();
VOID WPOFF();
VOID WPON();

ULONG Ret=0;
ULONG hookaddr=0;
ULONG oldaddres=0;

ULONG MyNtUserGetForegroundWindow(VOID)
{
        _asm{
         call oldaddres
        }

}

//bf8b1369
/*805c3867 e8df56f7ff      call    nt!_SEH_epilog (80538f4b) */
//805c3847 c786e0000000603f5580 mov dword ptr [esi+0E0h],offset nt!KeServiceDescriptorTableShadow (80553f60)
__declspec(naked)  void __stdcall MyHook()
{
         _asm{
          mov dword ptr [esi+0xe0],0x80553f60 //这个也是我机器上SSDTShadow 的地址
          push eax
          push edx
          push edi
          cli
          mov eax,cr0
          and eax,not 10000h
          mov cr0,eax
          mov edx,hookaddr
          mov eax,[esi+0xe0]
          add eax,0x10
          mov eax,[eax]
          mov edi,[eax+0x194*4]//194是NtUserGetForegroundWindow服务调用号
          cmp edi,edx
          jz ggdd
          mov oldaddres,edi
          mov [eax+0x194*4],edx
    ggdd:
          mov eax,cr0
          or eax,10000h
          mov cr0,eax
          sti  
          pop  edi
          pop edx
          pop eax
          jmp [Ret]
        }

}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
   NTSTATUS status;
   hookaddr=(ULONG)MyNtUserGetForegroundWindow;
   Hook();
   return STATUS_SUCCESS;
}
VOID Hook()
{   
         ULONG ObjAddrs,jmpAddrs;
         UNICODE_STRING  name;
         KIRQL  Irql;
         char code[10]={0xe9,0,0,0,0,0x90,0x90,0x90,0x90,0x90};
         ObjAddrs=(ULONG)0x805c3720;//这里我偷懒啦直接用硬编码啦,大家可以内存搜索
         ObjAddrs=ObjAddrs+0x127;//返回地址
         Ret=ObjAddrs+10;
         DbgPrint("pAaddrs is:%08X\n",ObjAddrs);
         DbgPrint("Ret is:%08X\n",Ret);
         jmpAddrs=(ULONG)MyHook-ObjAddrs-5;
         *(ULONG*)(code+1)=jmpAddrs;
     WPOFF();
     Irql=KeRaiseIrqlToDpcLevel();
      RtlCopyMemory(ObjAddrs,code,10);
     KeLowerIrql(Irql);
      WPON();  
   }

VOID WPOFF()
{
  __asm
  {
    cli
    mov eax,cr0
    and eax,not 10000h
    mov cr0,eax
  }
}

VOID WPON()
{
  __asm
  {
    mov eax,cr0
    or eax,10000h
    mov cr0,eax
    sti
  }
}
  测试环境:XPSP3
  大概就是这么多啦,都是些老东西,大家凑合着看吧,如果有什么不对的,欢迎大家指出
共同学习共同进步嘛。


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

上传的附件:
  • 3.jpg (107.48kb,374次下载)
收藏
点赞0
打赏
分享
最新回复 (7)
雪    币: 79
活跃值: 活跃值 (40)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
竹君 活跃值 5 2011-3-22 09:19
2
0
小提示(win32k.sys不是常在内存的,如果不是GUI线程,shadow ssdt地址无效)这句话似乎是有问题的
雪    币: 71
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mumaren 活跃值 2011-3-22 13:32
3
0
mark一下,备用
雪    币: 210
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
菜可菜 活跃值 2011-3-23 23:39
4
0
我新人,斗胆来理解并解释一下竹君大大说的这句,

其实win32k.sys是常驻的,但是 ssdt shadow 指向 win32k.sys 的GUI/USER的那个表里的内容不是。所以只有当当前线程是GUI线程时,那块内存才会被填充。

感觉是这样,不知道理解的对不对?

请竹大斧正。。。
雪    币: 210
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
菜可菜 活跃值 2011-3-23 23:49
5
0
最近一直在学这方面的东西,觉得眼熟,搜索了一下论坛,原来LZ那句话貌似是复制zhuwg大牛的文章里的那句话。
雪    币: 210
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
菜可菜 活跃值 2011-3-24 01:41
6
0
又看了一下论坛文章,发现又Exp又增加了一点。

继续竹大引出的话题,我猜想,仅仅是猜想。。。

指向win32k分配的那块内存区是分配属性是PagePool,属于分页内存,这种内存并不是永远保存在屋里内存上的。

而 nt内核分配的那块,属性是NonPagePool,是永远在屋里内存上的,所以任意时刻在 windbg 中键入
“dd nt!KiServiceTable”都是能够查看到的。

只是猜测,说的不对请大牛们批评指正。
雪    币: 220
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
广海混沌 活跃值 2011-3-24 03:34
7
0
呵呵 凌晨3点给你回复一下
雪    币: 306
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tfzxyinhao 活跃值 2011-3-31 16:21
8
0
ObjAddrs=(ULONG)0x805c3720;//这里我偷懒啦直接用硬编码啦,大家可以内存搜索

这个红色的这个地址是什么地址
游客
登录 | 注册 方可回帖
返回