内核呓语系列3 —— windows会话管理

2013-12-24 Nie.Meining Coding

今天接着讲windows子系统。上文提到,任何一个应用程序,包括CUI程序,都运行在Windows子系统中,实际上会话管理器smss.exe是个特殊情况,另外System和Idle也是特殊情况(它们根本没有对应的程序文件),这个留到以后讲进程的时候再细讲吧。

smss.exe之所以特殊是因为windows子系统窗口管理分为“会话 --> 窗口站 --> 桌面”三级架构,而会话正是由smss.exe创建的,此时还没有windows子系统。实际上smss.exe是Windows启动后创建的第一个用户模式进程,windows环境子系统进程csrss.exe正是由smss.exe所创建,win32.sys也是由smss.exe加载(MmLoadSystemImage + call oep)。

接下来smss还会创建winlogon.exe,提供登陆认证。winlogon.exe负责登陆界面、锁屏界面等实现。想起了当年广为流传的输入法漏洞、粘滞建漏洞等绕过登录认证的方法……这里就不详细解释了。

说到会话管理,xp中winlogon.exe登陆界面和第一个用户会共享session,但后来因为session隔离(见session隔离故事),导致某些需要与用户桌面进行交互的服务(例如一些木马程序的截屏功能)需要进行更多的操作来指定session和桌面。

前面已经提到过了,Windows的窗口管理由会话、窗口站、桌面三级组成,一个会话包含多个窗口站,每个窗口站又包含多个桌面,每个桌面上才是各个程序。第一个smss.exe创建第一个会话后,会调用NtWaitForMultipleObjects无限等待子进程csrss.exe和winlogon.exe:

nhyy3_1.png

当其中任何一个进程退出后,系统会崩溃。smss.exe通过调用NtRaiseHardError引发蓝屏,代码如下:

nhyy3_2.png

需要创建新的会话时,smss.exe进程会启动一个新的smss进程,不过新的smss完成会话创建、启动winlogon、wininit等进程后,直接就退出了,不再等待会话结束。有意思的是,smss通过参数发现自己是否是第一个会话。

最后再讲讲子系统和用户交互的细节。对于每个会话csrss.exe都会创建一个RIT线程接收鼠标、键盘等硬件事件,其原理是从对应的设备驱动程序中读取输入数据(技术细节留到以后讲I/O的时候再展开吧),并组织成消息的形式,发送到正确的线程消息队列中。每个GUI线程都有两个消息队列,分别针对SendMessage和PostMessage。严格来讲,鼠标事件并不是直接由RIT从设备驱动中读出的,中间还有一个桌面线程做转发,这里就不展开了。

想起以前写的两篇文章:《注入进程实现星号查看》、《鼠标修复软件2.0,IRP HOOK实现》。

说到windows子系统对图形界面、消息机制的原生支持,作为初级hack技术的消息钩子(SetWindowsHookEx)想必大家都不陌生。无论鼠标钩子、键盘钩子等,这种技术的神奇之处在于将一段代码插入到了其它线程的消息处理过程中。其实现原理是,每个GUI线程都有一个钩子数组。因此需要检测这类钩子时,通过Win32Thread进行枚举是一种方式(win32k.sys内部有专门的枚举函数_PhkFirstValid和_PhkNextValid)。

这里有个有趣的地方,钩子是在内核模式下被激发的,但又必须调用用户模式的钩子函数,因此引入了KeUserModeCallBack内核函数。这可是在rootkit中调用Ring3代码的官方稳定方案。除此以外,插APC是一个广为流传的方案……Ring0调用Ring3函数是个比较有趣的话题,我以前也做过一些研究,发出来参考:《ring0注入ring3的一种新方法》、《继续Ring0注入Ring3》。此外,由于消息钩子技术注入的代码依赖于KeUserModeCallBack函数,因此大量ARK(如360、QQ管家等)都是通过hook该函数来防止DLL注入。

windows子系统就写到这里了,最近挺忙的……接下来打算写系统调用。

发表评论:

Powered by emlog