ShadowSSDT表的获取
这里的ShadowSSDT表的获取是通过函数KeAddSystemServiceTable来获取的。
使用这个函数的原因:
1、这个函数是已经导出的,可以在代码中直接使用。
2、这个函数里面使用了ShadowSSDT,包含了ShadowSSDT的地址。
可以使用WinDbg查看该函数代码,如下:
kd> u KeAddSystemServiceTable l 30
nt!KeAddSystemServiceTable:
83fa3008 8bff mov edi,edi
83fa300a 55 push ebp
83fa300b 8bec mov ebp,esp
83fa300d 837d1801 cmp dword ptr [ebp+18h],1
83fa3011 7760 ja nt!KeAddSystemServiceTable+0x6b (83fa3073)
83fa3013 8b4518 mov eax,dword ptr [ebp+18h]
83fa3016 c1e004 shl eax,4
83fa3019 83b8c009f88300 cmp dword ptr nt!KeServiceDescriptorTable (83f809c0)[eax],0
83fa3020 7551 jne nt!KeAddSystemServiceTable+0x6b (83fa3073)
83fa3022 8d88000af883 lea ecx,nt!KeServiceDescriptorTableShadow (83f80a00)[eax]
83fa3028 833900 cmp dword ptr [ecx],0
83fa302b 7546 jne nt!KeAddSystemServiceTable+0x6b (83fa3073)
83fa302d 837d1801 cmp dword ptr [ebp+18h],1
83fa3031 8b5508 mov edx,dword ptr [ebp+8]
83fa3034 56 push esi
83fa3035 8b7510 mov esi,dword ptr [ebp+10h]
83fa3038 57 push edi
83fa3039 8b7d14 mov edi,dword ptr [ebp+14h]
83fa303c 8911 mov dword ptr [ecx],edx
83fa303e 8b4d0c mov ecx,dword ptr [ebp+0Ch]
83fa3041 8988040af883 mov dword ptr nt!KeServiceDescriptorTableShadow+0x4 (83f80a04)[eax],ecx
83fa3047 89b0080af883 mov dword ptr nt!KeServiceDescriptorTableShadow+0x8 (83f80a08)[eax],esi
83fa304d 89b80c0af883 mov dword ptr nt!KeServiceDescriptorTableShadow+0xc (83f80a0c)[eax],edi
83fa3053 7418 je nt!KeAddSystemServiceTable+0x65 (83fa306d)
在代码中获取ShadowSSDT的方式是暴力搜索,代码如下:
ULONG GetShadowTableAddress()
{
ULONG dwordatbyte, i;
PUCHAR p = (PUCHAR)KeAddSystemServiceTable;
for(i = 0; i < 0x1024; i++, p++)
{
__try
{
dwordatbyte = *(PULONG)p;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return NULL;
}
if(MmIsAddressValid((PVOID)dwordatbyte))
{
//这里得到的以dwordatbyte为首地址的数据是否与KeServiceDescriptorTable的前16字节相同
if(memcmp((PVOID)dwordatbyte, KeServiceDescriptorTable, 16) == 0)
{
//地址相同,则排除,因为要找到的是ShadowSSDT,而不是SSDT。
if((PVOID)dwordatbyte == KeServiceDescriptorTable)
continue;
return dwordatbyte;
}
}
}
return NULL;
}
ShadowSSDT Hook
ShadowSSDT的Hook方法与SSDT的Hook方法基本一样,不同的地方是以下几点:
1、ShadowSSDT Hook之前需要先KeAttachProcess一个有界面的进程,一般会操作explorer.exe
2、由于KeAttachProcess需要传入一个类型为PEPROCESS的参数,需要通过进程名获取该进程的PEPROCESS结构体。
3、Hook完成之后使用KeDetachProcess获取Attach的进程。
简单说一下通过进程名获取该进程的PEPROCESS结构体的方法:
使用PsGetProcessImageFileName获取当前进程的结构体,以此向前或向后遍历搜索,获取结构体中的进程名信息与需要的进程名比较。在这个里面需要处理的两个地方,由于系统版本不同,导致PEPROCESS结构体中进程名的偏移不同,因此需要先判断系统,设置不同的偏移;第二个是PsGetProcessImageFileName该函数只能运行于PASSIVE_LEVEL层,所以需要获取当前的IRQL进行判断。
疑问
关于KeAttachProcess和KeDetachProcess,
我想在Hook之后,KeAttachProcess一个进程,然后,在卸载Hook之后,再执行KeDetachProcess函数,但是当我Hook完成之后,运行一会,就出现系统蓝屏了,难道KeAttachProcess之后,对ShadowSSDT做完操作,就必须先KeDetachProcess吗?