[FREELDR][NTOS:MM] Add security cookie generation to FreeLoader (#6270)

* [NTOS:MM] Misc improvements for cookie generation code

- Improve support for 64 bit images
- Improve LdrpFetchAddressOfSecurityCookie code

* [FREELDR] Add security cookie generation to FreeLoader

CORE-17808
This commit is contained in:
Adam Słaboń 2024-03-27 22:33:06 +01:00 committed by GitHub
parent 36fa628605
commit fec827eeef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 124 additions and 28 deletions

View file

@ -56,3 +56,7 @@ PeLdrCheckForLoadedDll(
IN OUT PLIST_ENTRY ModuleListHead, IN OUT PLIST_ENTRY ModuleListHead,
IN PCH DllName, IN PCH DllName,
OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry); OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry);
PVOID
PeLdrInitSecurityCookie(
_In_ PLDR_DATA_TABLE_ENTRY LdrEntry);

View file

@ -27,9 +27,51 @@ DBG_DEFAULT_CHANNEL(PELOADER);
PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback = NULL; PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback = NULL;
#ifdef _WIN64
#define COOKIE_MAX 0x0000FFFFFFFFFFFFll
#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
#else
#define DEFAULT_SECURITY_COOKIE 0xBB40E64E
#endif
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
static PVOID
PeLdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
{
PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
ULONG DirSize;
PULONG_PTR Cookie = NULL;
/* Get the pointer to the config directory */
ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
TRUE,
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
&DirSize);
/* Check for sanity */
if (!ConfigDir ||
DirSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie))
{
/* Invalid directory*/
return NULL;
}
/* Now get the cookie */
Cookie = VaToPa((PULONG_PTR)ConfigDir->SecurityCookie);
/* Check this cookie */
if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
(PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage - sizeof(*Cookie))
{
Cookie = NULL;
}
/* Return validated security cookie */
return Cookie;
}
/* DllName - physical, UnicodeString->Buffer - virtual */ /* DllName - physical, UnicodeString->Buffer - virtual */
static BOOLEAN static BOOLEAN
PeLdrpCompareDllName( PeLdrpCompareDllName(
@ -386,6 +428,9 @@ PeLdrpLoadAndScanReferencedDll(
return Success; return Success;
} }
/* Init security cookie */
PeLdrInitSecurityCookie(*DataTableEntry);
(*DataTableEntry)->Flags |= LDRP_DRIVER_DEPENDENT_DLL; (*DataTableEntry)->Flags |= LDRP_DRIVER_DEPENDENT_DLL;
/* Scan its dependencies too */ /* Scan its dependencies too */
@ -473,6 +518,44 @@ PeLdrpScanImportAddressTable(
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
PVOID
PeLdrInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
{
PULONG_PTR Cookie;
ULONG_PTR NewCookie;
/* Fetch address of the cookie */
Cookie = PeLdrpFetchAddressOfSecurityCookie(VaToPa(LdrEntry->DllBase), LdrEntry->SizeOfImage);
if (!Cookie)
return NULL;
/* Check if it's a default one */
if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
(*Cookie == 0))
{
/* Generate new cookie using cookie address and time as seed */
NewCookie = (ULONG_PTR)Cookie ^ (ULONG_PTR)ArcGetRelativeTime();
#ifdef _WIN64
/* Some images expect first 16 bits to be kept clean (like in default cookie) */
if (NewCookie > COOKIE_MAX)
{
NewCookie >>= 16;
}
#endif
/* If the result is 0 or the same as we got, just add one to the default value */
if ((NewCookie == 0) || (NewCookie == *Cookie))
{
NewCookie = DEFAULT_SECURITY_COOKIE + 1;
}
/* Set the new cookie value */
*Cookie = NewCookie;
}
return Cookie;
}
/* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */ /* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
BOOLEAN BOOLEAN
PeLdrCheckForLoadedDll( PeLdrCheckForLoadedDll(

View file

@ -342,6 +342,9 @@ WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
return FALSE; return FALSE;
} }
/* Init security cookie */
PeLdrInitSecurityCookie(*DriverDTE);
// Modify any flags, if needed // Modify any flags, if needed
(*DriverDTE)->Flags |= Flags; (*DriverDTE)->Flags |= Flags;
@ -537,9 +540,12 @@ LoadModule(
/* Cleanup and bail out */ /* Cleanup and bail out */
ERR("PeLdrAllocateDataTableEntry('%s') failed\n", FullFileName); ERR("PeLdrAllocateDataTableEntry('%s') failed\n", FullFileName);
MmFreeMemory(BaseAddress); MmFreeMemory(BaseAddress);
BaseAddress = NULL; return NULL;
} }
/* Init security cookie */
PeLdrInitSecurityCookie(*Dte);
return BaseAddress; return BaseAddress;
} }

