Uninformed: Informative Information for the Uninformed

Vol 3» 2006.Jan

Windows OpenProcess

In Windows, the OpenProcess function is a wrapper to the NtOpenProcess routine. NtOpenProcess is implemented in the kernel by NTOSKRNL.EXE. The function prototype for NtOpenProcess is:

NTSTATUS NtOpenProcess (OUT PHANDLE ProcessHandle,
                                               IN ACCESS_MASK DesiredAccess,
                                               IN POBJECT_ATTRIBUTES ObjectAttributes,
                                               IN PCLIENT_ID ClientId OPTIONAL)
The ClientId parameter is the actual PID that is passed by OpenProcess. This parameter is optional, but during our observation the OpenProcess function always specified a ClientId when calling NtOpenProcess.

NtOpenProcess performs three primary functions:

  1. It verifies the process exists by calling PsLookupProcessByProcessId.
  2. It attempts to open a handle to the process by calling ObOpenObjectByPointer.
  3. If it was successful opening a handle to the process, it passes the handle back to the caller.
PsLookupProcessByProcessId was the next obvious place for research. One of the outstanding questions was how does PsLookupProcessByProcessId know that a given PID is part of a valid process? The answer becomes clear in the first few lines of the disassembly:
mov edi, edi
push ebp
mov ebp, esp
push ebx
push esi
mov eax, large fs:124h
push [ebp+arg_4]
mov esi, eax
dec dword ptr [esi+0D4h]
push PspCidTable
call ExMapHandleToPointer
From the above disassembly, it is clear that ExMapHandleToPointer queries the PspCidTable for the process ID.

Now we have a complete picture of how Blacklight detects hidden processes:

  1. Blacklight starts looping through the range of valid process IDs, 0 through 0x41DC.
  2. Blacklight calls OpenProcess on every possible PID.
  3. OpenProcess calls NtOpenProcess.
  4. NtOpenProcess calls PsLookupProcessByProcessId to verify the process exists.
  5. PsLookupProcessByProcessId uses the PspCidTable to verify the processes exists.
  6. NtOpenProcess calls ObOpenObjectByPointer to get the handle to the process.
  7. If OpenProcess was successful, Blacklight stores the information about the process and continues to loop.
  8. Once the process list has been created by exhausting all possible PIDs. Blacklight compares the PIDB list with the list it creates by calling CreateToolhelp32Snapshot. CreateToolhelp32Snapshot is a Win32 API that takes a snapshot of all running processes on the system. A discrepancy between the two lists implies that there is a hidden process. This case is reported by Blacklight.