003内核编程学习笔记
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SSDT hook 所延伸出来的知识
关于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);。