到底什么是子系统?
子系统是用户层概念。在Windows内核之上,如果想要执行类UNIX应用程序,就是POSIX子系统,如果要类似OS/2环境,就是OS/2子系统。
如何能模拟出不同子系统呢? 一般需要子系统用户态应用程序和相关DLL支援。
对于Windows子系统,作为亲儿子,其他子系统是依赖它才能活。
Windows子系统既有内核模式,又有用户模式。
内核模式包括图形和窗口管理部分,以win32k.sys存在,主要负责收集和分发消息,控制窗口显示和屏幕输出,同时处理不同形状绘制和文本输出。
用户模式包括子系统进程(csrss.exe)和系统DLL(kernel32.dll, user32.dll, gdi32.dll...).
刚刚提到子系统是用户层概念,为什么Windows子系统又有内核模式? Windows为了提高图形处理效率,把本应该放在用户模式的图形部分移到内核模式,才有了这个结果。
Windows NT三大子系统
OS/2、POSIX和Windows子系统
OS/2子系统
核心文件: os2.exe/os2srv.exe/os2ss.exe.
OS/2是IBM可与DOS/Windows早期版本竞争的操作系统,因为商业模式、技术和市场有错失,最终败在Windows脚下。
POSIX子系统
核心文件: psxss.exe/psxdll.dll.
在Windows 7不是默认开启,作为系统功能可开关。
从Windows 8.1开始, POSIX子系统被移除。
Windows 10 WSL
Windows Subsystem For Linux, 准确的说不算是上面提到的NT子系统。但因为名称上带有subsystem, 很容易与之混淆。
可执行程序和子系统对应关系
PE文件头部有个subsystem, 它表明应用程序在哪个子系统运行。
MS VC链接器提供选项/SUBSYSTEM指定最终可执行文件的subsystem数值。
dumpbin工具可以看到subsystem.
子系统进程csrss.exe
csrss全称: Client/Server Runtime Server Subsystem. 主要负责控制台窗口功能,以及创建、删除进程和线程等。每个进程在csrss进程中都有一个CSR_PROCESS结构, csrss可以由此控制Windows各个进程。
子系统内核部分win32k.sys
任何线程,只要调用win32k.sys的任何一个系统服务,就会变成GUI线程,最终会被纳入Windows子系统管理范畴。win32k负责用户层图形操作的内部处理, 比如Eng接口。
文本输出 win32k API: EngTextOut
ntdll.dll属于子系统DLL吗?
不属于。它是各子系统DLL共用的基础DLL.
ntdll.dll
它是连接用户模式和内核服务的桥梁。ntdll基本与系统服务对应,保留系统服务stub.
比如NtCreateProcess, NtCreateFile等。
ntdll!NtCreateFile和nt!NtCreateFile
二者分别属于用户模式和内核模式API, 前面最终会调用到后面, 后面是实作。
ntdll!NtCreateFile和ntdll!ZwCreateFile
二者是等同的。如下,ZwCreateFile其实就是NtCreateFile.
1: kd> u ntdll!ZwCreateFile
ntdll!NtCreateFile:
00007ff9`0776d7b0 4c8bd1 mov r10,rcx
00007ff9`0776d7b3 b855000000 mov eax,55h
00007ff9`0776d7b8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
00007ff9`0776d7c0 7503 jne ntdll!NtCreateFile+0x15 (00007ff9`0776d7c5)
00007ff9`0776d7c2 0f05 syscall
00007ff9`0776d7c4 c3 ret
00007ff9`0776d7c5 cd2e int 2Eh
00007ff9`0776d7c7 c3 ret
1: kd> u ntdll!NtCreateFile
ntdll!NtCreateFile:
00007ff9`0776d7b0 4c8bd1 mov r10,rcx
00007ff9`0776d7b3 b855000000 mov eax,55h
00007ff9`0776d7b8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
00007ff9`0776d7c0 7503 jne ntdll!NtCreateFile+0x15 (00007ff9`0776d7c5)
00007ff9`0776d7c2 0f05 syscall
00007ff9`0776d7c4 c3 ret
00007ff9`0776d7c5 cd2e int 2Eh
00007ff9`0776d7c7 c3 ret
IDA看到二者是不同导出Index, 同一个API.
ntdll大部分存根API实现都类似
用户模式下,Nt*和Zw*代表同一个程式,不过在内核中它们有差异。Windows的设计,是Nt*主要为了用户模式调用, 内核Nt*实作用户模式Nt*, 而Zw*在内核模式主要为了内核本身或驱动程序使用,不希望从用户模式调进来。