View file

@ -38,6 +38,7 @@ ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd;
ULONG_PTR MmPteCodeStart, MmPteCodeEnd; ULONG_PTR MmPteCodeStart, MmPteCodeEnd;
#ifdef _WIN64 #ifdef _WIN64
#define COOKIE_MAX 0x0000FFFFFFFFFFFFll
#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
#else #else
#define DEFAULT_SECURITY_COOKIE 0xBB40E64E #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
@ -2859,10 +2860,7 @@ LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
{ {
PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir; PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
ULONG DirSize; ULONG DirSize;
PVOID Cookie = NULL; PULONG_PTR Cookie = NULL;
/* Check NT header first */
if (!RtlImageNtHeader(BaseAddress)) return NULL;
/* Get the pointer to the config directory */ /* Get the pointer to the config directory */
ConfigDir = RtlImageDirectoryEntryToData(BaseAddress, ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
@ -2872,19 +2870,18 @@ LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
/* Check for sanity */ /* Check for sanity */
if (!ConfigDir || if (!ConfigDir ||
DirSize < FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable) || /* SEHandlerTable is after SecurityCookie */ DirSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie))
(ConfigDir->Size != DirSize))
{ {
/* Invalid directory*/ /* Invalid directory*/
return NULL; return NULL;
} }
/* Now get the cookie */ /* Now get the cookie */
Cookie = (PVOID)ConfigDir->SecurityCookie; Cookie = (PULONG_PTR)ConfigDir->SecurityCookie;
/* Check this cookie */ /* Check this cookie */
if ((PCHAR)Cookie <= (PCHAR)BaseAddress || if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
(PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage) (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage - sizeof(*Cookie))
{ {
Cookie = NULL; Cookie = NULL;
} }
@ -2903,28 +2900,34 @@ LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
/* Fetch address of the cookie */ /* Fetch address of the cookie */
Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage); Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
if (Cookie) if (!Cookie)
return NULL;
/* Check if it's a default one */
if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
(*Cookie == 0))
{ {
/* Check if it's a default one */ LARGE_INTEGER Counter = KeQueryPerformanceCounter(NULL);
if ((*Cookie == DEFAULT_SECURITY_COOKIE) || /* The address should be unique */
(*Cookie == 0)) NewCookie = (ULONG_PTR)Cookie;
/* We just need a simple tick, don't care about precision and whatnot */
NewCookie ^= (ULONG_PTR)Counter.LowPart;
#ifdef _WIN64
/* Some images expect first 16 bits to be kept clean (like in default cookie) */
if (NewCookie > COOKIE_MAX)
{ {
LARGE_INTEGER Counter = KeQueryPerformanceCounter(NULL); NewCookie >>= 16;
/* The address should be unique */
NewCookie = (ULONG_PTR)Cookie;
/* We just need a simple tick, don't care about precision and whatnot */
NewCookie ^= (ULONG_PTR)Counter.LowPart;
/* If the result is 0 or the same as we got, just add one to the default value */
if ((NewCookie == 0) || (NewCookie == *Cookie))
{
NewCookie = DEFAULT_SECURITY_COOKIE + 1;
}
/* Set the new cookie value */
*Cookie = NewCookie;
} }
#endif
/* If the result is 0 or the same as we got, just add one to the default value */
if ((NewCookie == 0) || (NewCookie == *Cookie))
{
NewCookie = DEFAULT_SECURITY_COOKIE + 1;
}
/* Set the new cookie value */
*Cookie = NewCookie;
} }
return Cookie; return Cookie;