admin 发表于 2024-12-18 21:53:34

WindowsX86内核17.跟踪SYSENTER、遍历SSDT、SSDT HOOK及对抗

一般不调用Ntdll,因为Ntdll参数要求跟3环是不一样的跟踪系统调用SYSENTERXP下的内核模块,开了PAE就找带pa的内核模块XP下的ntdll模块XP下的user32模块和kerne32模块IDA打开下载符号,下载完成点击保存idb,之后分析看idb就行没有符号的函数一般是微软觉得重要不提供符号的函数跟踪ReadProcessMemory,这里是参数转换,然后调Ntdll的导入函数导入表:ntdll导出函数IDA打开Ntdll,NtReadVirtualMemory和ZwReadVirtualMemory函数地址是一样的,序号不一样,为了兼容老版本,新版本一般用Zw,XP用的 Nt调用了186号APIcall的函数只有两种情况1)SYSENTER2)Int N但他们都会调到KiSystemService/ KiFastCallEntry 函数这两个函数之一SYSENTER 指令隐含的6步中最为关键的就是从 IA32_SYSENTER_EIP 寄存器取出指令指针放到EIP中,而 IA32_SYSENTER_EIP 寄存器保存的即是 nt!KiFastCallEntry() 的起始地址。通过内核调试器命令 rdmsr 0x176 可以获取该地址在Windbg中对照一下:获取KiFastCallEntry的地址因为所有进程都会来,所以进程对象筛选一下FS改为内核就能访问到KPCRB结构体(0x30),如果不改就是指向3环的TEB结构体(0x3B)FS:40h是TSS指针,访问TSS+4,ESP0是0环的ESP,修改ESP为0环的ESP,说明SYSENTER不会切栈接下来,edx是3环的栈,这里+8说明3环没有+8,3环正好是ebp和返回值,+8才是参数FS+1C存储了_KPCR首地址也就是FS:0,FS:0就是KPCR首地址,这里为什么不直接用FS:,因为汇编无法直接访问FS:0的地址,不能取地址,只能mov取内容而这样等于直接拿结构体首地址+0x124是KPCRB+4的位置,也就是当前线程当前线程+0x18是当前栈当前线程+0x140是之前模式,也就是从3环过来还是0环过来的Zw跟Nt很像Zw调的是KiSystemServiceZw函数最终还是调用了Nt函数,为什么微软不建议调Nt函数?1)因为Nt不检查参数2)下个版本这个函数可能就被删了为什么还要坚持调用?因为一般HOOK的都是Zw函数,而不是Nt函数,Nt更底层而MSR在3环比Nt更底层,寄存器选择调用函数和传参_KTHREAD(_ETHREAD)+E0就是SSDT(系统服务表),ServiceTable说明创建线程的时候SSDT表地址就放入了这个成员里表地址+EDI,说明表有两个,控制台只有SSDT表,Win32程序有两个表SSDT和ShadowSSDTUI函数实现代码在Win32k.sys切环境:/r,切进程:/i,再使用lm命令查看模块就能看到Win32k.sys对指定进程的指定函数下断点API编号12位有效,高位丢弃了下断点,拿到EDI之后断下EDI是结构体,16字节大小是指向SSDT首地址是SSDT的函数数量dds 地址,符号解析;ddp 地址,二级指针符号解析每个成员最后一项是参数大小的数组指针项数 = (当前函数下标地址 - 数组首地址)/4参数大小 = 参数大小的数组指针 + 项数遍历进程线程线程的ServiceTable指向服务表首地址,Win32服务表第一项是SSDT,第二项是ShadowSSDT取参数查出数量抬栈查表完成后调用该函数HOOK SSDT的方案:1)hook msr2)inine hook KiFastCallEntry3)hook 修改SSDT表 或 ShadowSSDT表inine hook KiIsCall
页: [1]
查看完整版本: WindowsX86内核17.跟踪SYSENTER、遍历SSDT、SSDT HOOK及对抗