I know how to use CreateToolhelp32Snapshot or EnumProcesses to enumerate processes but I was trying to experiment with different ways of doing it (I'm still learning and am trying to experiment with different ways of doing things and different ways of approaching problems).
I thought perhaps using for (DWORD i = 0; i < 1000; i++) {OpenProcess(PROCESS_VM_READ, FALSE, i)}
to iterate over the processes and if OpenProcess succeeds I know I have a valid PID. I picked 1000 just for testing purposes to limit the results. Code as follows:
VOID getProcessList() {
LPSTR procName[MAX_PATH];
HANDLE pHandle = NULL;
//try and open a handle to the process ID. Returns NULL if not a valid process ID
for (DWORD i = 0; i < 1000; i++) {
pHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, i);
//if process ID does not exist try the next one
if (pHandle == NULL) {
continue;
}
//get module name
GetModuleBaseName(pHandle, NULL, procName, MAX_PATH);
//if process exists print it's details
wprintf(L"%s %d\n", procName, i);
CloseHandle(pHandle);
}
printf("All processes enumerated");
}
int main() {
printf("Process Name Process ID\n\n");
getProcessList();
}
It works, but when compared to task manager it does not return all of the processes that are listed on task manager - only the ones that I have started (as opposed to CreateToolhelp32Snapshot which returns everything). I assume it has something to do with permissions and the PROCESS_VM_READ
permission, but I was looking through the other available permissions and couldn't find anything else to use.
It is possible to do with NtQuerySystemInformation
using the SYSTEM_PROCESS_ID_INFORMATION class. The output formatting would need some work but this gets you what you want:
#include <stdio.h>
#include <windows.h>
#include <winternl.h>
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
typedef struct _SYSTEM_PROCESS_ID_INFORMATION {
PVOID ProcessID; //PID
UNICODE_STRING ImageName; //Process name
} SYSTEM_PROCESS_ID_INFORMATION;
typedef NTSTATUS(NTAPI* pNtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass, //internal reference to systeminfoclass SYSTEM_PROCESS_ID_INFORMATION
PVOID SystemInformation, //the systeminformation we want
ULONG SystemInformationLength, //buffer to hold the information
PULONG ReturnLength
);
void getProcess(int pid) {
pNtQuerySystemInformation NtQuerySystemInformation; //handle to NtQuerySystemInformation
SYSTEM_PROCESS_ID_INFORMATION pidInfo; //SYSTEM_PROCESS_ID_INFORMATION stucture to be used
WCHAR processName[256]; //buffer to hold process name (pidInfo.ImageName.Buffer) - must be WCHAR to match PWSTR UNICODE_STRING structure
ULONG returnLength = 0; //from above - not sure what it is ?????
NTSTATUS status; //to test success
HANDLE hNtDLL; //handle for loading NTDLL.DLL
SYSTEM_INFORMATION_CLASS sysProcIdInfo = 0x58; //SYSTEM_INFORMATION_CLASS for SYSTEM_PROCESS_ID_INFORMATION
//load ntdll.dll
hNtDLL = GetModuleHandleA("ntdll.dll");
if (hNtDLL == NULL) {
printf("[!] Failed to load ntdll.dll with error %d\n", GetLastError());
return -1;
}
//get a handle to NtQuerySystemInformation
NtQuerySystemInformation = (pNtQuerySystemInformation)GetProcAddress(hNtDLL, "NtQuerySystemInformation");
if (NtQuerySystemInformation == NULL) {
printf("[!] Failed to get address of NtQuerySystemInformation with error %d\n", GetLastError());
return -1;
}
//initialize the SYSTEM_PROCESS_ID_INFORMATION structure
pidInfo.ProcessID = (PVOID)pid;
pidInfo.ImageName.Buffer = processName;
pidInfo.ImageName.Length = 0;
pidInfo.ImageName.MaximumLength = sizeof(processName);
//Query the PID for information
status = NtQuerySystemInformation(sysProcIdInfo, &pidInfo, sizeof(pidInfo), &returnLength);
if (status == STATUS_SUCCESS) {
wprintf(L"[+] The process ID %d is %s\n", pid, processName);
}
}
int main() {
for (int i = 0; i < 1000; i++) {
getProcess(i);
}
return 0;
}