热烈的马
- 关注

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)
NtQuerySystemInformation
NtQuerySystemInformation函数在MSDN中有响应的解释,其主要作用是检索指定的系统信息,我们可以利用此函数便利系统中所有的进程,然后与我们要找的进程进行匹配,这个实现还是比较的容易。
实现代码
#include <Windows.h> #include <winternl.h> #include <iostream> #include <string.h> using namespace std; typedef NTSTATUS(WINAPI* _NtQuerySystemInformation)( _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, _Inout_ PVOID SystemInformation, _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength ); _NtQuerySystemInformation lNtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation"); DWORD GetPid(LPCWSTR ProcessName) { char szInfo[0x70000]; ULONG uReturnedLEngth = 0; NTSTATUS status = lNtQuerySystemInformation(SystemProcessInformation, szInfo, sizeof(szInfo), &uReturnedLEngth); PSYSTEM_PROCESS_INFORMATION pinfo = (PSYSTEM_PROCESS_INFORMATION)szInfo; HANDLE hHandle = NULL; //printf("ProcessID: %d\tprocessName: %ws \n", dwID, pImageName); while (true) { if (pinfo->NextEntryOffset == 0) { break; } pinfo = (PSYSTEM_PROCESS_INFORMATION)((PCHAR)pinfo + pinfo->NextEntryOffset); if(lstrcmpiW(pinfo->ImageName.Buffer, ProcessName) == 0) { cout << "lsass pid is:" << (DWORD)pinfo->UniqueProcessId << endl; break; } } return (DWORD)pinfo->UniqueProcessId; } int main() { DWORD pid = GetPid(L"notepad.exe"); }
WTSEnumerateProcessesW
WTSEnumerateProcessesW函数使用RPC服务来获取进程列表,我们主要关注WTS_PROCESS_INFOA结构
https://learn.microsoft.com/zh-cn/windows/win32/api/wtsapi32/ns-wtsapi32-wts_process_infoa
typedef struct _WTS_PROCESS_INFOA { DWORD SessionId; DWORD ProcessId; LPSTR pProcessName; PSID pUserSid; } WTS_PROCESS_INFOA, *PWTS_PROCESS_INFOA;
- SessionId:进程关联的会话的远程桌面服务会话标识符
- ProcessId:会话主机服务器上的进程标识符
- pProcessName:包含与进程关联的可执行文件名称
- pUserSid:进程的主要访问令牌中用户安全标识符的指针
很明显ProcessId参数即可帮助我们获得进程的pid
代码实现
#include <windows.h> #include <wtsapi32.h> #include <iostream> #pragma comment(lib, "Wtsapi32.lib") using namespace std; DWORD GetPid(LPCWSTR ProcessName) { PWTS_PROCESS_INFOW wts; DWORD Count; DWORD i = 0; BOOL result =WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wts, &Count); if(result == 0){ cout << "WTSEnumerateProcessesW Error" << endl; return 1; } cout << "WTSEnumerateProcessesW Success" << endl; for (i;i < Count; i++) { if (lstrcmpiW(wts[i].pProcessName, ProcessName) == 0) { DWORD pid = wts[i].ProcessId; cout << "lsass pid is:" << pid << endl; return pid; break; } } WTSFreeMemory(wts); } int main() { GetPid(L"notepad.exe"); }
RegQueryValueExA
在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa中,包含了本地安全机构服务器服务(LSASS)进程。LSASS进程在Windows系统中担任验证本地用户和远程用户登录,并强制执行本地安全策略的重要角色。它负责处理用户的身份验证和授权操作。
Windows 8.1及以上版本引入了LSA保护功能,其主要目的是防止未受保护的进程读取内存和进行代码注入等恶意行为。通过实施LSA保护,可以增加系统的安全性,减少恶意程序对LSASS进程的攻击能力。
在注册表路径HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa中,存在一个名为LsaPid的键。该键所对应的值即为LSASS进程的PID(进程标识符)。通过查询LsaPid键的值,可以获取LSASS进程的PID信息,有助于进行系统监控、调试或其他相关操作。
RegQueryValueExA函数主要作用就是去枚举注册表的键值对。
代码实现
#include <windows.h> #include <malloc.h> #include <iostream> #define TOTALBYTES 8192 #define BYTEINCREMENT 4096 using namespace std; int main(){ HKEY lhKey = HKEY_LOCAL_MACHINE; LPCSTR pSubKey = "SYSTEM\\CurrentControlSet\\Control\\Lsa"; HKEY hkResult; LSTATUS Open = RegOpenKeyExA(lhKey, pSubKey, 0, KEY_ALL_ACCESS, &hkResult); if (Open != ERROR_SUCCESS) { cout << "RegOpenKeyExA Error" << endl; return 1; } cout << "RegOpenKeyExA Success" << endl; DWORD BufferSize = TOTALBYTES; LPCSTR pValueName = "LsaPid"; DWORD pType = REG_DWORD; DWORD pData; DWORD pcbData = sizeof(DWORD); LSTATUS Value = RegQueryValueExA(hkResult, pValueName, NULL, &pType, (LPBYTE)&pData, &pcbData); if (Value != ERROR_SUCCESS){ cout << "RegOpenKeyExA Error" << endl; return 1; } cout << "RegQueryValueExA Success" << endl; cout << "lsass pid is:" << pData << endl; RegCloseKey(hkResult); }
QueryServiceStatusEx
QueryServiceStatusEx函数主要根据指定的信息级别检索指定服务的当前状态,详细链接如下
https://learn.microsoft.com/zh-cn/windows/win32/api/winsvc/nf-winsvc-queryservicestatusex
LSASS提供的服务
CNG KeyIsolation (KeyIso)
Security Accounts Manager (SamSs)
Credential Manager (VaultSvc)
我们可以通过打开这些服务的任意一个,来获取进程的pid。我们来看看SERVICE_STATUS_PROCESS结构
https://learn.microsoft.com/zh-cn/windows/win32/api/winsvc/ns-winsvc-service_status_process
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;
其中的DWORD dwProcessId参数即可帮助我们获得进程的pid。
代码实现
#include <windows.h> #include <iostream> using namespace std; int main() { SERVICE_STATUS_PROCESS ProcessInfo; DWORD bBufSize = sizeof(DWORD64); DWORD lpcbBytesNeeded; //建立与指定计算机上的服务控制管理器的连接,并打开指定的服务控制管理器数据库 SC_HANDLE Handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (Handle == NULL) { cout << "OpenSCManagerA Error" << endl; return 1; } cout << "OpenSCManagerA Success" << endl; //打开现有服务 SC_HANDLE Handle2 = OpenServiceW(Handle, L"VaultSvc", SC_MANAGER_ALL_ACCESS); if (Handle == NULL) { cout << "OpenServiceA Error" << endl; return 1; } cout << "OpenServiceA Success" << endl; //检索指定服务的当前状态,根据SERVICE_STATUS_PROCESS结构体获得进程信息 BOOL Query_info = QueryServiceStatusEx(Handle2, SC_STATUS_PROCESS_INFO, (LPBYTE)&ProcessInfo, sizeof(SERVICE_STATUS_PROCESS), &lpcbBytesNeeded); if (Query_info == 0) { cout << "QueryServiceStatusEx Error" << endl; return 1; } cout << "QueryServiceStatusEx Success" << endl; cout << "lsass pid is:" << (DWORD)ProcessInfo.dwProcessId << endl; CloseServiceHandle(Handle2); CloseServiceHandle(Handle); }
NtFsControlFile
NtFsControlFile例程将控制代码直接发送到指定的文件系统或文件系统筛选器驱动程序,导致相应的驱动程序执行指定的操作。
这里我们需要借助管道来获取进程的pid,管道的本质是用于进程间通信的共享内存区域,管道有两端,一个端口进程可以进行写入数据,另外一个端口进程可以进行读取数据。我们把创建管道的进行成为管道服务器,连接管道的进程成为管道客户端。
Windows管道分类
匿名管道:只能本地实现,半双工通信(即单向通信)。
命名管道:可以用于网络通信、可以对客户端连接、可以双向通信、可以在本机或者跨网络在不同进程间进行通信(即客户端可以是本地进程本地访问:.\pipe\PipeName或者远程访问远程:\ServerName\pipe\PipeName)
可以使用下面命令来查看本地管道
[System.IO.Directory]::GetFiles("\\.\pipe\") Get-ChildItem \\.\pipe\
或者使用Process Explorer,搜索\Device\NamedPipe也可以查看到
我们先连接管道,然后使用NtFsControlFile(或者GetNamedPipeServerProcessId)函数去获取指定命名管道进程的标识符。
代码实现
#include "function.h" #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) int main() { HANDLE lFileHandle; OBJECT_ATTRIBUTES Object; IO_STATUS_BLOCK Io; UNICODE_STRING lNtFileName; lRtlInitUnicodeString(&lNtFileName, L"\\Device\\NamedPipe\\lsass"); InitializeObjectAttributes(&Object, &lNtFileName, OBJ_CASE_INSENSITIVE, 0, NULL); NTSTATUS Status = lNtOpenFile(&lFileHandle, FILE_READ_ATTRIBUTES, &Object, &Io, FILE_SHARE_READ, NULL); if (!NT_SUCCESS(Status)) { cout << "NtOpenFile Error" << endl; return 1; } cout << "NtOpenFile Success" << endl; LPCSTR InputBuffer = "ServerProcessId"; DWORD OutputBuffer; lNtFsControlFile(lFileHandle, NULL, NULL, NULL, &Io, FSCTL_PIPE_GET_PIPE_ATTRIBUTE, (PVOID)InputBuffer, strlen(InputBuffer)+1, &OutputBuffer, sizeof(OutputBuffer)); if (!NT_SUCCESS(Status)) { cout << "NtFsControlFile Error" << endl; return 1; } cout << "NtFsControlFile Success" << endl; cout << "lsass pid is:" << OutputBuffer << endl; }
安全事件日志
事件4608是Windows操作系统中的一个事件日志,它表示"Windows 正在启动"。当LSASS.EXE进程启动并初始化审核子系统时,会记录此事件,其中包含着lsass进程的pid。
这里我们很显然我们需要管理员权限,实现步骤如下
使用EvtQuery函数进行事件查询:调用EvtQuery函数来查询事件,并获得一个事件查询的句柄(handle)作为返回值。
使用EvtSeek函数在结果集中查找特定事件:使用EvtSeek函数传入上一步得到的事件查询句柄,可以在结果集中查找特定事件。
利用EvtNext函数查询下一个事件:使用EvtNext函数传入事件查询句柄,可以获取查询结果集中的下一个事件。
使用EvtCreateRenderContext函数创建呈现上下文:调用EvtCreateRenderContext函数创建一个上下文对象,用于指定要从事件中呈现的信息。
使用EvtRender函数进行呈现:通过调用EvtRender函数并传入上述创建的呈现上下文,可以将事件呈现为可读的格式(如XML片段),即可获得进程pid。
代码实现
#include <windows.h> #include <winevt.h> #include <iostream> using namespace std; #pragma comment(lib, "Wevtapi.lib") DWORD IsAdmin() { HANDLE TokenHandle; BOOL OpenToken = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &TokenHandle); if (OpenToken == 0) { cout << "OpenProcessToken Error" << endl; return 1; } TOKEN_ELEVATION TokenInformation; DWORD ReturnLength; GetTokenInformation(TokenHandle, TokenElevation, &TokenInformation, sizeof(TokenInformation), &ReturnLength); DWORD isadmin = TokenInformation.TokenIsElevated; if (isadmin == 0) { cout << "Please raise process permissions" << endl; return 1; } return 0; } DWORD GetLsaPidFromEventLogs(void) { if (IsAdmin() == 1) { return 1; } DWORD dwProcessId = 0; EVT_HANDLE hResults = EvtQuery(NULL, L"Security", L"*/*[EventID=4608]", EvtQueryTolerateQueryErrors); if (hResults == NULL) { cout << "EvtQuery Error" << endl; return 1; } BOOL Result = EvtSeek(hResults, 0, NULL, 0, EvtSeekRelativeToLast); if (Result != TRUE) { cout << "EvtSeek Error" << endl; return 1; } DWORD dwReturned = 0; EVT_HANDLE hEvent; BOOL Result1 = EvtNext(hResults, 1, &hEvent, INFINITE, 0, &dwReturned); if (Result1 != TRUE) { cout << "EvtNext Error" << endl; return 1; } LPCWSTR ppValues[] = { L"Event/System/Execution/@ProcessID" }; EVT_HANDLE hContext = EvtCreateRenderContext(ARRAYSIZE(ppValues), ppValues, EvtRenderContextValues); if (hContext == NULL) { cout << "EvtCreateRenderContext Error" << endl; return 1; } EVT_VARIANT pProcessId = { 0 }; BOOL Result2 = EvtRender(hContext, hEvent, EvtRenderEventValues, sizeof(EVT_VARIANT), &pProcessId, &dwReturned, NULL); if (Result2 != TRUE) { cout << "EvtRender Error" << endl; return 1; } dwProcessId = pProcessId.UInt32Val; EvtClose(hEvent); EvtClose(hContext); EvtClose(hResults); cout << "lsass pid is:" << dwProcessId << endl; return dwProcessId; } int main() { GetLsaPidFromEventLogs(); }
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)