[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 PCH DllName,
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;
#ifdef _WIN64
#define COOKIE_MAX 0x0000FFFFFFFFFFFFll
#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
#else
#define DEFAULT_SECURITY_COOKIE 0xBB40E64E
#endif
/* 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 */
static BOOLEAN
PeLdrpCompareDllName(
@ -386,6 +428,9 @@ PeLdrpLoadAndScanReferencedDll(
return Success;
}
/* Init security cookie */
PeLdrInitSecurityCookie(*DataTableEntry);
(*DataTableEntry)->Flags |= LDRP_DRIVER_DEPENDENT_DLL;
/* Scan its dependencies too */
@ -473,6 +518,44 @@ PeLdrpScanImportAddressTable(
/* 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 */
BOOLEAN
PeLdrCheckForLoadedDll(

View File

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

View File

@ -38,6 +38,7 @@ ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd;
ULONG_PTR MmPteCodeStart, MmPteCodeEnd;
#ifdef _WIN64
#define COOKIE_MAX 0x0000FFFFFFFFFFFFll
#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
#else
#define DEFAULT_SECURITY_COOKIE 0xBB40E64E
@ -2859,10 +2860,7 @@ LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
{
PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
ULONG DirSize;
PVOID Cookie = NULL;
/* Check NT header first */
if (!RtlImageNtHeader(BaseAddress)) return NULL;
PULONG_PTR Cookie = NULL;
/* Get the pointer to the config directory */
ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
@ -2872,19 +2870,18 @@ LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
/* Check for sanity */
if (!ConfigDir ||
DirSize < FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable) || /* SEHandlerTable is after SecurityCookie */
(ConfigDir->Size != DirSize))
DirSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie))
{
/* Invalid directory*/
return NULL;
}
/* Now get the cookie */
Cookie = (PVOID)ConfigDir->SecurityCookie;
Cookie = (PULONG_PTR)ConfigDir->SecurityCookie;
/* Check this cookie */
if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
(PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
(PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage - sizeof(*Cookie))
{
Cookie = NULL;
}
@ -2903,28 +2900,34 @@ LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
/* Fetch address of the cookie */
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 */
if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
(*Cookie == 0))
LARGE_INTEGER Counter = KeQueryPerformanceCounter(NULL);
/* 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;
#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);
/* 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;
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;