Windows内核学习

消息机制

Window消息机制的解决方案是通过GUI线程来处理,消息队列在R0层。

Linux消息机制是通过进程来处理。

1.当线程刚创建的时候,都是普通线程:

Thread.ServiceTable->KeServiceDescriptorTable (系统服务表)

2.当线程第一次调用Win32k.sys(调用服务号>100)的时候,会调用:PsConvertToGuiThread。

主要做2件事情:

a.扩充内核栈,必须换成64KB大小的内核栈,因为普通内核栈只有12KB大小
b.创建一个_KTHREAD结构体(有一个成员指针指向结构体 _THREADINFO,_THREADINFO结构体有一个成员叫MessageQueue,即消息队列,只有GUI线程才有),普通线程_KTHREAD->Win32Thread = NULL;
c.Thread.ServiceTable->KeServiceDescriptorTableShadow
d.把需要的内存数据映射到本进程空间。

总结: 可以通过KTHREAD.Win32Thread来找到消息队列,只有GDI线程才有消息队列,一对一的关系。

窗口与线程

所有的窗口在0环都有一个 _WINDOWS_OBJECT 对象,该对象->PTHREADINFO 指向其GDI线程。

一个线程有N多窗口,一个窗口只能属于一个线程。

窗口句柄是全局对象,可以被多个进程使用。

消息队列

消息队列的结构

1.SentMessagesListHead // 接收SendMessage发来的消息。

2.PostedMessagesListHead // 接到PostMessage发来的消息

3.HardwareMessagesListHead // 接收鼠标、键盘的消息

一共有7种,自行百度补全、

GetMessage 函数(
LPMSG lpMsg
HWND hWnd
UNIT wMsgMin
UNIT wMsgMax
)

注: GetMessage 会自动处理 SentMessagesListHead 队列的消息并消灭

DispatchMessage 拿着句柄进0环通过窗口对象来进行分发。

TranslateMessage 主要负责处理键盘消息 WM_CHAR消息的转换等。

内核调用

从0环到3环的几种方式:

  • APC
  • 异常
  • 内核回调

凡是有窗口的程序就有可能0环直接调用3环程序。

回调机制中0环调用3环的代码是函数KeUserModeCallback。

APC 回到3环的落脚点 ntdll!KiUserApcDispatcher

异常 回到3环的落脚点 ntdll!KiUserExceptionDispatcher

内核回调表 PEB + 0x2C -> 内核进入三环的地址表