关于获取指定进程Pid的讨论
字数 2109 2025-08-06 18:08:11

获取指定进程PID的多种方法详解

前言

获取指定进程的PID是系统编程和安全研究中的常见需求。本文详细介绍了7种不同的方法,包括常规方法和一些不常见但有效的技术。

1. NtQuerySystemInformation方法

函数原型

__kernel_entry NTSTATUS NtQuerySystemInformation(
  [in]            SYSTEM_INFORMATION_CLASS SystemInformationClass,
  [in, out]       PVOID                    SystemInformation,
  [in]            ULONG                    SystemInformationLength,
  [out, optional] PULONG                   ReturnLength
);

实现步骤

  1. 调用NtQuerySystemInformation函数
  2. 设置SystemInformationClass参数为适当的进程信息类
  3. 解析返回的系统信息结构获取PID

特点

  • 是内核函数,功能强大
  • 可以获取系统级的详细信息
  • 需要正确处理缓冲区大小和返回长度

2. WTSEnumerateProcessesW方法

函数原型

BOOL WTSEnumerateProcessesW(
  [in]  HANDLE             hServer,
  [in]  DWORD              Reserved,
  [in]  DWORD              Version,
  [out] PWTS_PROCESS_INFOW *ppProcessInfo,
  [out] DWORD              *pCount
);

数据结构

typedef struct _WTS_PROCESS_INFOA {
  DWORD SessionId;
  DWORD ProcessId;
  LPSTR pProcessName;
  PSID  pUserSid;
} WTS_PROCESS_INFOA, *PWTS_PROCESS_INFOA;

实现步骤

  1. 调用WTSEnumerateProcessesW获取进程列表
  2. 遍历WTS_PROCESS_INFOW结构数组
  3. 通过ProcessId字段获取目标进程PID

特点

  • 使用RPC服务获取进程列表
  • 可以获取会话ID和用户SID等额外信息
  • 需要释放返回的进程信息内存

3. 注册表查询方法(RegQueryValueExA)

关键注册表路径

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa

相关函数

LSTATUS RegOpenKeyExA(
  [in] HKEY   hKey,
  [in] LPCSTR lpSubKey,
  [in] DWORD  ulOptions,
  [in] REGSAM samDesired,
  [out] PHKEY phkResult
);

LSTATUS RegQueryValueExA(
  [in]                HKEY    hKey,
  [in, optional]      LPCSTR  lpValueName,
  [reserved]          LPDWORD lpReserved,
  [out, optional]     LPDWORD lpType,
  [out, optional]     LPBYTE  lpData,
  [in, out, optional] LPDWORD lpcbData
);

实现步骤(以lsass.exe为例)

  1. 使用RegOpenKeyExA打开LSA注册表项
  2. 使用RegQueryValueExA查询LsaPid键值
  3. 解析返回的数据获取lsass进程PID

特点

  • 特别适用于获取系统关键进程(如lsass)的PID
  • Windows 8.1及以上版本有LSA保护机制
  • 需要管理员权限

4. 服务状态查询方法(QueryServiceStatusEx)

相关LSASS服务

  • CNG KeyIsolation (KeyIso)
  • Security Accounts Manager (SamSs)
  • Credential Manager (VaultSvc)

关键函数

SC_HANDLE OpenSCManagerW(
  [in, optional] LPCWSTR lpMachineName,
  [in, optional] LPCWSTR lpDatabaseName,
  [in]           DWORD   dwDesiredAccess
);

SC_HANDLE OpenServiceW(
  [in] SC_HANDLE hSCManager,
  [in] LPCWSTR   lpServiceName,
  [in] DWORD     dwDesiredAccess
);

BOOL QueryServiceStatusEx(
  [in]            SC_HANDLE      hService,
  [in]            SC_STATUS_TYPE InfoLevel,
  [out]           LPBYTE         lpBuffer,
  [in]            DWORD          cbBufSize,
  [out]           LPDWORD        pcbBytesNeeded
);

数据结构

typedef struct _SERVICE_STATUS_PROCESS {
  DWORD dwServiceType;
  DWORD dwCurrentState;
  DWORD dwControlsAccepted;
  DWORD dwWin32ExitCode;
  DWORD dwServiceSpecificExitCode;
  DWORD dwCheckPoint;
  DWORD dwWaitHint;
  DWORD dwProcessId;
  DWORD dwServiceFlags;
} SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;

实现步骤

  1. 使用OpenSCManagerW连接服务控制管理器
  2. 使用OpenServiceW打开目标服务
  3. 调用QueryServiceStatusEx获取服务状态
  4. SERVICE_STATUS_PROCESS结构中读取dwProcessId

特点

  • 适用于获取服务进程的PID
  • 可以获取服务的详细状态信息
  • 需要适当的访问权限

5. NtQueryInformationFile方法

关键函数

