您的位置:首页 > 编程语言

内核编程学习笔记(003) SSDT hook 所延伸出来的知识

2011-03-20 10:34 495 查看
关于SSDT :SystemServiceDescriptorTable (系统服务描述表)我还是第一次深刻的接触到这类东西,说来百度百科有对这玩意的解析和定义。但不得不说的是看雪《SSDT Hook的妙用 对抗ring0 inline hook》一文了,作者是堕落天才。我在两者的基础上,做了一个归纳:

内核中有两个系统服务描述符表,一个是KeServiceDescriptorTable,由ntoskrnl.exe导出,一个是KeServieDescriptorTableShadow,没有导出。

结构如下:

typedef struct _SYSTEM_SERVICE_TABLE
{
PVOID ServiceTableBase; //这个指向系统服务函数地址表
PULONG ServiceCounterTableBase;
ULONG NumberOfService; //服务函数的个数,NumberOfService*4 就是整个地址表的大小
ULONG ParamTableBase;
}SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;

typedef struct _SERVICE_DESCRIPTOR_TABLE
{
SYSTEM_SERVICE_TABLE ntoskrnel; //ntoskrnl.exe的服务函数
SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数,(gdi.dll/user.dll的内核支持)
SYSTEM_SERVICE_TABLE NotUsed1;
SYSTEM_SERVICE_TABLE NotUsed2;
}SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE;

由于KeServiceDescriptorTable是由ntoskrnl.exe导出的导出表,可以在WinDbg中直接查看:命令如下
dd KeServiceDescriptorTable

然后KeServiceDescriptorTable的这里地址里的数据就是整个Nt服务索引表的首地址

简单理解:
Nt服务索引表的首地址 = [KeServiceDescriptorTable]

整个 Nt服务索引表 里按顺序存放了每个 Nt函数的入口地址 每个地址占着4个字节

如果你想找的是43号的NtCreateMutant 函数的入口地址,就要经过如下的计算(索引是由0开始的)43(decimal) = 2b(Hex)

NtCreateMutant 函数的入口地址 = [[KeServiceDescriptorTable] + 0x2b * 4]

在WinDbg中:
dd poi[poi[KeServiceDescriptorTable] + 0n43 * 4] //其中0n代表使用十进制
poi代表point这个很容易理解

[KeServiceDescriptorTable] + 0x2b * 4 这个位置 的4个字节, 如果改成了其他的函数的地址,那么就可以把
SSDT给HOOK住了。

注意:
①ULONG 就是4个字节的长度。

②乘以4的操作可以左移2位来做,汇编的方便之处
shl eax,2 等价于 mul 2
复习:imul 带符号乘法 mul无符号乘法

③特别注意,前后一定要平衡寄存器环境,多次蓝屏之后都应该反省一下了

ULONG NtCreateMutant_in_SSDT;
ULONG NtCreateMutant_CurrentAddress;

//在SSDT表中读出 NtCreateMutant 所在地址信息
__asm
{
push ebx
push eax
mov ebx,KeServiceDescriptorTable
mov ebx,[ebx]
mov eax,0x2b
shl eax,2
add ebx,eax
mov NtCreateMutant_in_SSDT,ebx
mov ebx,[ebx]
mov NtCreateMutant_CurrentAddress,ebx
pop eax
pop ebx
}
*****************分割线*******************

注意:

①去掉页面保护的方法为CR0 的 wp(写保护(Write Proctect标志位
000x0000这位如果为0,就去掉页面保护,为1就加上保护

②要用cli 和 sti 来屏蔽和恢复外中断

③还是那句:前后平衡寄存器环境
//去掉页面保护 和 写入新的 NtCreateMutant地址
__asm
{
cli
push ebx
push eax
mov eax,cr0
and eax,not 00010000h
mov cr0,eax
mov ebx,NtCreateMutant_in_SSDT
mov eax,ulPiaoNtCreateMutant //这里放进自己函数的地址
mov [ebx],eax
mov eax,cr0
or eax, 00010000h
mov cr0,eax
pop eax
pop ebx
sti
}

*****************分割线*******************

定义NtCreateMutant的原形可以用来获得Nt函数地址(ULONG)后,通过(强制转换成NTCREATEMUTANT *)原型的指针掉调用该函数;

//定义NtCreateMutant的原形
typedef NTSTATUS __stdcall NTCREATEMUTANT(
OUT PHANDLE MutantHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN BOOLEAN InitialOwner);

例如:realNtCreateMutant = (NTCREATEMUTANT *)realNtCreateMutantAddress;
然后这样调用
(NTSTATUS)realNtCreateMutant(MutantHandle,
DesiredAccess,
ObjectAttributes,
InitialOwner);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: