A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #30426  by grechkoed
 Fri Jun 09, 2017 2:56 pm
Sorry for the stupid question, but I'm just interested in. Why on earth process ID is always a pointer in the kernel header files and functions? In the same time process id is just a DWORD in user mode.
Code: Select all
NTSTATUS PsLookupProcessByProcessId(
  _In_  HANDLE    ProcessId,
  _Out_ PEPROCESS *Process
);
From ntdef.h
Code: Select all
typedef void *HANDLE;
Also both process ID and thread ID are pointers in CLIENT_ID structure.
Code: Select all
typedef struct _CLIENT_ID
{
     PVOID UniqueProcess;
     PVOID UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
User mode function
Code: Select all
DWORD WINAPI GetCurrentProcessId
 #30831  by fsdhook
 Fri Sep 08, 2017 4:47 pm
RING3: same as sizeof(long), 4 bytes.
RING0: same as sizeof(void*), 4 or 8 bytes.
 #30832  by Vrtule
 Fri Sep 08, 2017 5:23 pm
Sorry for the stupid question, but I'm just interested in. Why on earth process ID is always a pointer in the kernel header files and functions? In the same time process id is just a DWORD in user mode.
AFAIK the DWORDs are there due to compatibility reasons with earlier systems (Win9x/NT?). Similarly, the CreateFile API returns INVALID_HANDLE_VALUE on error, although Windows represents invalid handles by the NULL value (other OpenXXX or CreateXXX return NULL on failure).

Under the hood, process and thread IDs are handles. A handle table (same for both ID types) is used to translate them into pointers to process and thread objects (PEPROCESS/PETHREAD). I did not look to this in Windows 8+ but I doubt they changed it. And since the maximum handle value is AFAIK about 2^24, it never gets high enough to jump out of four bytes.
 #30833  by fsdhook
 Fri Sep 08, 2017 10:29 pm
Vrtule wrote:
Sorry for the stupid question, but I'm just interested in. Why on earth process ID is always a pointer in the kernel header files and functions? In the same time process id is just a DWORD in user mode.
AFAIK the DWORDs are there due to compatibility reasons with earlier systems (Win9x/NT?). Similarly, the CreateFile API returns INVALID_HANDLE_VALUE on error, although Windows represents invalid handles by the NULL value (other OpenXXX or CreateXXX return NULL on failure).

Under the hood, process and thread IDs are handles. A handle table (same for both ID types) is used to translate them into pointers to process and thread objects (PEPROCESS/PETHREAD). I did not look to this in Windows 8+ but I doubt they changed it. And since the maximum handle value is AFAIK about 2^24, it never gets high enough to jump out of four bytes.
Are you sure the maximum handle value is 2^24, but not (2^32)-1?
 #30834  by tangptr
 Sat Sep 09, 2017 12:58 am
Concordantly, the value of process id would be no more than 2^32-4. However, due to Microsoft-specific definition, it is defined to be a pointer. It would be better to understand if you analyze the structure of PspCidTable.
 #30835  by Vrtule
 Sat Sep 09, 2017 8:49 am
Are you sure the maximum handle value is 2^24, but not (2^32)-1?
It was something like that in older Windows, not sure how things stand now. Handle table is implemented as a general translation mechanism that can use a custom number of levels of translation (the process is quite similar to page tables). Maybe, the PspCidTable has a different number of levels than a regular handle table.

Also, the highest bit of the handle (bit 31) indicates whether the handle is a kernel handle (1) or user handle (0).