NTSTATUS NtQueryInformationFile(
  [in]  HANDLE                 FileHandle,
  [out] PIO_STATUS_BLOCK       IoStatusBlock,
  [out] PVOID                  FileInformation,
  [in]  ULONG                  Length,
  [in]  FILE_INFORMATION_CLASS FileInformationClass
);

NTSTATUS NtOpenFile(
  [out] PHANDLE            FileHandle,
  [in]  ACCESS_MASK        DesiredAccess,
  [in]  POBJECT_ATTRIBUTES ObjectAttributes,
  [out] PIO_STATUS_BLOCK   IoStatusBlock,
  [in]  ULONG              ShareAccess,
  [in]  ULONG              OpenOptions
);

枚举值

FileProcessIdsUsingFileInformation - 用于查询使用文件的进程ID

实现步骤

  1. 使用NtOpenFile打开目标进程文件(如lsass.exe)获取句柄
  2. 调用NtQueryInformationFile查询文件信息
  3. 指定FileInformationClassFileProcessIdsUsingFileInformation
  4. 解析返回的信息获取PID

特点

  • 使用未公开的内核函数
  • 需要正确处理对象属性和访问权限
  • 适用于获取特定文件(如可执行文件)关联的进程PID

6. 命名管道方法(NtFsControlFile)

关键函数

NTSTATUS NtFsControlFile(
  [in]            HANDLE           FileHandle,
  [in, optional]  HANDLE           Event,
  [in, optional]  PIO_APC_ROUTINE  ApcRoutine,
  [in, optional]  PVOID            ApcContext,
  [out]           PIO_STATUS_BLOCK IoStatusBlock,
  [in]            ULONG            FsControlCode,
  [in, optional]  PVOID            InputBuffer,
  [in]            ULONG            InputBufferLength,
  [out, optional] PVOID            OutputBuffer,
  [in]            ULONG            OutputBufferLength
);

实现步骤

  1. 创建或连接到命名管道
  2. 使用NtOpenFile获取管道文件句柄
  3. 调用NtFsControlFile发送控制代码
  4. 从输出缓冲区解析服务器进程PID

替代函数

GetNamedPipeServerProcessId - 封装了NtFsControlFile的功能

特点

  • 通过命名管道机制获取PID
  • 可以用于本地或远程进程
  • 需要正确处理管道创建和连接

7. 安全事件日志方法

相关事件

事件ID 4608 (S): Windows正在启动 - 包含lsass进程的PID

关键函数

BOOL OpenProcessToken(
  [in]  HANDLE  ProcessHandle,
  [in]  DWORD   DesiredAccess,
  [out] PHANDLE TokenHandle
);

BOOL GetTokenInformation(
  [in]            HANDLE                  TokenHandle,
  [in]            TOKEN_INFORMATION_CLASS TokenInformationClass,
  [out, optional] LPVOID                 TokenInformation,
  [in]            DWORD                  TokenInformationLength,
  [out]           PDWORD                 ReturnLength
);

EVT_HANDLE EvtQuery(
  [in] EVT_HANDLE Session,
  [in] LPCWSTR    Path,
  [in] LPCWSTR    Query,
  [in] DWORD      Flags
);

EVT_HANDLE EvtSeek(
  [in] EVT_HANDLE ResultSet,
  [in] LONGLONG   Position,
  [in] EVT_HANDLE Bookmark,
  [in] DWORD      Timeout,
  [in] DWORD      Flags
);

EVT_HANDLE EvtNext(
  [in]  EVT_HANDLE ResultSet,
  [in]  DWORD      EventArraySize,
  [out] PEVT_HANDLE EventArray,
  [in]  DWORD      Timeout,
  [in]  DWORD      Flags,
  [out] PDWORD     Returned
);

EVT_HANDLE EvtCreateRenderContext(
  [in] DWORD          ValuePathsCount,
  [in] LPCWSTR*       ValuePaths,
  [in] DWORD          Flags
);

BOOL EvtRender(
  [in]      EVT_HANDLE      Context,
  [in]      EVT_HANDLE      Fragment,
  [in]      DWORD           Flags,
  [in]      DWORD           BufferSize,
  [out]     PVOID           Buffer,
  [out]     PDWORD          BufferUsed,
  [out]     PDWORD          PropertyCount
);

实现步骤

  1. 检查管理员权限(OpenProcessToken + GetTokenInformation)
  2. 使用EvtQuery查询安全事件日志
  3. 使用EvtSeek定位到特定事件(4608)
  4. 使用EvtNext获取事件内容
  5. 创建渲染上下文(EvtCreateRenderContext)
  6. 使用EvtRender解析事件内容获取PID

特点

  • 从系统事件日志中提取信息
  • 需要管理员权限
  • 适用于获取系统关键进程启动时的PID
  • 可以获取历史记录

总结

