Skip to content

Commit

Permalink
[FREELDR] Add helpers for loading external PE images from FreeLdr.
Browse files Browse the repository at this point in the history
- Add global bootloader DTE list `FreeldrDTE` and module list `FrLdrModuleList`;
- Add wrapper function that also processes imports `FldrpLoadImage()`;
- Use this for scsiport.
  • Loading branch information
HBelusca committed Oct 3, 2024
1 parent cec2afe commit af94215
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 75 deletions.
112 changes: 38 additions & 74 deletions boot/freeldr/freeldr/disk/scsiport.c
Original file line number Diff line number Diff line change
Expand Up @@ -1629,109 +1629,73 @@ ScsiPortWriteRegisterUshort(
WRITE_REGISTER_USHORT(Register, Value);
}

extern char __ImageBase;

ULONG
ARC_STATUS
LoadBootDeviceDriver(VOID)
{
PIMAGE_NT_HEADERS NtHeaders;
LIST_ENTRY ModuleListHead;
PIMAGE_IMPORT_DESCRIPTOR ImportTable;
ULONG ImportTableSize;
PLDR_DATA_TABLE_ENTRY BootDdDTE, FreeldrDTE;
CHAR NtBootDdPath[MAX_PATH];
PVOID ImageBase = NULL;
ULONG (NTAPI *EntryPoint)(IN PVOID DriverObject, IN PVOID RegistryPath);
ARC_STATUS Status;
BOOLEAN Success;
PLDR_DATA_TABLE_ENTRY BootDdDTE, ScsiPortDTE;
ULONG (NTAPI *EntryPoint)(IN PVOID DriverObject, IN PVOID RegistryPath);
CHAR NtBootDdPath[MAX_PATH];

// FIXME: Must be done *INSIDE* the HAL!
#ifdef _M_IX86
HalpInitializePciStubs();
HalpInitBusHandler();
#endif

/* Initialize the loaded module list */
InitializeListHead(&ModuleListHead);

/* Create full ntbootdd.sys path */
strcpy(NtBootDdPath, FrLdrBootPath);
strcat(NtBootDdPath, "\\NTBOOTDD.SYS");

/* Load file */
Success = PeLdrLoadImage(NtBootDdPath, LoaderBootDriver, &ImageBase);
if (!Success)
if (!FreeldrDTE)
{
/* That's OK, file simply doesn't exist */
return ESUCCESS;
/* Hack to get FreeLdr PE image support initialized */
PLDR_DATA_TABLE_ENTRY DummyDTE;
Status = FldrpLoadImage("", NULL, LoaderBootDriver, &DummyDTE, NULL);
ASSERT(Status != ESUCCESS); // Function call must fail.
}

/* Allocate a DTE for ntbootdd */
Success = PeLdrAllocateDataTableEntry(&ModuleListHead, "ntbootdd.sys",
"NTBOOTDD.SYS", ImageBase, &BootDdDTE);
if (!Success)
if (!FreeldrDTE)
{
/* Cleanup and bail out */
MmFreeMemory(ImageBase);
return EIO;
/* FreeLdr PE image support could not be initialized, bail out */
return ENOEXEC;
}

/* Add the PE part of freeldr.sys to the list of loaded executables, it
contains ScsiPort* exports, imported by ntbootdd.sys */
Success = PeLdrAllocateDataTableEntry(&ModuleListHead, "scsiport.sys",
"FREELDR.SYS", &__ImageBase, &FreeldrDTE);
/*
* Add freeldr.sys to the list of loaded executables,
* it contains ScsiPort* exports, imported by ntbootdd.sys.
*/
Success = PeLdrAllocateDataTableEntry(&FrLdrModuleList,
"scsiport.sys",
"FREELDR.SYS",
VaToPa(FreeldrDTE->DllBase),
&ScsiPortDTE);
if (!Success)
{
/* Cleanup and bail out */
PeLdrFreeDataTableEntry(BootDdDTE);
MmFreeMemory(ImageBase);
return EIO;
}

/* Fix imports */
Success = PeLdrScanImportDescriptorTable(&ModuleListHead, "", BootDdDTE);
if (!Success)
/* Load the image */
Status = FldrpLoadImage(NtBootDdPath,
"ntbootdd.sys", // and FullDllName "NTBOOTDD.SYS",
LoaderBootDriver,
&BootDdDTE,
NULL /*&ImageBase*/);
if (Status != ESUCCESS)
{
/* Cleanup and bail out */
PeLdrFreeDataTableEntry(FreeldrDTE);
PeLdrFreeDataTableEntry(BootDdDTE);
MmFreeMemory(ImageBase);
return EIO;
/* That's OK, file simply doesn't exist. Cleanup and bail out. */
PeLdrFreeDataTableEntry(ScsiPortDTE);
return ESUCCESS;
}

#if 0
/* Now unlink the DTEs, they won't be valid later */
RemoveEntryList(&ScsiPortDTE->InLoadOrderLinks);
RemoveEntryList(&BootDdDTE->InLoadOrderLinks);
RemoveEntryList(&FreeldrDTE->InLoadOrderLinks);

/* Change imports to PA */
ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(BootDdDTE->DllBase),
TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
{
PIMAGE_THUNK_DATA ThunkData = (PIMAGE_THUNK_DATA)VaToPa(RVA(BootDdDTE->DllBase, ImportTable->FirstThunk));

while (((PIMAGE_THUNK_DATA)ThunkData)->u1.AddressOfData != 0)
{
ThunkData->u1.Function = (ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function);
ThunkData++;
}
}

/* Relocate image to PA */
NtHeaders = RtlImageNtHeader(VaToPa(BootDdDTE->DllBase));
if (!NtHeaders)
return EIO;
Success = (BOOLEAN)LdrRelocateImageWithBias(VaToPa(BootDdDTE->DllBase),
NtHeaders->OptionalHeader.ImageBase - (ULONG_PTR)BootDdDTE->DllBase,
"FreeLdr",
TRUE,
TRUE, /* In case of conflict still return success */
FALSE);
if (!Success)
return EIO;
#endif

/* Call the entrypoint */
/* Call the entrypoint and keep the image loaded in memory */
// FldrpStartImage(BootDdDTE);
EntryPoint = VaToPa(BootDdDTE->EntryPoint);
(*EntryPoint)(NULL, NULL);
EntryPoint(NULL, NULL);

return ESUCCESS;
}
Expand Down
2 changes: 1 addition & 1 deletion boot/freeldr/freeldr/include/disk.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,4 @@ DiskGetPartitionEntry(
/*
* SCSI support (disk/scsiport.c)
*/
ULONG LoadBootDeviceDriver(VOID);
ARC_STATUS LoadBootDeviceDriver(VOID);
21 changes: 21 additions & 0 deletions boot/freeldr/freeldr/include/peloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,24 @@ PeLdrCheckForLoadedDll(
PVOID
PeLdrInitSecurityCookie(
_In_ PLDR_DATA_TABLE_ENTRY LdrEntry);



extern LIST_ENTRY FrLdrModuleList;
extern PLDR_DATA_TABLE_ENTRY FreeldrDTE;

ARC_STATUS
FldrpLoadImage(
_In_ PCSTR ImageFilePath,
_In_opt_ PCSTR ImportName,
_In_ TYPE_OF_MEMORY MemoryType,
_Out_ PLDR_DATA_TABLE_ENTRY* ImageEntry,
_Out_opt_ PVOID* ImageBasePA);

BOOLEAN
FldrpUnloadImage(
_Inout_ PLDR_DATA_TABLE_ENTRY ImageEntry);

ARC_STATUS
FldrpStartImage(
_In_ PLDR_DATA_TABLE_ENTRY ImageEntry);
186 changes: 186 additions & 0 deletions boot/freeldr/freeldr/lib/peloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ DBG_DEFAULT_CHANNEL(PELOADER);

/* GLOBALS *******************************************************************/

LIST_ENTRY FrLdrModuleList;
PLDR_DATA_TABLE_ENTRY FreeldrDTE;

PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback = NULL;

#ifdef _WIN64
Expand All @@ -37,6 +40,44 @@ PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback = NULL;

/* PRIVATE FUNCTIONS *********************************************************/

static BOOLEAN
FrLdrInitImageSupport(VOID)
{
// extern char __ImageBase;
BOOLEAN Success;

if (FreeldrDTE)
{
/* Already initialized, bail out */
return TRUE;
}

/* Initialize the loaded module list */
InitializeListHead(&FrLdrModuleList);

/*
* Add freeldr.sys to the list of loaded executables, as it
* contains exports that may be imported by the loaded image.
* For example, ScsiPort* exports, imported by ntbootdd.sys.
*/
Success = PeLdrAllocateDataTableEntry(&FrLdrModuleList,
"freeldr.sys",
"FREELDR.SYS",
&__ImageBase,
&FreeldrDTE);
if (!Success)
{
/* Cleanup and bail out */
ERR("PeLdrAllocateDataTableEntry('%s') failed\n", "FREELDR.SYS");
return FALSE; // ENOMEM;
}

/* Now unlink the DTEs, they won't be valid later */
// RemoveEntryList(&FreeldrDTE->InLoadOrderLinks);

return Success;
}

static PVOID
PeLdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
{
Expand Down Expand Up @@ -1009,3 +1050,148 @@ PeLdrLoadImage(
MmFreeMemory(PhysicalBase);
return FALSE;
}


/**
* @brief
* External FreeLdr PE image loader.
**/
ARC_STATUS
FldrpLoadImage(
_In_ PCSTR ImageFilePath,
_In_opt_ PCSTR ImportName,
_In_ TYPE_OF_MEMORY MemoryType,
_Out_ PLDR_DATA_TABLE_ENTRY* ImageEntry,
_Out_opt_ PVOID* ImageBasePA)
{
ARC_STATUS Status;
BOOLEAN Success;
PVOID ImageBase = NULL;
PLDR_DATA_TABLE_ENTRY ImageDTE;
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_IMPORT_DESCRIPTOR ImportTable;
ULONG ImportTableSize;

/* Initialize image loading support */
// if (!FreeldrDTE)
if (!FrLdrInitImageSupport())
{
ERR("Cannot initialize Image Support\n");
return ENOEXEC;
}

/* Load the image */
Success = PeLdrLoadImage(ImageFilePath, MemoryType, &ImageBase);
if (!Success)
{
ERR("PeLdrLoadImage('%s') failed\n", ImageFilePath);
return ENOEXEC;
}

if (!ImportName)
{
/* Get the file name from the path */
ImportName = strrchr(ImageFilePath, '\\');
if (ImportName)
{
/* Name is past the path separator */
ImportName++;
}
else
{
/* No directory, just use the given path */
ImportName = ImageFilePath;
}
}

/* Allocate a DTE for it */
Success = PeLdrAllocateDataTableEntry(&FrLdrModuleList,
ImportName,
ImageFilePath,
ImageBase,
&ImageDTE);
if (!Success)
{
/* Cleanup and bail out */
ERR("PeLdrAllocateDataTableEntry('%s') failed\n", ImageFilePath);
MmFreeMemory(ImageBase);
return ENOMEM;
}

/* Reset ImageBase */
ASSERT(VaToPa(ImageDTE->DllBase) == ImageBase);
// ImageBase = VaToPa(ImageDTE->DllBase);

/* Load any other referenced DLLs for the loaded image */
Success = PeLdrScanImportDescriptorTable(&FrLdrModuleList, ""/*DirPath*/, ImageDTE);
if (!Success)
{
/* Cleanup and bail out */
ERR("PeLdrScanImportDescriptorTable('%s') failed\n", ImageFilePath);
Status = EIO;
goto Failure;
}

// /* Now unlink the DTEs, they won't be valid later */
// RemoveEntryList(&FreeldrDTE->InLoadOrderLinks);
// RemoveEntryList(&ImageDTE->InLoadOrderLinks);

/* Change imports to PA */
ImportTable =
(PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&ImportTableSize);
for (; (ImportTable->Name != 0) && (ImportTable->FirstThunk != 0); ImportTable++)
{
PIMAGE_THUNK_DATA ThunkData = (PIMAGE_THUNK_DATA)VaToPa(RVA(ImageDTE->DllBase, ImportTable->FirstThunk));

while (((PIMAGE_THUNK_DATA)ThunkData)->u1.AddressOfData != 0)
{
ThunkData->u1.Function = (ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function);
ThunkData++;
}
}

NtHeaders = RtlImageNtHeader(ImageBase);
ASSERT(NtHeaders); // PeLdrLoadImage succeeded, so the image was valid and had a header...
// ASSERT(NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC);

/* Relocate image to PA */
Success = (BOOLEAN)LdrRelocateImageWithBias(ImageBase,
NtHeaders->OptionalHeader.ImageBase - (ULONG_PTR)ImageDTE->DllBase,
"FreeLdr",
TRUE,
TRUE, /* In case of conflict still return success */
FALSE);
if (!Success)
{
Status = EIO;
goto Failure;
}

*ImageEntry = ImageDTE;
if (ImageBasePA)
*ImageBasePA = ImageBase;

return ESUCCESS;

Failure:
/* We failed, cleanup */
FldrpUnloadImage(ImageDTE);
return Status;
}

/**
* @brief
* Unload a loaded external FreeLdr PE image.
**/
BOOLEAN
FldrpUnloadImage(
_Inout_ PLDR_DATA_TABLE_ENTRY ImageEntry)
{
PVOID ImageBase = VaToPa(ImageEntry->DllBase);
PeLdrFreeDataTableEntry(ImageEntry);
MmFreeMemory(ImageBase);
return TRUE;
}

0 comments on commit af94215

Please sign in to comment.