Windows内核新手上路2——挂钩shadow SSDT
文章核心内容:安全软件窗口保护、安全输入、截屏保护的一些思路。挂钩NtUserFindWindowEx、NtUserGetForegroundWindow、NtUserBuildHwndList、NtUserQueryWindow、NtUserWindowFromPoint、NtUserSetParent、NtUserPostMessage、NtUserMessageCall、NtUserSetWindowLong、NtUserShowWindow、NtUserDestroyWindow、NtUserCallHwndParamLock用于窗口保护,挂钩了NtUserSendInput、NtUserGetAsyncKeyState、NtUserOpenDesktop、NtUserTranslateMessage用于安全输入,挂钩NtGdiBitBlt、NtGdiStretchBlt用于截屏保护。
a) Shadow SSDT简介
Shadow SSDT,亦可称SSSDT,英文全名Shadow System Services Descriptor Table,中文直译“阴影系统服务描述表”。Shadow SSDT管的是图形、用户相关的函数(gdi32.dll、user32.dll)。
SSDT SHANDOW的结构跟SSDT的结构类似(见Windows内核新手上路1——挂钩SSDT)。
shadow SSDT的Win32子系统的内核实现是WIN32K.SYS,属于GUI线程,要切换到GUI线程,没有导出表,在windbg中可以用db KeServiceDescriptorTableShadow
查看地址,但是编程中只能通过SSDT的到处来搜索定位。
挂钩shadow SSDT的方法类似于挂钩SSDT,有一点不同的是,在挂钩前,必须将进程上下文切换到CSRSS进程。
shadow SSDT中函数列表的地址 名称是 W32pServiceTable 它是一个未导出的变量 可以通过 db win32k!W32pServiceTable 来查看
1.1 窗口保护
恶意程序通过获取安全软件的窗口句柄,然后通过关闭、隐藏、禁用等手段破坏其正常工作,需要挂钩这些函数来防止恶意程序的破坏。R3和R0函数对应关系如表1所示。
表1 R3-R0函数对于关系
R3 | R0 | 作用 |
FindWindow | NtUserFindWindowEx | 查找窗口获取句柄 |
GetForegroundWindow | NtUserGetForegroundWindow | 得到当前顶层窗口 |
EnumWindows | NtUserBuildHwndList | 枚举所有顶层窗口 |
GetWindowThreadProcessId | NtUserQueryWindow | 获取句柄对应的进程PID |
WindowFromPoint | NtUserWindowFromPoint | 获取所在位置的窗口句柄 |
SetParent | NtUserSetParent | 改变某个子窗口的父窗 |
PostMessage | NtUserPostMessage | 发送消息 |
SendMessage | NtUserMessageCall | 发送消息 |
SetWindowLong | NtUserSetWindowLong | 改变窗口属性 |
ShowWindow | NtUserShowWindow | 改变窗口显示状态 |
DestroyWindow | NtUserDestroyWindow | 销毁窗口 |
EnableWindow | NtUserCallHwndParamLock | 禁用、启用窗口 |
1.2 安全输入
挂钩NtUserSendInput、NtUserGetAsyncKeyState、NtUserOpenDesktop、NtUserTranslateMessage分别用于防止模拟按键、获取键盘按键状态、打开安全桌面、将虚假按键还原成真实的按键。
a) NtUserSendInput
恶意程序可以通过调用SendInput来模拟按键干扰正常输入,可以挂钩NtUserSendInput防止恶意操作。当用户正在输入密码等隐私信息的时候,禁止其他程序调用SendInput模拟键盘和鼠标操作。
b) NtUserGetAsyncKeyState
恶意程序可能不停的调用NtUserGetAsyncKeyState来获取键盘的按键状态从而记录键盘的输入信息,可以挂钩NtUserGetAsyncKeyState用来禁止此类键盘记录行为。当用户正在输入密码等隐私信息的时候,禁止其他程序调用NtUserGetAsyncKeyState,但是不会阻止当前受保护的进程调用(否则会影响正常的密码输入行为)。
c) NtUserOpenDesktop
在Windows操作系统中,消息钩子(通过SetWindowsHookEx设置)只会当前的桌面上的窗口有效,所以,可以建立一个安全桌面,用于运行需要严密保护的进程,这样,非本桌面上运行的程序无法通过消息钩子的方式来获取需要保护进程窗口的信息,达到了保护目标进程窗口的目的(360保险箱和金山密保都有一个叫安全桌面的功能,正是这样实现的)。
首先调用真实的NtUserOpenDesktop函数,然后获取返回句柄的桌面名字,如果此桌面名字跟创建的安全桌面名字一样,则关闭此桌面句柄,并返回一个NULL值,否则返回真实的句柄。达到保护安全桌面的目的,真正做到安全桌面不可渗透。
d) NtUserTranslateMessage
在输入密码的时候,用户程序一般调用TranslateMessage将消息转化为具体的按键信息,利用此特点,可以构建一个DirectInput安全输入通道,即尽可能少的通过Windows系统的键盘按键传输通道(此通道是极度危险的,恶意程序可以在任意位置添加HOOK截获按键信息)。
对NtUserTranslateMessage的挂钩用于修正虚拟键盘输入的虚拟按键,首先需要判断是否正在输入密码,虚拟键盘是否正在运行,是否需要修正按键,这三个参数都是运行于R3的控制程序传递进来给R0驱动的。然后判断消息是否是键盘按键的消息,如果是,则进一步判断此消息是否对应虚假按键,如果是,则修正为真实的按键。虚假的按键和真实的按键也是R3传递给R0驱动的。整个输入通道完全自己构建,不通过Windows系统提供的任何通道,所有的类型的HOOK都无法在此期间截获虚拟键盘输入的密码(很多安全软件提供的虚拟键盘的思路大致如此吧,没有去仔细调研)。
1.3 截屏保护
很多截屏类的键盘记录程序。当用户在虚拟键盘上按下一个键时,恶意程序就截一次屏幕,这样可以清楚地看到用户输入的密码信息。挂钩两个函数NtGdiBitBlt、NtGdiStretchBlt可以用于防截屏。
卡巴斯基反病毒软件率先推出截屏保护,即当虚拟键盘运行的时候,阻止程序进行截屏操作,在一定程度上可以阻止此类键盘记录工具的工作。但是卡巴斯基有一个很大的缺陷,它只能阻止全屏的截图,不能阻止部分屏幕的截图。
PS:上面都是一些思路,没有涉及代码,还需要一步步去实践验证。