本文详细介绍了7种获取指定进程PID的方法,每种方法各有特点和适用场景:

  1. NtQuerySystemInformation - 强大的系统级查询
  2. WTSEnumerateProcessesW - 通过RPC获取进程列表
  3. 注册表查询 - 适用于系统关键进程
  4. 服务状态查询 - 适用于服务进程
  5. NtQueryInformationFile - 通过文件对象查询
  6. 命名管道方法 - 通过进程间通信机制
  7. 安全事件日志 - 从系统日志中提取

在实际应用中,应根据具体需求和环境选择合适的方法,并考虑权限要求、系统版本兼容性等因素。对于安全敏感的操作,还需要注意避免触发防护机制。

获取指定进程PID的多种方法详解 前言 获取指定进程的PID是系统编程和安全研究中的常见需求。本文详细介绍了7种不同的方法,包括常规方法和一些不常见但有效的技术。 1. NtQuerySystemInformation方法 函数原型 实现步骤 调用 NtQuerySystemInformation 函数 设置 SystemInformationClass 参数为适当的进程信息类 解析返回的系统信息结构获取PID 特点 是内核函数,功能强大 可以获取系统级的详细信息 需要正确处理缓冲区大小和返回长度 2. WTSEnumerateProcessesW方法 函数原型 数据结构 实现步骤 调用 WTSEnumerateProcessesW 获取进程列表 遍历 WTS_PROCESS_INFOW 结构数组 通过 ProcessId 字段获取目标进程PID 特点 使用RPC服务获取进程列表 可以获取会话ID和用户SID等额外信息 需要释放返回的进程信息内存 3. 注册表查询方法(RegQueryValueExA) 关键注册表路径 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa 相关函数 实现步骤(以lsass.exe为例) 使用 RegOpenKeyExA 打开LSA注册表项 使用 RegQueryValueExA 查询 LsaPid 键值 解析返回的数据获取lsass进程PID 特点 特别适用于获取系统关键进程(如lsass)的PID Windows 8.1及以上版本有LSA保护机制 需要管理员权限 4. 服务状态查询方法(QueryServiceStatusEx) 相关LSASS服务 CNG KeyIsolation (KeyIso) Security Accounts Manager (SamSs) Credential Manager (VaultSvc) 关键函数 数据结构 实现步骤 使用 OpenSCManagerW 连接服务控制管理器 使用 OpenServiceW 打开目标服务 调用 QueryServiceStatusEx 获取服务状态 从 SERVICE_STATUS_PROCESS 结构中读取 dwProcessId 特点 适用于获取服务进程的PID 可以获取服务的详细状态信息 需要适当的访问权限 5. NtQueryInformationFile方法 关键函数 枚举值 FileProcessIdsUsingFileInformation - 用于查询使用文件的进程ID 实现步骤 使用 NtOpenFile 打开目标进程文件(如lsass.exe)获取句柄 调用 NtQueryInformationFile 查询文件信息 指定 FileInformationClass 为 FileProcessIdsUsingFileInformation 解析返回的信息获取PID 特点 使用未公开的内核函数 需要正确处理对象属性和访问权限 适用于获取特定文件(如可执行文件)关联的进程PID 6. 命名管道方法(NtFsControlFile) 关键函数 实现步骤 创建或连接到命名管道 使用 NtOpenFile 获取管道文件句柄 调用 NtFsControlFile 发送控制代码 从输出缓冲区解析服务器进程PID 替代函数 GetNamedPipeServerProcessId - 封装了 NtFsControlFile 的功能 特点 通过命名管道机制获取PID 可以用于本地或远程进程 需要正确处理管道创建和连接 7. 安全事件日志方法 相关事件 事件ID 4608 (S): Windows正在启动 - 包含lsass进程的PID 关键函数 实现步骤 检查管理员权限( OpenProcessToken + GetTokenInformation ) 使用 EvtQuery 查询安全事件日志 使用 EvtSeek 定位到特定事件(4608) 使用 EvtNext 获取事件内容 创建渲染上下文( EvtCreateRenderContext ) 使用 EvtRender 解析事件内容获取PID 特点 从系统事件日志中提取信息 需要管理员权限 适用于获取系统关键进程启动时的PID 可以获取历史记录 总结 本文详细介绍了7种获取指定进程PID的方法,每种方法各有特点和适用场景: NtQuerySystemInformation - 强大的系统级查询 WTSEnumerateProcessesW - 通过RPC获取进程列表 注册表查询 - 适用于系统关键进程 服务状态查询 - 适用于服务进程 NtQueryInformationFile - 通过文件对象查询 命名管道方法 - 通过进程间通信机制 安全事件日志 - 从系统日志中提取 在实际应用中,应根据具体需求和环境选择合适的方法,并考虑权限要求、系统版本兼容性等因素。对于安全敏感的操作,还需要注意避免触发防护机制。