The term 'handle' in this text refers to handles to the internel kernel32 objects, which are usually cast as type HANDLE. These objects are process related objects like processes, threads, mutexes, semaphores, sockets, files etc. Basically any handle you can close with CloseHandle(). This does NOT include GDI objects, things like HPEN, HDC, HBITMAP etc, they have almost nothing to do with kernel32 objects.
A handle, within the context of a process, is supposedly (not documented by Microsoft) the index into the processes' handle table of the entry which contains the info about the object the handle references. The handle table is a DWORD representing the number of entries in the array followed by an array of handle entries. A handle entry is a DWORD representing the access flags for the entry followed by a pointer to the actual object in memory.
typedef struct _HANDLE_TABLE { DWORD cEntries; // Max number of handles in table HANDLE_TABLE_ENTRY array[1]; // An array (number is given by cEntries) } HANDLE_TABLE, *PHANDLE_TABLE; typedef struct _HANDLE_TABLE_ENTRY { DWORD flags; // Valid flags depend on what type of object this is PVOID pObject; // Pointer to the object that the handle refers to } HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
A process ID is actually a pointer to the process structure containing the process information, xor'd with an 'obsfucator'. There are several algorythms I've seen to get this value. I'm using my own which doesn't use any undocumented calls, by calling GetCurrentProcessId() in ring 3, passing that value to a VxD which calls VWIN32_GetCurrentProcessHandle (which returns the unobfuscated pointer to the current PDB) and xor'ing the two to get the 'obsfucator' which is returned to ring 3.
A reasonable method for obtaining this value that does not use a VxD (thanks dd!) is:
DWORD _dw = 0, _dwCurProcId = GetCurrentProcessId(); __asm { mov eax,dword ptr fs:[18h] mov eax,dword ptr [eax+30h] mov ebx,eax xor ebx,dword ptr [_dwCurProcId] mov dword ptr [_dw],ebx }; Unobsfucator = _dw;
A process database structure (PDB) contains all the info about an active
process, and is in fact one of the standard 17 types of kernel32 objects.
typedef struct _PROCESS_DATABASE { DWORD Type; // 00h KERNEL32 object type (5) DWORD cReference; // 04h Number of references to process DWORD un1; // 08h DWORD someEvent; // 0Ch An event object DWORD TerminationStatus; // 10h Returned by GetExitCodeProcess DWORD un2; // 14h DWORD DefaultHeap; // 18h Address of the process heap DWORD MemoryContext; // 1Ch pointer to the process's context DWORD flags; // 20h DWORD pPSP; // 24h Linear address of PSP? WORD PSPSelector; // 28h WORD MTEIndex; // 2Ah WORD cThreads; // 2Ch WORD cNotTermThreads; // 2Eh WORD un3; // 30h WORD cRing0Threads; // 32h number of ring 0 threads HANDLE HeapHandle; // 34h Heap to allocate handle tables out of // This seems to always be the KERNEL32 heap DWORD W16TDB; // 38h Win16 Task Database selector DWORD MemMapFiles; // 3Ch memory mapped file list (?) PENVIRONMENT_DATABASE pEDB; // 40h Pointer to Environment Database PHANDLE_TABLE pHandleTable; // 44h Pointer to process handle table struct _PROCESS_DATABASE * ParentPDB; // 48h Parent process database PMODREF MODREFlist; // 4Ch Module reference list DWORD ThreadList; // 50h Threads in this process DWORD DebuggeeCB; // 54h Debuggee Context block? DWORD LocalHeapFreeHead; // 58h Head of free list in process heap DWORD InitialRing0ID; // 5Ch CRITICAL_SECTION crst; // 60h DWORD un4[2]; // 78h DWORD pConsole; // 84h Pointer to console for process DWORD tlsInUseBits1; // 88h // Represents TLS indices 0 - 31 DWORD tlsInUseBits2; // 8Ch // Represents TLS indices 32 - 63 DWORD ProcessDWORD; // 90h struct _PROCESS_DATABASE * ProcessGroup; // 94h PMODREF pExeMODREF; // 98h pointer to EXE's MODREF DWORD TopExcFilter; // 9Ch Top Exception Filter? DWORD BasePriority; // A0h Base scheduling priority for process DWORD HeapOwnList; // A4h Head of the list of process heaps DWORD HeapHandleBlockList;// A8h Pointer to head of heap handle block list DWORD pSomeHeapPtr; // ACh normally zero, but can a pointer to a // moveable handle block in the heap DWORD pConsoleProvider; // B0h Process that owns the console we're using? WORD EnvironSelector; // B4h Selector containing process environment WORD ErrorMode; // B6H SetErrorMode value (also thunks to Win16) DWORD pevtLoadFinished; // B8h Pointer to event LoadFinished? WORD UTState; // BCh } PDB, *PPDB;
All kernel32 objects (basically, anything you can get a handle for) share
a common header: The first DWORD represents the object type, and the
second DWORD represents the usage count (the number of handles
referencing the object). The types for the object types are defined as:
K32OBJ_SEMAPHORE 0x1 K32OBJ_EVENT 0x2 K32OBJ_MUTEX 0x3 K32OBJ_CRITICAL_SECTION 0x4 K32OBJ_PROCESS 0x5 K32OBJ_THREAD 0x6 K32OBJ_FILE 0x7 K32OBJ_CHANGE 0x8 K32OBJ_CONSOLE 0x9 K32OBJ_SCREEN_BUFFER 0xA K32OBJ_MEM_MAPPED_FILE 0xB K32OBJ_SERIAL 0xC K32OBJ_DEVICE_IOCTL 0xD K32OBJ_PIPE 0xE K32OBJ_MAILSLOT 0xF K32OBJ_TOOLHELP_SNAPSHOT 0x10 K32OBJ_SOCKET 0x11
To get the process ID of a process referenced by a process handle, I use GetCurrentProcessId() ^ Obsfucator to get a pointer to the current processes database structure. This structure contains a pointer at offset 44h which points to the handle table. All the objects begin with a DWORD indicating the type of the object, followed by a DWORD representing the usage count (the number of handles refering to this object). The handle should be an index into this array, and the process ID for the process refered to by the handle should be the pointer to the object xor'ed with Obsfucator. I'm fairly certain that these pointers (to the objects) are in shared memory, and handles in different processes can point to the same object in shared memory, and that there is one PDB object for each process, and that handles in different processes which refer to the same process will point to the same process structure.
On Win98, and on Win95 with some kernel upgrade, the format of the
internal objects seems to have changed. Instead of the process
object beginning with the DWORD 5 followed by the usage count, it
seems to begin with a WORD (0x0006) followed by a WORD for the usage
count, followed by a pointer to something I haven't identified.
typedef struct _newPDB { WORD Type; WORD Usage; PVOID SomePointer; ...
Most of the rest of the structure seems to be the same, but I
think something may have changed with the handle table as well. It
seems that a handle is no longer a straight index into the array, it
is four times the array index. To tell which form of the kernel
object I am looking at, I check the HIWORD of the Type DWORD for
being 0. Since all the K32OBJ Type constants are well below 0xffff,
the the HIWORD will always be 0 if it is set to one of these values,
but in the new format the HIWORD represents the usage count, which
will always be greater than 0. So, to get to a process ID for a
handle in any given process, I use the following:
DWORD GetProcessID(HANDLE hProcess, DWORD pid) { PPDB ppdb = NULL, ppdb2 = NULL; DWORD index; // check for special 'current process' value if ((DWORD)hProcess == 0x7fffffff) return pid; // initialize 'Obsfucator' by whatever method if (Unobsfucator == 0) InitUnobsfucator(); if (Unobsfucator == 0) return 0; ppdb = (PPDB)(pid ^ Unobsfucator); // get pointer to PDB if (ppdb == NULL) return 0; // make sure not null pointer // check if new format or old format if (HIWORD(ppdb->Type) == 0) // old format index = (DWORD)hProcess; // handle is straight index else // new format index = (DWORD)hProcess/4; // handle is index * 4 // make sure index is valid if (index > ppdb->pHandleTable->cEntries) return 0; // make sure not empty entry if (ppdb->pHandleTable->array[index].pObject == NULL) return 0; // point ppdb2 to object ppdb2 = (PPDB)ppdb->pHandleTable->array[index].pObject; // check for process object if (LOWORD(ppdb2->Type) != LOWORD(ppdb->Type)) return 0; return (DWORD)ppdb2 ^ Unobsfucator; }The new kernel32 object types that I've identified are:
Semaphore: 0x01 Event: 0x02 Mutex: 0x03 Critical section? Fiber? Process: 0x06 Thread: 0x07 File: 0x08 Change notify: 0x09 Console in: 0x0a New console related type? Screen buffer: 0x0c File mapping: 0x0d Serial: 0x0e VxD handle: 0x0f Unnamed Pipe: 0x10 Mailslot: 0x11 Toolhelp Snapshot: 0x12 Socket: 0x13 Waitable Timer? Job? (Win2k) Tape drive? (Win2k)
If you know anything about this change in the internal structure format such as what upgrade actually caused this change in the kernel, or any of the new formats, or anything else that may have changed also, please share the knowledge!