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