如何获取指定进程的pid这是个比较有意思的话题,本文会介绍一些常用的或不常用的方法。
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)
如何获取指定进程的pid,这是一个非常有趣的话题,我们常用的方式就是拍摄快照然后进行枚举CreateToolhelp32Snapshot、Process32First、Process32Next等几个函数结合使用,本篇文章将会介绍一些常用或者不常用的其他方法。
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函数使用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官方文档参数,很容易就可以实现,我们看看实现的效果
注册表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读取注册表项中指定名称的类型和数据
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函数检索指定服务的当前状态
我们先来看看这个函数的官方解释
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_classFileProcessIdsUsingFileInformation
显示此值保留,官网不提供看不到具体结构,借助未公开函数查询
参数很明了了
主要结合NtOpenFile去打开指定文件,以获得其句柄,然后利用NtQueryInformationFile函数返回其指定句柄进程的各种信息。 没有代码基础的实现起来可能有点费劲,都用的内核函数 NtOpenFile
https://learn.microsoft.com/zh-cn/windows/win32/api/winternl/nf-winternl-ntopenfile
NtOpenFile函数去打开lsass.exe进程,文件对象的句柄
NtQueryInformationFile函数接收NtOpenFile返回的对象句柄,返回有关文件对象的各种信息
通过命名管道去获取指定进程的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知识大陆
师傅们点赞、转发、在看就是最大的支持
后台回复知识星球或者知识大陆也可获取加入链接(两个加其一即可)