← Learn

Process Enumeration

Author
Moise Medici
Updated
23 Nov 2025 · Completed

Method 3

The last method relies on NtQuerySystemInformation. Note that this function is part of an internal Windows library. It is partially undocumented, especially with respect to the structures returned, and usage is discouraged by Microsoft.

process_enumeration_3.c
#include <windows.h>
#include <winternl.h>
#include <winnt.h>
#include <stdio.h>
#include <wchar.h>
#define RET_SUCCESS 0
#define RET_ERROR -1
int main() {
ULONG retLen, sysInfoLen = 0;
PSYSTEM_PROCESS_INFORMATION procInfo = {0};
NTSTATUS STATUS = 0;
NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &retLen);
procInfo =
(PSYSTEM_PROCESS_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)retLen);
if (procInfo == NULL) {
printf("HeapAlloc failed, error %lu\n", GetLastError());
return RET_ERROR;
}
STATUS = NtQuerySystemInformation(SystemProcessInformation, procInfo, retLen, &sysInfoLen);
if (STATUS != 0x0) {
printf("NtQuerySystemInformation failed, error 0x%0.8lX\n", STATUS);
return RET_ERROR;
}
while (procInfo->NextEntryOffset) {
const UNICODE_STRING* name = &procInfo->ImageName;
if (name->Buffer) {
printf(
"Process ID: %.*ls, Executable: %lu\n",
name->MaximumLength,
name->Buffer,
(unsigned long)(ULONG_PTR)procInfo->UniqueProcessId
);
if (wcscmp(name->Buffer, L"notepad.exe") == 0) {
printf("Notepad detected. Exiting\n\n");
break;
}
}
procInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)procInfo + procInfo->NextEntryOffset);
}
return RET_SUCCESS;
}

The function signature is:

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

The first parameter indicates the information that is going to be returned. The type of argument needed is SYSTEM_INFORMATION_CLASS. Since the goal is to retrieve the list of processes, SystemProcessInformation is used, as described by Microsoft: “Returns an array of SYSTEM_PROCESS_INFORMATION structures, one for each process running in the system.

These structures contain information about the resource usage of each process, including the number of threads and handles used by the process, the peak page-file usage, and the number of memory pages that the process has allocated.”

The SYSTEM_INFORMATION_CLASS is partially documented in the appendix 12, however a more complete resource is appendix 13.

NtQuerySystemInformation is a function that needs to be called twice, the first time to populate the size of the information requested and store it in ReturnLength, and the second time to populate the SystemInformation argument.

Once the first call is completed, the heap can be reserved for an object of size ReturnLength. The second call will populate the memory space and the code can then loop over the list of structures.

Within the loop, it prints the usual PID and name string and stops if Notepad is detected. The last line of the loop is only used to move to the next structure, since it is a linked list where each structure is linked to the next one with an address stored in NextEntryOffset.