凌晨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
大概就是这么多啦,都是些老东西,大家凑合着看吧,如果有什么不对的,欢迎大家指出
共同学习共同进步嘛。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)