You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何判断进程类型?Windows内核层区分系统与用户级进程并获取应用列表

关于Windows进程区分与任务管理器应用列表的内核层实现

刚好之前折腾过Windows 7内核驱动里的进程枚举和区分工作,来给你详细拆解这两个问题:


一、如何判断一个进程是用户交互程序还是系统/后台进程?

首先得澄清:Windows官方并没有严格的「用户程序/普通进程」划分,我们常说的用户程序一般指有可视化窗口、和用户直接交互的进程,而系统/后台进程包括系统服务、无窗口的后台工具等。判断方式分用户态和内核态两种:

用户态快速判断

  • 检查进程是否有顶层可见窗口:可以用EnumWindows遍历系统中所有窗口,再通过GetWindowThreadProcessId关联到进程ID,有可见顶层窗口的基本就是用户能看到的程序。
  • 查看进程会话ID:调用ProcessIdToSessionId获取会话ID,系统核心进程(比如smss.execsrss.exe)的会话ID是0,用户登录后启动的程序会话ID通常≥1(不过部分服务也会跑到用户会话,这点要注意)。

内核态精准判断

  • 查看EPROCESS结构体的SessionId字段:会话ID为0的基本是系统级进程,会话ID≥1的属于用户会话进程。
  • 解析进程令牌:系统进程的令牌通常携带NT AUTHORITY\SYSTEM这类高权限SID,而用户程序的令牌对应的是当前登录用户的SID。可以用SeQueryInformationToken函数获取令牌的用户信息来区分。

二、Windows 7内核驱动中区分系统服务进程与用户级应用,及获取任务管理器「应用程序」栏的进程列表

先明确:任务管理器的「应用程序」栏不是所有用户进程的集合,它只展示有顶层可见窗口、且运行在用户交互桌面的进程,服务创建的窗口(哪怕有)也不会出现在这里。要在驱动里实现这个,分两步走:

1. 内核层区分系统服务进程与用户级应用

系统服务进程是由服务控制管理器(services.exe)启动的,有几个核心特征可以用来区分:

  • 父进程追溯:查看EPROCESSInheritedFromUniqueProcessId字段,父进程是services.exe的基本都是服务进程(别硬编码PID,services.exe的PID每次启动可能不一样)。
  • 会话ID:大部分服务默认运行在会话0(Windows Vista之后的会话隔离机制),而用户交互程序在用户会话(ID≥1)。
  • 令牌权限:服务进程通常使用SYSTEM令牌或专用服务令牌,用户应用则使用当前登录用户的令牌,通过PsReferencePrimaryToken获取令牌后解析SID就能区分。
  • 桌面关联:服务进程一般关联的是WinSta0\Service-0x0-xxxx$这类专用桌面,而用户应用关联的是WinSta0\Default交互桌面。

2. 获取和任务管理器「应用程序」栏一致的进程列表

要复刻这个列表,核心是筛选出有顶层可见窗口且在用户交互桌面的进程,驱动里可以这么做:

  • 检查进程的桌面关联:通过EPROCESSWindowStationDesktop字段,判断是否关联了WinSta0\Default桌面(这是用户交互的默认桌面)。
  • 验证窗口可见性:需要获取进程的顶层窗口信息,检查是否带有WS_VISIBLE样式。内核里可以通过附加到目标进程,调用win32k的内部窗口枚举函数(不过要注意,Windows 7的会话隔离意味着会话0的驱动需要切换到目标会话才能访问用户窗口)。
  • 排除系统级窗口:有些系统进程也会在用户会话创建窗口,但这类窗口通常不会被任务管理器归类到「应用程序」栏,比如explorer.exe的系统托盘窗口,需要通过窗口类名或进程名称进一步过滤。

驱动实现的注意事项

  • 操作EPROCESS时,一定要用PsLookupProcessByProcessId安全获取进程对象,别直接硬读内存,容易导致系统崩溃。
  • Windows 7的会话隔离机制会限制会话0的驱动访问用户会话资源,需要用KeStackAttachProcess附加到目标会话的进程后再操作窗口相关结构。
  • 尽量避免在驱动里直接操作注册表(比如查服务注册表项),不仅效率低,还容易触发系统安全机制。

内容的提问来源于stack exchange,提问作者MrLister

火山引擎 最新活动