Red Team Notes logo Red Team Notes

We will need to enumerate, parse and be able to work with the handles and information of the processes to inject or hook them.

There are different ways to enumerate the processes of a system.

CreateToolhelp32Snapshot (Classic technique) (WinAPI)

The classic technique to find a process is by creating a snapshots with CreateToolhelp32Snapshot WINAPI. Once done we can iterate over the names in order to match to the desired one.

Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes.

If the function succeeds, it returns an open handle to the specified snapshot.

HANDLE CreateToolhelp32Snapshot(
  [in] DWORD dwFlags,
  [in] DWORD th32ProcessID
);

dwFlags=TH32CS_SNAPPROCESS -> Includes all processes in the system in the snapshot. To enumerate the processes, see Process32First, Process32Next

Final code:

#include <Windows.h>
#include <stdio.h>
#include <tlhelp32.h>

int FindProcess(const char * procname){
    int pid = 0;
    HANDLE hSnapshot;
    PROCESSENTRY32 lppe;

    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    if(INVALID_HANDLE_VALUE == hSnapshot){
        return -1;
    }
    lppe.dwSize = sizeof(PROCESSENTRY32);
    printf("Num of Processes... dwSize -> %d\n", lppe.dwSize);

    // Snapshot done!
    
    if(!Process32First(hSnapshot, &lppe)){
        CloseHandle(hSnapshot);
        return -1;
    }

    do{
        if(lstrcmpiA(procname, lppe.szExeFile)==0){
            printf("PID -> %d\t%s\n", lppe.th32ProcessID, lppe.szExeFile);
            pid = lppe.th32ProcessID;
            break;
        }
        
    }while(Process32Next(hSnapshot, &lppe));

    CloseHandle(hSnapshot);    
    return pid;
}

int main(int argc, char ** argv) {
    
    int pid;
    pid = FindProcess("notepad.exe");
    if(pid == 0){
        printf("Process Not found\n");
        return 0;
    }
    printf("pid -> %d\n", pid);
    return 0;
}

EnumProcesses (WinAPI)

EnumProcess retrieves a list with all the process identifier of the system.

BOOL EnumProcesses(
  [out] DWORD   *lpidProcess,
  [in]  DWORD   cb,
  [out] LPDWORD lpcbNeeded
);

To obtain process handles for the processes whose identifiers you have just obtained, call the OpenProcess function Once obtained the list we should open the process in order to search the process name.

HANDLE OpenProcess(
  [in] DWORD dwDesiredAccess,
  [in] BOOL  bInheritHandle,
  [in] DWORD dwProcessId
);

There are different ways to obtain the Process Name from the Handle. With GetModuleBaseNameA, QueryFullProcessImageName or GetProcessImageFileNameA. I used GetModuleBaseNameA that returns only the executable name.

#include <Windows.h>
#include <stdio.h>
#include <psapi.h>

#pragma comment(lib, "psapi.lib")

int FindProcess(const char * procname){
    int pid = 0;
    DWORD lpidProcess[1024];
    DWORD cb = sizeof(lpidProcess);
    DWORD lpcbNeeded;
    DWORD numProcesses;
    HANDLE hProc;
    TCHAR procName[1024];

    if(!EnumProcesses(lpidProcess, cb, &lpcbNeeded)){
        return -1;
    }

    // Get the processes list
    numProcesses = lpcbNeeded/sizeof(DWORD);
    for(int i=0; i<numProcesses; i++){
        // Open a Process Handle with a pid
        hProc = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, lpidProcess[i]);
        if(hProc != NULL){
            // Getting the executable name of the process handle
            if(GetModuleBaseNameA(hProc, NULL, procName, 1024) > 0){
                if (lstrcmpiA(procname, procName) == 0) {
                    pid = lpidProcess[i];
                    CloseHandle(hProc);
                    break;
                }
            }
        }
        CloseHandle(hProc);        
    }
    return pid;
}

int main(int argc, char ** argv) {
    
    int pid;
    pid = FindProcess("notepad.exe");
    if(pid == 0){
        printf("Process Not found\n");
        return 0;
    }
    printf("pid -> %d\n", pid);
    return 0;
}

WTSEnumerateProcessA (WinAPI)

We can do a process enumeration with Windows Terminal Services. WTSEnumerateProcessA retrieves information about the active processes on a specified Remote Desktop Session Host (RD Session Host) server. Authentication is required, but as we are working locally we do not.

BOOL WTSEnumerateProcessesA(
  [in]  HANDLE             hServer,
  [in]  DWORD              Reserved,
  [in]  DWORD              Version,
  [out] PWTS_PROCESS_INFOA *ppProcessInfo,
  [out] DWORD              *pCount
);

The function returns an array of WTS_PROCESS_INFOA which contains the following info:

typedef struct _WTS_PROCESS_INFOA {
  DWORD SessionId;
  DWORD ProcessId;
  LPSTR pProcessName;
  PSID  pUserSid;
} WTS_PROCESS_INFOA, *PWTS_PROCESS_INFOA;

Example of the final code:

#include <Windows.h>
#include <stdio.h>
#include <wtsapi32.h>

#pragma comment(lib, "Wtsapi32.lib")

