Smss.exe加载win32k.sys过程总结
windows操作系统初始化#
windows操作系统再初始化的过程中,当内核完全初始化而且各个组件也已经准备好后会加载一个个用户进程smss.exe(会话管理器),此进程会接着调用NtSetSystemInformation并传入SystemRegistryAppendStringInformation == 38参数加载win32k.sys这个模块,接着就会调用win32k.sys的DriverEntry入口。接着smss.exe便会启动Windows 子系统进程csrss.exe。
win32k.sys加载ShadowSSDT表#
当smss.exe在加载win32k.sys模块后,win32k.sys这个模块会紧接着执行其模块入口DriverEntry,紧接着其会执行AddSystemServiceTable为系统增加一张ShadowSSDT表。我们可以在smss.exe刚刚加载win32k.sys是将ntoskrnl.exe所导出的KeAddSystemServiceTable给EAThook了,然后在我们自己的MyKeAddSystemServiceTable()中判断通过判断加载的表的基地址是否在win32k.sys模块地址范围中,如果不在证明不是正确的ShadowSSDT表。
关于win32k.sys所在地址有效性的问题#
win32k.sys包含ShadowSSDT表,只要线程中调用GUI函数最后都会调用ShadowSSDT表中的服务。但并不是只有GUI线程才会将win32k.sys加载到内存中,参考教主的帖子是说win32k.sys模块的加载与会话有关,所以只要不是System和smss.exe(会话管理器不属于任意一个继承)进程其他任何一个进程都会加载win32k.sys。
我们看一下在System进程中win32k.sys模块的地址,发现确实是无效的。
所以如果我们想要在内核中修改win32k.sys模块(IAT_hook)就必须保证当前进程上下文不在System和smss.exe中,也就是需要将进程上下文切换到除了两个进程之外的任意一个进程地址空间中。
获得csrss.exe进程的PID#
当我们需要IAT_HOOKwin32k.sys模块时可以将地址空间切换到csrss.exe进程地址空间中,再这之前我们需要先获得csrss.exe进程的PID,然后通过其PID得到对应的EPROCESS,然后切换到对应的进程地址空间中。一种获得csrss.exe的方法是通过枚举系统中所有的句柄然后,寻找名为"\Windows\ApiPort"的ALPC port句柄然后得到其对应的进程PID(csrss.exe进程会创建一个名为"\Windows\ApiPort"的ALPC port对象)。
HANDLE GetCsrssPid()
{
HANDLE Process, hObject;
HANDLE CsrssId;
OBJECT_ATTRIBUTES obj;
CLIENT_ID cid;
UCHAR Buff[0x1000];
POBJECT_NAME_INFORMATION pObjName = (PVOID)&Buff;
PSYSTEM_HANDLE_INFORMATION_EX Handles;
Handles = QueryHandleInfo(SystemHandleInformation); //通过调用ZwQuerySystemInformation获得所有的句柄信息返回SYSTEM_HANDLE_INFORMATION_EX结构体
if (!Handles)
return CsrId;
for (ULONG i = 0; i < Handles->NumberOfHandles; i++)
{
if (Handles->Information[r].ObjectTypeNumber == 21) //ALPC Port object
{
InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
cid.UniqueThread = 0;
if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
{
if (NT_SUCCESS(ZwDuplicateObject(Process, (HANDLE)Handles->Information[r].Handle,NtCurrentProcess(), &hObject, 0, 0,DUPLICATE_SAME_ACCESS))) //将句柄复制到当前进程中
{
if (NT_SUCCESS(ZwQueryObject(hObject, ObjectNameInformation, ObjName, 0x100, NULL))) //传入参数ObjectNameInformation得到对象的名称信息
{
if (pObjName->Name.Buffer && !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20))
{
CsrssId = (HANDLE)Handles->Information[r].ProcessId;
}
}
ZwClose(hObject);
}
ZwClose(Process);
}
}
}
ExFreePool(Handles);
return CsrssId;
}
ZwQuerySystemInformation的参数SystemInformationClass等于SystemHandleInformation(16),SystemInformation会返回SYSTEM_HANDLE_INFORMATION_EX结构体,其第一个NumbreOfHandles字段为获得的句柄的总数目,然后SYSTEM_HANDLE_INFORMATION数组为各个句柄的信息。
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG NumberOfHandles;
SYSTEM_HANDLE_INFORMATION Information[1];
}SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
SYSTEM_HANDLE_INFORMATION结构包含了句柄的一些基本信息,例如所属进程PID等等。
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
}SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】