由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)
如何获取指定进程的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
对的就是查询注册表,这样就简单了
LSASS提供的服务
我们先来看看这个函数的官方解释
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
通过命名管道去获取指定进程的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
);
事件4608 (S):Windows 正在启动,其中包含着lsass进程的pid。当LSASS.EXE进程启动并初始化审核子系统时,将记录此事件,通常在操作系统启动过程中生成。
https://learn.microsoft.com/zh-cn/windows/security/threat-protection/auditing/event-4608
我们需要管理员权限,因此我们可以利用OpenProcessToken、GetTokenInformation函数判断当前进程是否拥有管理员权限
9 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!