Skip to content

Commit dfb4390

Browse files
committed
[FREELDR] peloader.c: Fix PE import binding (reactos#7537)
Use the PE import table's OriginalFirstThunk array when scanning and resolving imports during DLL binding. It points to an array of pointer-sized IMAGE_THUNK_DATA structures which describe the functions being imported. On the other hand, the FirstThunk points to an array of pointers, whose initial values are a copy of those pointed to by OriginalFirstThunk, but are replaced by the actual function pointers determined at runtime, when a DLL is loaded (see PeLdrpBindImportName() function). If we were to use the FirstThunk array to find again later the imports by name or ordinal, we would fail because these are replaced by the addresses of the corresponding functions. This fixes loading kdcom.dll from Windows XP x64 with FreeLDR when testing on ReactOS x64. ```diff (freeldr\freeldr\lib\peloader.c:498) trace: PeLdrpScanImportAddressTable() ---- Calling PeLdrpBindImportName() in a loop (freeldr\freeldr\lib\peloader.c:501) trace: *** ThunkName->u1.AddressOfData = 00000000000070F0 (freeldr\freeldr\lib\peloader.c:502) trace: *** ThunkData->u1.AddressOfData = 0000000000573780 (freeldr\freeldr\lib\peloader.c:209) trace: !!! ExportDirectory->NumberOfNames 1504 -(freeldr\freeldr\lib\peloader.c:210) trace: !!! ImportHint 0 - ExportName 'CcCanIWrite' - ImportDataName '' +(freeldr\freeldr\lib\peloader.c:210) trace: !!! ImportHint 282 - ExportName 'HalPrivateDispatchTable' - ImportDataName 'HalPrivateDispatchTable' .... -(freeldr\freeldr\lib\peloader.c:268) err: Did not find export ''! -(freeldr\freeldr\lib\peloader.c:709) err: PeLdrpScanImportAddressTable() failed: ImportName = 'ntoskrnl.exe', DirectoryPath = 'multi(0)disk(0)rdisk(0)partition(2)\ReactOS\system32\' ``` ('-': lines before the fix; '+': lines after the fix) Code has been adapted based from the following functions: ntdll/ldr/ldrpe.c!LdrpSnapThunk() and LdrpSnapIAT() ntoskrnl/mm/ARM3/sysldr.c!MiSnapThunk() and MiResolveImageReferences() References: https://devblogs.microsoft.com/oldnewthing/20231129-00/?p=109077 https://devblogs.microsoft.com/oldnewthing/20231130-00/?p=109084 https://stackoverflow.com/questions/42413937/why-pe-need-original-first-thunkoft
1 parent 576fafb commit dfb4390

File tree

1 file changed

+36
-26
lines changed

1 file changed

+36
-26
lines changed

boot/freeldr/freeldr/lib/peloader.c

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ PeLdrpBindImportName(
139139
_Inout_ PLIST_ENTRY ModuleListHead,
140140
_In_ PVOID DllBase,
141141
_In_ PVOID ImageBase,
142+
_In_ PIMAGE_THUNK_DATA ThunkName,
142143
_Inout_ PIMAGE_THUNK_DATA ThunkData,
143144
_In_ PIMAGE_EXPORT_DIRECTORY ExportDirectory,
144145
_In_ ULONG ExportSize,
@@ -155,8 +156,9 @@ PeLdrpBindImportName(
155156
PCHAR ExportName, ForwarderName;
156157
BOOLEAN Success;
157158

158-
//TRACE("PeLdrpBindImportName(): DllBase 0x%p, ImageBase 0x%p, ThunkData 0x%p, ExportDirectory 0x%p, ExportSize %d, ProcessForwards 0x%X\n",
159-
// DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards);
159+
//TRACE("PeLdrpBindImportName(): "
160+
// "DllBase 0x%p, ImageBase 0x%p, ThunkName 0x%p, ThunkData 0x%p, ExportDirectory 0x%p, ExportSize %d, ProcessForwards 0x%X\n",
161+
// DllBase, ImageBase, ThunkName, ThunkData, ExportDirectory, ExportSize, ProcessForwards);
160162

161163
/* Check passed DllBase */
162164
if (!DllBase)
@@ -166,13 +168,14 @@ PeLdrpBindImportName(
166168
}
167169

168170
/* Convert all non-critical pointers to PA from VA */
171+
ThunkName = VaToPa(ThunkName);
169172
ThunkData = VaToPa(ThunkData);
170173

171174
/* Is the reference by ordinal? */
172-
if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards)
175+
if (IMAGE_SNAP_BY_ORDINAL(ThunkName->u1.Ordinal) && !ProcessForwards)
173176
{
174177
/* Yes, calculate the ordinal */
175-
Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base);
178+
Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkName->u1.Ordinal) - (UINT32)ExportDirectory->Base);
176179
//TRACE("PeLdrpBindImportName(): Ordinal %d\n", Ordinal);
177180
}
178181
else
@@ -181,14 +184,14 @@ PeLdrpBindImportName(
181184
if (!ProcessForwards)
182185
{
183186
/* AddressOfData in thunk entry will become a virtual address (from relative) */
184-
//TRACE("PeLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData);
185-
ThunkData->u1.AddressOfData =
186-
(ULONG_PTR)RVA(ImageBase, ThunkData->u1.AddressOfData);
187-
//TRACE("PeLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData);
187+
//TRACE("PeLdrpBindImportName(): ThunkName->u1.AOD was %p\n", ThunkName->u1.AddressOfData);
188+
ThunkName->u1.AddressOfData =
189+
(ULONG_PTR)RVA(ImageBase, ThunkName->u1.AddressOfData);
190+
//TRACE("PeLdrpBindImportName(): ThunkName->u1.AOD became %p\n", ThunkName->u1.AddressOfData);
188191
}
189192

190-
/* Get the import name */
191-
ImportData = VaToPa((PVOID)ThunkData->u1.AddressOfData);
193+
/* Get the import name, convert it to a physical pointer */
194+
ImportData = VaToPa((PVOID)ThunkName->u1.AddressOfData);
192195

193196
/* Get pointers to Name and Ordinal tables (RVA -> VA) */
194197
NameTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames));
@@ -197,8 +200,8 @@ PeLdrpBindImportName(
197200
//TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
198201
// NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals);
199202

200-
/* Get the hint, convert it to a physical pointer */
201-
Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint;
203+
/* Get the hint */
204+
Hint = ImportData->Hint;
202205
//TRACE("HintIndex %d\n", Hint);
203206

204207
/* Get the export name from the hint */
@@ -358,6 +361,7 @@ PeLdrpBindImportName(
358361
DataTableEntry->DllBase,
359362
ImageBase,
360363
&RefThunkData,
364+
&RefThunkData,
361365
RefExportDirectory,
362366
RefExportSize,
363367
TRUE,
@@ -451,6 +455,7 @@ PeLdrpScanImportAddressTable(
451455
_Inout_ PLIST_ENTRY ModuleListHead,
452456
_In_ PVOID DllBase,
453457
_In_ PVOID ImageBase,
458+
_In_ PIMAGE_THUNK_DATA ThunkName,
454459
_Inout_ PIMAGE_THUNK_DATA ThunkData,
455460
_In_ PCSTR DirectoryPath,
456461
_In_ PLIST_ENTRY Parent)
@@ -460,8 +465,8 @@ PeLdrpScanImportAddressTable(
460465
ULONG ExportSize;
461466

462467
TRACE("PeLdrpScanImportAddressTable(): "
463-
"DllBase 0x%p, ImageBase 0x%p, ThunkData 0x%p\n",
464-
DllBase, ImageBase, ThunkData);
468+
"DllBase 0x%p, ImageBase 0x%p, ThunkName 0x%p, ThunkData 0x%p\n",
469+
DllBase, ImageBase, ThunkName, ThunkData);
465470

466471
/* Obtain the export table from the DLL's base */
467472
if (!DllBase)
@@ -486,26 +491,27 @@ PeLdrpScanImportAddressTable(
486491
return FALSE;
487492
}
488493

489-
/* Go through each entry in the thunk table and bind it */
490-
while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != 0)
494+
/* Go through each thunk in the table and bind it */
495+
while (((PIMAGE_THUNK_DATA)VaToPa(ThunkName))->u1.AddressOfData != 0)
491496
{
492497
/* Bind it */
493498
Success = PeLdrpBindImportName(ModuleListHead,
494499
DllBase,
495500
ImageBase,
501+
ThunkName,
496502
ThunkData,
497503
ExportDirectory,
498504
ExportSize,
499505
FALSE,
500506
DirectoryPath,
501507
Parent);
502-
503-
/* Move to the next entry */
504-
ThunkData++;
505-
506-
/* Return error if binding was unsuccessful */
508+
/* Fail if binding was unsuccessful */
507509
if (!Success)
508510
return Success;
511+
512+
/* Move to the next thunk */
513+
ThunkName++;
514+
ThunkData++;
509515
}
510516

511517
/* Return success */
@@ -649,13 +655,16 @@ PeLdrScanImportDescriptorTable(
649655
}
650656
#endif
651657

652-
/* If image doesn't have any import directory - just return success */
653-
if (ImportTable == NULL)
658+
/* If the image doesn't have any import directory, just return success */
659+
if (!ImportTable)
654660
return TRUE;
655661

656-
/* Loop through all entries */
657-
for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
662+
/* Loop through all the entries */
663+
for (;(ImportTable->Name != 0) && (ImportTable->OriginalFirstThunk != 0);ImportTable++)
658664
{
665+
PIMAGE_THUNK_DATA ThunkName = RVA(ScanDTE->DllBase, ImportTable->OriginalFirstThunk);
666+
PIMAGE_THUNK_DATA ThunkData = RVA(ScanDTE->DllBase, ImportTable->FirstThunk);
667+
659668
/* Get pointer to the name */
660669
ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name));
661670
TRACE("PeLdrScanImportDescriptorTable(): Looking at %s\n", ImportName);
@@ -683,7 +692,8 @@ PeLdrScanImportDescriptorTable(
683692
Success = PeLdrpScanImportAddressTable(ModuleListHead,
684693
DataTableEntry->DllBase,
685694
ScanDTE->DllBase,
686-
(PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk),
695+
ThunkName,
696+
ThunkData,
687697
DirectoryPath,
688698
&ScanDTE->InLoadOrderLinks);
689699

0 commit comments

Comments
 (0)