关于获取指定进程Pid的讨论
2023-6-19 09:2:19 Author: 星冥安全(查看原文) 阅读量:10 收藏

如何获取指定进程的pid这是个比较有意思的话题,本文会介绍一些常用的或不常用的方法。

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)

前言

如何获取指定进程的pid,这是一个非常有趣的话题,我们常用的方式就是拍摄快照然后进行枚举CreateToolhelp32Snapshot、Process32First、Process32Next等几个函数结合使用,本篇文章将会介绍一些常用或者不常用的其他方法。

NtQuerySystemInformation

NtQuerySystemInformation这个函数是个内核函数,MSDN上有详细的解释,让我们来看看
https://learn.microsoft.com/zh-cn/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation

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

我们来看看第一个参数,非常明了了,我们可以直接获得指定进程的pid

我们看看实现的效果

WTSEnumerateProcessesW

WTSEnumerateProcessesW函数使用RPC服务来获取进程列表。
https://learn.microsoft.com/zh-cn/windows/win32/api/wtsapi32/nf-wtsapi32-wtsenumerateprocessesw

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

我们看看WTS_PROCESS_INFOW这个结构体

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

DWORD ProcessId即可获得进程的pid
参考MSDN官方文档参数,很容易就可以实现,我们看看实现的效果

RegQueryValueExA

注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa中,包含本地安全机构服务器服务 (LSASS) 进程,其主要作用就是验证本地用户和远程用户的登录,并强制本地安全策略。Windows 8.1及其以上的版本具有LSA保护,其主要作用就是防止非受保护的进程读取内存和代码注入。 其中的LsaPid键所对应的值即是lsass进程的pid

我们来看看RegQueryValueExA函数
https://learn.microsoft.com/zh-cn/windows/win32/api/winreg/nf-winreg-regqueryvalueexa

对的就是查询注册表,这样就简单了

  • RegOpenKeyExA打开要读取的注册表的项

  • RegQueryValueExA读取注册表项中指定名称的类型和数据

QueryServiceStatusEx

LSASS提供的服务

  • CNG KeyIsolation (KeyIso)

  • Security Accounts Manager (SamSs)

  • Credential Manager (VaultSvc)
    我们通过打开这些服务的任意一个,来获取进程的pid
    我们先来看看QueryServiceStatusEx函数
    https://learn.microsoft.com/zh-cn/windows/win32/api/winsvc/nf-winsvc-queryservicestatusex

    其中参数的SERVICE_STATUS_PROCESS结构

  • OpenSCManagerW建立与指定计算机上的服务控制管理器的连接,并打开指定的服务控制管理器数据库

  • 利用OpenServiceW打开现有服务

  • QueryServiceStatusEx函数检索指定服务的当前状态

NtQueryInformationFile

我们先来看看这个函数的官方解释
https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationfile


我们来看看# FILE_INFORMATION_CLASS枚举
https://learn.microsoft.com/zh-cn/windows-hardware/drivers/ddi/wdm/ne-wdm-_file_information_class
FileProcessIdsUsingFileInformation


显示此值保留,官网不提供看不到具体结构,借助未公开函数查询


参数很明了了
主要结合NtOpenFile去打开指定文件,以获得其句柄,然后利用NtQueryInformationFile函数返回其指定句柄进程的各种信息。 没有代码基础的实现起来可能有点费劲,都用的内核函数 NtOpenFile
https://learn.microsoft.com/zh-cn/windows/win32/api/winternl/nf-winternl-ntopenfile

  • NtOpenFile函数去打开lsass.exe进程,文件对象的句柄

  • NtQueryInformationFile函数接收NtOpenFile返回的对象句柄,返回有关文件对象的各种信息

NtFsControlFile

通过命名管道去获取指定进程的pid,首先我们来了解一下什么是

Windows命名管道。
管道
本质是用于进程间通信的共享内存区域,管道有两端,一个端口进程可以进行写入数据,另外一个端口进程可以进行读取数据。我们把创建管道的进行成为管道服务器,连接管道的进程成为管道客户端。
Windows管道分类
匿名管道:只能本地实现,半双工通信(即单向通信)。
命名管道:可以用于网络通信、可以对客户端连接、可以双向通信、可以在本机或者跨网络在不同进程间进行通信(即客户端可以是本地进程本地访问:.\pipe\PipeName或者远程访问远程:\ServerName\pipe\PipeName)
本地查看管道(远程查看不讨论)

[System.IO.Directory]::GetFiles("\\.\pipe\")
Get-ChildItem \\.\pipe\


利用Process Explorer,搜索\Device\NamedPipe

Windows中利用CreateNamedPipeA函数创建一个有名称的命名管道
服务端可以使用ConnectNamedPipe函数等待客户端的连接请求
客户端可以使用CreateFile或CallNamedPipe函数进行连接
其中GetNamedPipeServerProcessId函数可以检索指定命名管道的服务器进程标识符,但是其内部最终调用的是NtFsControlFile,因此我们的思路就很清晰了
先连接管道,然后使用NtFsControlFile(或者GetNamedPipeServerProcessId)函数去获取指定命名管道进程的标识符。
NtFsControlFile
https://learn.microsoft.com/zh-CN/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntfscontrolfile

__kernel_entry NTSYSCALLAPI 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
);
  • NtOpenFile函数去打开lsass.exe进程,文件对象的句柄

  • NtFsControlFile函数获得其对象的句柄,然后函数将控制代码发送到lsass进程,通过OutputBuffer获得其pid

安全事件日志

事件4608 (S):Windows 正在启动,其中包含着lsass进程的pid。当LSASS.EXE进程启动并初始化审核子系统时,将记录此事件,通常在操作系统启动过程中生成。
https://learn.microsoft.com/zh-cn/windows/security/threat-protection/auditing/event-4608
我们需要管理员权限,因此我们可以利用OpenProcessToken、GetTokenInformation函数判断当前进程是否拥有管理员权限

  • EvtQuery函数进行查询事件,返回值为一个句柄

  • EvtSeek接收EvtQuery返回的句柄,在查询结果集中查找特定事件

  • 利用EvtNext函数查询下一个事件

  • 利用EvtCreateRenderContext函数,创建一个上下文,用于指定要呈现的事件中的信息

  • EvtRender函数根据指定的呈现上下文呈现 XML 片段,即可获得进行的pid

转载:https://forum.butian.net/share/2121作者:事与愿违欢迎大家去关注作者

欢迎师傅加入安全交流群(qq群:611901335),或者后台回复加群

如果想和我一起讨论,欢迎加入我的知识星球!!!

扫描下图加入freebuf知识大陆

师傅们点赞、转发、在看就是最大的支持

后台回复知识星球或者知识大陆也可获取加入链接(两个加其一即可)


文章来源: http://mp.weixin.qq.com/s?__biz=MzkxMDMwNDE2OQ==&mid=2247490983&idx=1&sn=3aca18b6ce28c2f4446538bc537f5c90&chksm=c12c2b61f65ba27744ac2f9051bd88f49f0d88d63954b3e7693063d09447bc616ef632956a5f#rd
如有侵权请联系:admin#unsafe.sh