登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 708|回复: 0

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

[复制链接]

102

主题

10

回帖

607

积分

管理员

积分
607
发表于 2024-12-18 21:53:34 | 显示全部楼层 |阅读模式
一般不调用Ntdll,因为Ntdll参数要求跟3环是不一样的
跟踪系统调用SYSENTER
XP下的内核模块,开了PAE就找带pa的内核模块
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374271021-e16e1d0b-ac49-4ca1-ad6a-a855f9496e91.png
XP下的ntdll模块
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374271220-78765d24-b6c8-44d0-aaf9-e592e4ae2f52.png
XP下的user32模块和kerne32模块
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374271443-4bb9169a-8d4b-4fa7-ab84-c6e0b9d288be.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374271648-ccf0b439-8f5d-4c15-bb30-df6d85efa3b3.png
IDA打开下载符号,下载完成点击保存idb,之后分析看idb就行
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374272081-9decff0d-b87b-4b56-8ef2-9139440e1e99.png
没有符号的函数一般是微软觉得重要不提供符号的函数
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374272451-f5b3a4f7-2166-405f-ace5-7a8df65be431.png
跟踪ReadProcessMemory,这里是参数转换,然后调Ntdll的导入函数
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374272820-d396ff16-5807-4f05-84fb-d3a2dd9007b0.png
导入表:ntdll导出函数
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374273169-69c4ea8c-8d8e-4ca7-ad7f-355fe9117213.png
IDA打开Ntdll,NtReadVirtualMemory和ZwReadVirtualMemory函数地址是一样的,序号不一样,为了兼容老版本,新版本一般用Zw,XP用的 Nt
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374273400-95f97ec3-1027-4f99-8fe7-03a9cb00a5c3.png
调用了186号API
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374273679-b3d1fa69-ac69-4684-b543-b93335a673cd.png
call的函数只有两种情况
1)SYSENTER
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374274203-fce240ca-6c7a-4b15-a30c-8208e058f726.png
2)Int N
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374274597-5e2f0251-afe5-443f-adb2-94635c291875.png
但他们都会调到KiSystemService/ KiFastCallEntry 函数这两个函数之一
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374274931-3fee5785-c302-4635-97d4-0f82173b180f.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374275293-32b05b8e-0bd4-4875-8e43-73cd2aaf68e8.png
SYSENTER 指令隐含的6步中最为关键的就是从 IA32_SYSENTER_EIP 寄存器取出指令指针放到EIP中,而 IA32_SYSENTER_EIP 寄存器保存的即是 nt!KiFastCallEntry() 的起始地址。通过内核调试器命令 rdmsr 0x176 可以获取该地址
在Windbg中对照一下:获取KiFastCallEntry的地址
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374275694-4a5ed927-35ad-491a-8050-877756d8a37e.png
因为所有进程都会来,所以进程对象筛选一下
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374275943-0c9e593c-a76e-4cc0-89ae-c1c5a4323bc2.png
FS改为内核就能访问到KPCRB结构体(0x30),如果不改就是指向3环的TEB结构体(0x3B)
FS:40h是TSS指针,访问TSS+4,ESP0是0环的ESP,修改ESP为0环的ESP,说明SYSENTER不会切栈
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374276375-b335802e-e949-4c11-895b-c5bb37a52314.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374276888-842d4d90-3015-4047-b78f-8ec2e3470de1.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374277411-c5a2afd9-4bc6-46b6-8f25-d7d1013e8a89.png
接下来,edx是3环的栈,这里+8说明3环没有+8,3环正好是ebp和返回值,+8才是参数
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374277947-6d386fe6-0fa0-4d6b-9e9c-937e4561a3c4.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374278491-cfd26869-2cc4-49c5-ad1c-a02e13565869.png
FS+1C存储了_KPCR首地址也就是FS:0,FS:0就是KPCR首地址,这里为什么不直接用FS:[0],因为汇编无法直接访问FS:0的地址[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374278894-a8ebb795-13ee-4a16-a63e-77661ac32c77.png ,不能取地址,只能mov取内容
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374279158-99647661-e703-45d7-b141-bafa5f4b88f5.png
而这样等于直接拿结构体首地址[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374279455-0838beb8-9342-434a-99ca-20e3df5a98c5.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374279670-56d2a72e-23d2-4aae-a638-e18ddb4b2e10.png
+0x124是KPCRB+4的位置,也就是当前线程
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374280007-b907429b-96d6-47d3-a687-50cdd133d0cd.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374280488-dad4c4ba-6f11-42e5-b2e9-c7b764965aab.png
当前线程+0x18是当前栈
当前线程+0x140是之前模式,也就是从3环过来还是0环过来的
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374280740-7d967cdc-9be3-44ac-bbf2-cad935f56912.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374281133-67d8494d-627c-4477-af97-c00e5062bfd4.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374281563-1edc8509-06e0-453d-890a-c2a8f7eb58f5.png
Zw跟Nt很像
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374282070-9d71fe72-39e3-442b-83fd-93561084df3d.png
Zw调的是KiSystemService
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374282544-0490c571-c95e-45b2-9193-09a79361373d.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374282809-9bae055b-bd64-4d71-b622-724e528e4108.png
Zw函数最终还是调用了Nt函数,为什么微软不建议调Nt函数?
1)因为Nt不检查参数
2)下个版本这个函数可能就被删了
为什么还要坚持调用?因为一般HOOK的都是Zw函数,而不是Nt函数,Nt更底层
而MSR在3环比Nt更底层,寄存器选择调用函数和传参
_KTHREAD(_ETHREAD)+E0就是SSDT(系统服务表),ServiceTable
说明创建线程的时候SSDT表地址就放入了这个成员里
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374283172-893dade8-2e1c-46a3-bb17-4fe8410345f1.png
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374283779-13a564da-a903-46c4-9299-b0f16cb7a58e.png
表地址+EDI,说明表有两个,控制台只有SSDT表,Win32程序有两个表SSDT和ShadowSSDT
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374284235-62a6edec-a5c6-4eb2-a62e-e90c9749a853.png
UI函数实现代码在Win32k.sys
切环境:/r,[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374284747-665ffcbd-0712-4149-912b-91cd17669f7f.png
切进程:/i,[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374285264-b946e8fd-5e08-4cf7-bdff-074cf4c1eaf2.png
再使用lm命令查看模块就能看到Win32k.sys
对指定进程的指定函数下断点[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374285759-428bd1de-71c8-4957-a01c-4101e20e726a.png
API编号12位有效,高位丢弃了
下断点,拿到EDI之后断下
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374286317-290c931a-c7fa-4e8c-801e-d24d08f60ec9.png
EDI是结构体,16字节大小
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374286822-122ae1b0-9af2-4713-bc4c-b19408648163.png
[EDI+0]是指向SSDT首地址
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374287853-d95f55e6-ca50-4141-8ae0-828c034e141e.png
[EDI+8]是SSDT的函数数量
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374288366-717f3be4-94d2-4385-975d-a2db3e2030a2.png
dds 地址,符号解析;ddp 地址,二级指针
符号解析每个成员
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374288860-039a0db4-104f-45c1-8b23-c7cfd0241fad.png
最后一项是参数大小的数组指针
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374289442-cbb168d5-c0b6-4d31-9fb9-f4a4959c78f9.png
项数 = (当前函数下标地址 - 数组首地址)/4
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374289976-ca347c2c-4174-4c5b-9abb-67d30f890816.png
参数大小 = 参数大小的数组指针 + 项数
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374290515-c5349be5-af48-4bc1-8115-f9a2a5761520.png
遍历进程线程
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374290966-3d56c169-8ed3-4fae-ad0d-b8daf358b348.png
线程的ServiceTable指向服务表首地址,Win32服务表第一项是SSDT,第二项是ShadowSSDT
取参数
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374291202-83743d28-c794-4e7f-bbad-19faf02be305.png
查出数量抬栈
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374291507-5063dadc-a951-40ce-b1a3-07a6963278f8.png
查表完成后调用该函数
[color=var(--fgColor-accent, var(--color-accent-fg))] 1664374291748-16ea1982-9ce7-4c1b-9ff4-b8cfb6f6fbfd.png
HOOK SSDT的方案:
1)hook msr
2)inine hook KiFastCallEntry
3)hook 修改SSDT表 或 ShadowSSDT表
inine hook KiIsCall
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|断点社区 |网站地图

GMT+8, 2025-2-22 16:44 , Processed in 0.114404 second(s), 28 queries .

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

快速回复 返回顶部 返回列表