EncodePointer / DecodePointer functions for KERNEL32.DLL in Windows XP/2003

kernel32-obfuscated-pointers

Update 2020/11/30: the implementation is updated here, needs to be implemented in NTDLL.DLL and redirected from KERNEL32.DLL
Update 2020/11/27: all new KERNEL32.DLL functions are maintained here now: https://rentry.co/kernel32-extras

Purpose/History

These functions are used by Windows Applications to make memory pointers more secure.

The EncodePointer / DecodePointer code used originally comes from Wine:
https://github.com/rpodgorny/wine/blob/master/libs/port/interlocked.c
https://github.com/wine-mirror/wine/blob/master/dlls/ntdll/rtl.c

Here is a essay about these functions: https://devblogs.microsoft.com/oldnewthing/20201113-00/?p=104447

These functions are implemented in NTDLL.DLL, and redirected to NTDLL.DLL in KERNEL32.DLL

Requirements

  1. A x86 version of Windows 2003 / XP SP1 with source code available: see https://rentry.co/build-win2k3
  2. Ability to execute executables built for newer versions than Windows XP SP2 / Windows Server 2003 RTM (NT 5.2): https://rentry.co/kernel32-version-unlock

Changes

  1. create the following \base\ntdll\_obfuscated_pointers.c file:
#include "ldrp.h"
#include <ntos.h>

static DWORD_PTR pointer_obfuscator;

/***********************************************************************
 * rotl_ptr (internal)
 */
#ifdef _WIN64
#define ROT_BITS 64
#else
#define ROT_BITS 32
#endif

static DWORD_PTR rotl_ptr( DWORD_PTR num, int shift )
{
    shift &= ROT_BITS - 1;
    return (num << shift) | (num >> (ROT_BITS-shift));
}

/***********************************************************************
 * rotr_ptr (internal)
 */
static DWORD_PTR rotr_ptr( DWORD_PTR num, int shift )
{
    shift &= ROT_BITS - 1;
    return (num >> shift) | (num << (ROT_BITS-shift));
}

static DWORD_PTR get_pointer_obfuscator( void )
{
    if (!pointer_obfuscator)
    {
        ULONG seed = NtGetTickCount();
        ULONG_PTR rand;
        /* generate a random value for the obfuscator */
        rand = RtlUniform( &seed );

        /* handle 64bit pointers */
        rand ^= RtlUniform( &seed ) << ((sizeof (DWORD_PTR) - sizeof (ULONG))*8);

        /* set the high bits so dereferencing obfuscated pointers will (usually) crash */
        rand |= 0xc0000000 << ((sizeof (DWORD_PTR) - sizeof (ULONG))*8);

        InterlockedCompareExchangePointer( (void**) &pointer_obfuscator, (void*) rand, NULL );
    }
    return pointer_obfuscator;
}

/*************************************************************************
 * RtlEncodePointer   [NTDLL.@]
 */
PVOID
RtlEncodePointer(
  IN PVOID Ptr
)
{
    DWORD_PTR ptrval = (DWORD_PTR) Ptr;
    DWORD_PTR cookie = get_pointer_obfuscator();
    /* http://blogs.msdn.com/b/michael_howard/archive/2006/08/16/702707.aspx */
    ptrval = (ptrval ^ cookie);
    return (PVOID)rotr_ptr(ptrval, cookie);
}

PVOID 
RtlDecodePointer(
   PVOID Ptr
)
{
    DWORD_PTR ptrval = (DWORD_PTR) Ptr;
    DWORD_PTR cookie = get_pointer_obfuscator();
    ptrval = rotl_ptr(ptrval, cookie);
    return (PVOID)(ptrval ^ cookie);
}
  1. In \base\ntdll\ntdlldef.src: add these two lines
    DecodePointer
    EncodePointer
    
  2. In \base\ntdll\daytona\sources & \base\ntdll\wow6432\sources add to SOURCES macro:
    ..\_obfuscated_pointers.c \
    
  3. Run bcz in \base\ntdll
  4. In \base\win32\client\kernel32.src add these two lines
    DecodePointer = NTDLL.RtlDecodePointer
    EncodePointer = NTDLL.RtlEncodePointer
    
  5. Run bcz in \base\win32\client
  6. Overwrite the created \base\ntdll\daytona\obj\i386\NTDLL.DLL in the C:\WINDOWS\SYSTEM32 folder of your Windows XP installation.
  7. Overwrite the created \base\win32\client\daytona\obj\i386\KERNEL32.DLL in the C:\WINDOWS\SYSTEM32 folder of your Windows XP installation.
Edit
Pub: 13 Nov 2020 17:53 UTC
Edit: 01 Dec 2020 20:03 UTC
Views: 597