int FindProcess(const char * procname){
    int pid = 0;
    WTS_PROCESS_INFOA * listProcesses;
    DWORD numProcesses;

    // Get a list of (WTS_PROCESS_INFOA) Process
    if (WTSEnumerateProcessesA(WTS_CURRENT_SERVER_HANDLE , 0, 1, &listProcesses, &numProcesses) == 0){
        return -1;
    }
    for(int i=0; i<numProcesses;i++){
        if (lstrcmpiA(procname, listProcesses[i].pProcessName) == 0) {
            pid = listProcesses[i].ProcessId;
            break;
        }
    }
    return pid;
}

int main(int argc, char ** argv) {
    
    int pid;
    pid = FindProcess("notepad.exe");
    if(pid <= 0){
        printf("Process Not found\n");
        return 0;
    }
    printf("pid -> %d\n", pid);
    return 0;
}

NtQuerySystemInformation (NativeAPI)

NtQuerySystemInformation retrieves the specified system information.

Note: NtQuerySystemInformation Unavailable in future versions of Windows.

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

Note: A NTAPI has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Ntdll.dll.

#include <Windows.h>
#include <stdio.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")
#define SystemProcessInformation 5

typedef NTSTATUS (NTAPI * t_NtQuerySystemInformation)(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

int FindProcess(const char * procname){
    int pid = 0;
    PVOID buffer = NULL;
    DWORD buffSize = 0;

    // Link NtQuerySystemInformation 
    t_NtQuerySystemInformation pNtQuerySystemInformation;
    pNtQuerySystemInformation = (t_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation");
    
    // Get INITIAL
    pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemProcessInformation, 0, 0, &buffSize);
    printf("BuffSize -> %d\n", buffSize);

    if(buffSize <= 0 ){
        return -1;
    }

    if (buffer = VirtualAlloc(0, buffSize, MEM_COMMIT, PAGE_READWRITE)){
        SYSTEM_PROCESS_INFORMATION * sysProc = (SYSTEM_PROCESS_INFORMATION *)buffer;
        if (!pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS) SystemProcessInformation, buffer, buffSize, &buffSize)) {
            while(TRUE){
                printf("procname = %s\n", sysProc->ImageName.Buffer);
                if (lstrcmpiW(procname, sysProc->ImageName.Buffer) == 0) {
					pid = (int) sysProc->UniqueProcessId;
					return pid;
				}
                if (!sysProc->NextEntryOffset){
					break;
                }
                sysProc = (SYSTEM_PROCESS_INFORMATION *)((ULONG_PTR) sysProc + sysProc->NextEntryOffset);
            }
        }

    }


    return pid;
}

int main(int argc, char ** argv) {
    
    int pid;
    pid = FindProcess("notepad.exe");
    if(pid == 0){
        printf("Process Not found\n");
        return 0;
    }
    printf("pid -> %d\n", pid);
    return 0;
}

NtGetNextProcess (NativeAPI)

NtGetNextProcess is an internal Windows Native API function (part of ntdll.dll) that is used to enumerate processes on the system. It is not officially documented by Microsoft and, as such, should be used with caution, as it may change in future versions of Windows.

Unlike more standard functions such as EnumProcesses or CreateToolhelp32Snapshot, which are part of the Windows API and are documented, NtGetNextProcess provides a more direct (though less secure) way to iterate over open processes on the system.

According to chatgpt :)

NTSTATUS NtGetNextProcess(
    HANDLE ProcessHandle,       // Handle of current process or NULL to begin with
    ACCESS_MASK DesiredAccess,  // Permissions required for the next process
    ULONG HandleAttributes,     // Handle attributes (optional)
    ULONG Flags,                // Additional flags (usually 0)
    PHANDLE NewProcessHandle    // Handle of the next found process
);

We can iterate through all the proceses and find the desired one. Since we don’t have the PID we can use GetProcessId to obtain the PID from a process handle.

Example of final code:

#include <Windows.h>
#include <stdio.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")

typedef NTSTATUS (NTAPI * t_NtGetNextProcess)(
    HANDLE ProcessHandle,
    ACCESS_MASK DesiredAccess,
    ULONG HandleAttributes,
    ULONG Flags,
    PHANDLE NewProcessHandle
);

int FindProcess(const char * procname){
    int pid = 0;
    HANDLE hProc;
    HANDLE hInitialProc = NULL;
    TCHAR proccessName[1024];

    // Link NtGetNextProcess 
    t_NtGetNextProcess pNtGetNextProcess;
    pNtGetNextProcess = (t_NtGetNextProcess)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtGetNextProcess");
    while(!pNtGetNextProcess(hInitialProc, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, 0, &hProc)){
        if(GetModuleBaseNameA(hProc, NULL, proccessName, 1024) > 0){
            if (lstrcmpiA(procname, proccessName) == 0) {
					pid = GetProcessId(hProc);
                    CloseHandle(hProc);
                    CloseHandle(hInitialProc);
					return pid;
				}
        }
        hInitialProc = hProc;

    
    }
    CloseHandle(hProc);
    CloseHandle(hInitialProc);
       
    return pid;
}

int main(int argc, char ** argv) {
    
    int pid;
    pid = FindProcess("notepad.exe");
    if(pid == 0){
        printf("Process Not found\n");
        return 0;
    }
    printf("pid -> %d\n", pid);
    return 0;
}