Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpeloader.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: FreeLoader 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: freeldr/winldr/peloader.c 00005 * PURPOSE: Provides routines for loading PE files. To be merged with 00006 * arch/i386/loader.c in future 00007 * This article was very handy during development: 00008 * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/ 00009 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org) 00010 * The source code in this file is based on the work of respective 00011 * authors of PE loading code in ReactOS and Brian Palmer and 00012 * Alex Ionescu's arch/i386/loader.c, and my research project 00013 * (creating a native EFI loader for Windows) 00014 */ 00015 00016 /* INCLUDES ***************************************************************/ 00017 #include <freeldr.h> 00018 #include <debug.h> 00019 00020 DBG_DEFAULT_CHANNEL(PELOADER); 00021 00022 static BOOLEAN 00023 WinLdrpCompareDllName(IN PCH DllName, 00024 IN PUNICODE_STRING UnicodeName); 00025 00026 static BOOLEAN 00027 WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead, 00028 IN PVOID DllBase, 00029 IN PVOID ImageBase, 00030 IN PIMAGE_THUNK_DATA ThunkData, 00031 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, 00032 IN ULONG ExportSize, 00033 IN BOOLEAN ProcessForwards); 00034 00035 static BOOLEAN 00036 WinLdrpLoadAndScanReferencedDll(PLIST_ENTRY ModuleListHead, 00037 PCCH DirectoryPath, 00038 PCH ImportName, 00039 PLDR_DATA_TABLE_ENTRY *DataTableEntry); 00040 00041 static BOOLEAN 00042 WinLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead, 00043 IN PVOID DllBase, 00044 IN PVOID ImageBase, 00045 IN PIMAGE_THUNK_DATA ThunkData); 00046 00047 00048 00049 /* FUNCTIONS **************************************************************/ 00050 00051 /* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */ 00052 BOOLEAN 00053 WinLdrCheckForLoadedDll(IN OUT PLIST_ENTRY ModuleListHead, 00054 IN PCH DllName, 00055 OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry) 00056 { 00057 PLDR_DATA_TABLE_ENTRY DataTableEntry; 00058 LIST_ENTRY *ModuleEntry; 00059 00060 TRACE("WinLdrCheckForLoadedDll: DllName %s, LoadedEntry: %X\n", 00061 DllName, LoadedEntry); 00062 00063 /* Just go through each entry in the LoadOrderList and compare loaded module's 00064 name with a given name */ 00065 ModuleEntry = ModuleListHead->Flink; 00066 while (ModuleEntry != ModuleListHead) 00067 { 00068 /* Get pointer to the current DTE */ 00069 DataTableEntry = CONTAINING_RECORD(ModuleEntry, 00070 LDR_DATA_TABLE_ENTRY, 00071 InLoadOrderLinks); 00072 00073 TRACE("WinLdrCheckForLoadedDll: DTE %p, EP %p, base %p name '%ws'\n", 00074 DataTableEntry, DataTableEntry->EntryPoint, DataTableEntry->DllBase, 00075 VaToPa(DataTableEntry->BaseDllName.Buffer)); 00076 00077 /* Compare names */ 00078 if (WinLdrpCompareDllName(DllName, &DataTableEntry->BaseDllName)) 00079 { 00080 /* Yes, found it, report pointer to the loaded module's DTE 00081 to the caller and increase load count for it */ 00082 *LoadedEntry = DataTableEntry; 00083 DataTableEntry->LoadCount++; 00084 TRACE("WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry); 00085 return TRUE; 00086 } 00087 00088 /* Go to the next entry */ 00089 ModuleEntry = ModuleEntry->Flink; 00090 } 00091 00092 /* Nothing found */ 00093 return FALSE; 00094 } 00095 00096 BOOLEAN 00097 WinLdrScanImportDescriptorTable(IN OUT PLIST_ENTRY ModuleListHead, 00098 IN PCCH DirectoryPath, 00099 IN PLDR_DATA_TABLE_ENTRY ScanDTE) 00100 { 00101 PLDR_DATA_TABLE_ENTRY DataTableEntry; 00102 PIMAGE_IMPORT_DESCRIPTOR ImportTable; 00103 ULONG ImportTableSize; 00104 PCH ImportName; 00105 BOOLEAN Status; 00106 00107 /* Get a pointer to the import table of this image */ 00108 ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase), 00109 TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize); 00110 00111 { 00112 UNICODE_STRING BaseName; 00113 BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer); 00114 BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength; 00115 BaseName.Length = ScanDTE->BaseDllName.Length; 00116 TRACE("WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n", 00117 &BaseName, ImportTable); 00118 } 00119 00120 /* If image doesn't have any import directory - just return success */ 00121 if (ImportTable == NULL) 00122 return TRUE; 00123 00124 /* Loop through all entries */ 00125 for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++) 00126 { 00127 /* Get pointer to the name */ 00128 ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name)); 00129 TRACE("WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName); 00130 00131 /* In case we get a reference to ourselves - just skip it */ 00132 if (WinLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName)) 00133 continue; 00134 00135 /* Load the DLL if it is not already loaded */ 00136 if (!WinLdrCheckForLoadedDll(ModuleListHead, ImportName, &DataTableEntry)) 00137 { 00138 Status = WinLdrpLoadAndScanReferencedDll(ModuleListHead, 00139 DirectoryPath, 00140 ImportName, 00141 &DataTableEntry); 00142 00143 if (!Status) 00144 { 00145 ERR("WinLdrpLoadAndScanReferencedDll() failed\n"); 00146 return Status; 00147 } 00148 } 00149 00150 /* Scan its import address table */ 00151 Status = WinLdrpScanImportAddressTable( 00152 ModuleListHead, 00153 DataTableEntry->DllBase, 00154 ScanDTE->DllBase, 00155 (PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk)); 00156 00157 if (!Status) 00158 { 00159 ERR("WinLdrpScanImportAddressTable() failed: ImportName = '%s', DirectoryPath = '%s'\n", 00160 ImportName, DirectoryPath); 00161 return Status; 00162 } 00163 } 00164 00165 return TRUE; 00166 } 00167 00168 BOOLEAN 00169 WinLdrAllocateDataTableEntry(IN OUT PLIST_ENTRY ModuleListHead, 00170 IN PCCH BaseDllName, 00171 IN PCCH FullDllName, 00172 IN PVOID BasePA, 00173 OUT PLDR_DATA_TABLE_ENTRY *NewEntry) 00174 { 00175 PVOID BaseVA = PaToVa(BasePA); 00176 PWSTR Buffer; 00177 PLDR_DATA_TABLE_ENTRY DataTableEntry; 00178 PIMAGE_NT_HEADERS NtHeaders; 00179 USHORT Length; 00180 TRACE("WinLdrAllocateDataTableEntry(, '%s', '%s', %p)\n", 00181 BaseDllName, FullDllName, BasePA); 00182 00183 /* Allocate memory for a data table entry, zero-initialize it */ 00184 DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY)); 00185 if (DataTableEntry == NULL) 00186 return FALSE; 00187 RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY)); 00188 00189 /* Get NT headers from the image */ 00190 NtHeaders = RtlImageNtHeader(BasePA); 00191 00192 /* Initialize corresponding fields of DTE based on NT headers value */ 00193 DataTableEntry->DllBase = BaseVA; 00194 DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage; 00195 DataTableEntry->EntryPoint = RVA(BaseVA, NtHeaders->OptionalHeader.AddressOfEntryPoint); 00196 DataTableEntry->SectionPointer = 0; 00197 DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum; 00198 00199 /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName 00200 by simple conversion - copying each character */ 00201 Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR)); 00202 Buffer = (PWSTR)MmHeapAlloc(Length); 00203 if (Buffer == NULL) 00204 { 00205 MmHeapFree(DataTableEntry); 00206 return FALSE; 00207 } 00208 RtlZeroMemory(Buffer, Length); 00209 00210 DataTableEntry->BaseDllName.Length = Length; 00211 DataTableEntry->BaseDllName.MaximumLength = Length; 00212 DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer); 00213 while (*BaseDllName != 0) 00214 { 00215 *Buffer++ = *BaseDllName++; 00216 } 00217 00218 /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName 00219 using the same method */ 00220 Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR)); 00221 Buffer = (PWSTR)MmHeapAlloc(Length); 00222 if (Buffer == NULL) 00223 { 00224 MmHeapFree(DataTableEntry); 00225 return FALSE; 00226 } 00227 RtlZeroMemory(Buffer, Length); 00228 00229 DataTableEntry->FullDllName.Length = Length; 00230 DataTableEntry->FullDllName.MaximumLength = Length; 00231 DataTableEntry->FullDllName.Buffer = PaToVa(Buffer); 00232 while (*FullDllName != 0) 00233 { 00234 *Buffer++ = *FullDllName++; 00235 } 00236 00237 /* Initialize what's left - LoadCount which is 1, and set Flags so that 00238 we know this entry is processed */ 00239 DataTableEntry->Flags = LDRP_ENTRY_PROCESSED; 00240 DataTableEntry->LoadCount = 1; 00241 00242 /* Insert this DTE to a list in the LPB */ 00243 InsertTailList(ModuleListHead, &DataTableEntry->InLoadOrderLinks); 00244 TRACE("Inserting DTE %p, name='%S' DllBase=%p \n", DataTableEntry, 00245 DataTableEntry->BaseDllName.Buffer, DataTableEntry->DllBase); 00246 00247 /* Save pointer to a newly allocated and initialized entry */ 00248 *NewEntry = DataTableEntry; 00249 00250 /* Return success */ 00251 return TRUE; 00252 } 00253 00254 /* WinLdrLoadImage loads the specified image from the file (it doesn't 00255 perform any additional operations on the filename, just directly 00256 calls the file I/O routines), and relocates it so that it's ready 00257 to be used when paging is enabled. 00258 Addressing mode: physical 00259 */ 00260 BOOLEAN 00261 WinLdrLoadImage(IN PCHAR FileName, 00262 TYPE_OF_MEMORY MemoryType, 00263 OUT PVOID *ImageBasePA) 00264 { 00265 ULONG FileId; 00266 PVOID PhysicalBase; 00267 PVOID VirtualBase = NULL; 00268 UCHAR HeadersBuffer[SECTOR_SIZE * 2]; 00269 PIMAGE_NT_HEADERS NtHeaders; 00270 PIMAGE_SECTION_HEADER SectionHeader; 00271 ULONG VirtualSize, SizeOfRawData, NumberOfSections; 00272 LONG Status; 00273 LARGE_INTEGER Position; 00274 ULONG i, BytesRead; 00275 TRACE("WinLdrLoadImage(%s, %ld, *)\n", FileName, MemoryType); 00276 00277 /* Open the image file */ 00278 Status = ArcOpen(FileName, OpenReadOnly, &FileId); 00279 if (Status != ESUCCESS) 00280 { 00281 //UiMessageBox("Can not open the file"); 00282 return FALSE; 00283 } 00284 00285 /* Load the first 2 sectors of the image so we can read the PE header */ 00286 Status = ArcRead(FileId, HeadersBuffer, SECTOR_SIZE * 2, &BytesRead); 00287 if (Status != ESUCCESS) 00288 { 00289 UiMessageBox("Error reading from file"); 00290 ArcClose(FileId); 00291 return FALSE; 00292 } 00293 00294 /* Now read the MZ header to get the offset to the PE Header */ 00295 NtHeaders = RtlImageNtHeader(HeadersBuffer); 00296 00297 if (!NtHeaders) 00298 { 00299 //Print(L"Error - no NT header found in %s\n", FileName); 00300 UiMessageBox("Error - no NT header found"); 00301 ArcClose(FileId); 00302 return FALSE; 00303 } 00304 00305 /* Ensure this is executable image */ 00306 if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0)) 00307 { 00308 //Print(L"Not an executable image %s\n", FileName); 00309 UiMessageBox("Not an executable image"); 00310 ArcClose(FileId); 00311 return FALSE; 00312 } 00313 00314 /* Store number of sections to read and a pointer to the first section */ 00315 NumberOfSections = NtHeaders->FileHeader.NumberOfSections; 00316 SectionHeader = IMAGE_FIRST_SECTION(NtHeaders); 00317 00318 /* Try to allocate this memory, if fails - allocate somewhere else */ 00319 PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage, 00320 (PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)), 00321 MemoryType); 00322 00323 if (PhysicalBase == NULL) 00324 { 00325 /* It's ok, we don't panic - let's allocate again at any other "low" place */ 00326 PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType); 00327 00328 if (PhysicalBase == NULL) 00329 { 00330 //Print(L"Failed to alloc pages for image %s\n", FileName); 00331 UiMessageBox("Failed to alloc pages for image"); 00332 ArcClose(FileId); 00333 return FALSE; 00334 } 00335 } 00336 00337 /* This is the real image base - in form of a virtual address */ 00338 VirtualBase = PaToVa(PhysicalBase); 00339 00340 TRACE("Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase); 00341 00342 /* Set to 0 position and fully load the file image */ 00343 Position.HighPart = Position.LowPart = 0; 00344 Status = ArcSeek(FileId, &Position, SeekAbsolute); 00345 if (Status != ESUCCESS) 00346 { 00347 UiMessageBox("Error seeking to start of file"); 00348 ArcClose(FileId); 00349 return FALSE; 00350 } 00351 00352 Status = ArcRead(FileId, PhysicalBase, NtHeaders->OptionalHeader.SizeOfHeaders, &BytesRead); 00353 00354 if (Status != ESUCCESS) 00355 { 00356 //Print(L"Error reading headers %s\n", FileName); 00357 UiMessageBox("Error reading headers"); 00358 ArcClose(FileId); 00359 return FALSE; 00360 } 00361 00362 /* Reload the NT Header */ 00363 NtHeaders = RtlImageNtHeader(PhysicalBase); 00364 00365 /* Load the first section */ 00366 SectionHeader = IMAGE_FIRST_SECTION(NtHeaders); 00367 00368 /* Fill output parameters */ 00369 *ImageBasePA = PhysicalBase; 00370 00371 /* Walk through each section and read it (check/fix any possible 00372 bad situations, if they arise) */ 00373 for (i = 0; i < NumberOfSections; i++) 00374 { 00375 VirtualSize = SectionHeader->Misc.VirtualSize; 00376 SizeOfRawData = SectionHeader->SizeOfRawData; 00377 00378 /* Handle a case when VirtualSize equals 0 */ 00379 if (VirtualSize == 0) 00380 VirtualSize = SizeOfRawData; 00381 00382 /* If PointerToRawData is 0, then force its size to be also 0 */ 00383 if (SectionHeader->PointerToRawData == 0) 00384 { 00385 SizeOfRawData = 0; 00386 } 00387 else 00388 { 00389 /* Cut the loaded size to the VirtualSize extents */ 00390 if (SizeOfRawData > VirtualSize) 00391 SizeOfRawData = VirtualSize; 00392 } 00393 00394 /* Actually read the section (if its size is not 0) */ 00395 if (SizeOfRawData != 0) 00396 { 00397 /* Seek to the correct position */ 00398 Position.LowPart = SectionHeader->PointerToRawData; 00399 Status = ArcSeek(FileId, &Position, SeekAbsolute); 00400 00401 TRACE("SH->VA: 0x%X\n", SectionHeader->VirtualAddress); 00402 00403 /* Read this section from the file, size = SizeOfRawData */ 00404 Status = ArcRead(FileId, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress, SizeOfRawData, &BytesRead); 00405 00406 if (Status != ESUCCESS) 00407 { 00408 ERR("WinLdrLoadImage(): Error reading section from file!\n"); 00409 break; 00410 } 00411 } 00412 00413 /* Size of data is less than the virtual size - fill up the remainder with zeroes */ 00414 if (SizeOfRawData < VirtualSize) 00415 { 00416 TRACE("WinLdrLoadImage(): SORD %d < VS %d\n", SizeOfRawData, VirtualSize); 00417 RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG_PTR)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData); 00418 } 00419 00420 SectionHeader++; 00421 } 00422 00423 /* We are done with the file - close it */ 00424 ArcClose(FileId); 00425 00426 /* If loading failed - return right now */ 00427 if (Status != ESUCCESS) 00428 return FALSE; 00429 00430 00431 /* Relocate the image, if it needs it */ 00432 if (NtHeaders->OptionalHeader.ImageBase != (ULONG_PTR)VirtualBase) 00433 { 00434 WARN("Relocating %p -> %p\n", NtHeaders->OptionalHeader.ImageBase, 00435 VirtualBase); 00436 return (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase, 00437 (ULONG_PTR)VirtualBase - (ULONG_PTR)PhysicalBase, 00438 "FreeLdr", 00439 TRUE, 00440 TRUE, /* in case of conflict still return success */ 00441 FALSE); 00442 } 00443 00444 TRACE("WinLdrLoadImage() done, PA = %p\n", *ImageBasePA); 00445 return TRUE; 00446 } 00447 00448 /* PRIVATE FUNCTIONS *******************************************************/ 00449 00450 /* DllName - physical, UnicodeString->Buffer - virtual */ 00451 static BOOLEAN 00452 WinLdrpCompareDllName(IN PCH DllName, 00453 IN PUNICODE_STRING UnicodeName) 00454 { 00455 PWSTR Buffer; 00456 UNICODE_STRING UnicodeNamePA; 00457 SIZE_T i, Length; 00458 00459 /* First obvious check: for length of two names */ 00460 Length = strlen(DllName); 00461 00462 UnicodeNamePA.Length = UnicodeName->Length; 00463 UnicodeNamePA.MaximumLength = UnicodeName->MaximumLength; 00464 UnicodeNamePA.Buffer = VaToPa(UnicodeName->Buffer); 00465 TRACE("WinLdrpCompareDllName: %s and %wZ, Length = %d " 00466 "UN->Length %d\n", DllName, &UnicodeNamePA, Length, UnicodeName->Length); 00467 00468 if ((Length * sizeof(WCHAR)) > UnicodeName->Length) 00469 return FALSE; 00470 00471 /* Store pointer to unicode string's buffer */ 00472 Buffer = VaToPa(UnicodeName->Buffer); 00473 00474 /* Loop character by character */ 00475 for (i = 0; i < Length; i++) 00476 { 00477 /* Compare two characters, uppercasing them */ 00478 if (toupper(*DllName) != toupper((CHAR)*Buffer)) 00479 return FALSE; 00480 00481 /* Move to the next character */ 00482 DllName++; 00483 Buffer++; 00484 } 00485 00486 /* Check, if strings either fully match, or match till the "." (w/o extension) */ 00487 if ((UnicodeName->Length == Length * sizeof(WCHAR)) || (*Buffer == L'.')) 00488 { 00489 /* Yes they do */ 00490 return TRUE; 00491 } 00492 00493 /* Strings don't match, return FALSE */ 00494 return FALSE; 00495 } 00496 00497 static BOOLEAN 00498 WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead, 00499 IN PVOID DllBase, 00500 IN PVOID ImageBase, 00501 IN PIMAGE_THUNK_DATA ThunkData, 00502 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, 00503 IN ULONG ExportSize, 00504 IN BOOLEAN ProcessForwards) 00505 { 00506 ULONG Ordinal; 00507 PULONG NameTable, FunctionTable; 00508 PUSHORT OrdinalTable; 00509 LONG High, Low, Middle, Result; 00510 ULONG Hint; 00511 PIMAGE_IMPORT_BY_NAME ImportData; 00512 PCHAR ExportName; 00513 00514 //TRACE("WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n", 00515 // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards); 00516 00517 /* Check passed DllBase param */ 00518 if(DllBase == NULL) 00519 { 00520 WARN("DllBase == NULL!\n"); 00521 return FALSE; 00522 } 00523 00524 /* Convert all non-critical pointers to PA from VA */ 00525 ThunkData = VaToPa(ThunkData); 00526 00527 /* Is the reference by ordinal? */ 00528 if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards) 00529 { 00530 /* Yes, calculate the ordinal */ 00531 Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base); 00532 //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal); 00533 } 00534 else 00535 { 00536 /* It's reference by name, we have to look it up in the export directory */ 00537 if (!ProcessForwards) 00538 { 00539 /* AddressOfData in thunk entry will become a virtual address (from relative) */ 00540 //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData); 00541 ThunkData->u1.AddressOfData = 00542 (ULONG_PTR)RVA(ImageBase, ThunkData->u1.AddressOfData); 00543 //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData); 00544 } 00545 00546 /* Get the import name */ 00547 ImportData = VaToPa((PVOID)ThunkData->u1.AddressOfData); 00548 00549 /* Get pointers to Name and Ordinal tables (RVA -> VA) */ 00550 NameTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames)); 00551 OrdinalTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals)); 00552 00553 //TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n", 00554 // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals); 00555 00556 /* Get the hint, convert it to a physical pointer */ 00557 Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint; 00558 //TRACE("HintIndex %d\n", Hint); 00559 00560 /* Get the export name from the hint */ 00561 ExportName = VaToPa(RVA(DllBase, NameTable[Hint])); 00562 00563 /* If Hint is less than total number of entries in the export directory, 00564 and import name == export name, then we can just get it from the OrdinalTable */ 00565 if ((Hint < ExportDirectory->NumberOfNames) && 00566 (strcmp(ExportName, (PCHAR)ImportData->Name) == 0)) 00567 { 00568 Ordinal = OrdinalTable[Hint]; 00569 //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal); 00570 } 00571 else 00572 { 00573 /* It's not the easy way, we have to lookup import name in the name table. 00574 Let's use a binary search for this task. */ 00575 00576 //TRACE("WinLdrpBindImportName() looking up the import name using binary search...\n"); 00577 00578 /* Low boundary is set to 0, and high boundary to the maximum index */ 00579 Low = 0; 00580 High = ExportDirectory->NumberOfNames - 1; 00581 00582 /* Perform a binary-search loop */ 00583 while (High >= Low) 00584 { 00585 /* Divide by 2 by shifting to the right once */ 00586 Middle = (Low + High) / 2; 00587 00588 /* Get the name from the name table */ 00589 ExportName = VaToPa(RVA(DllBase, NameTable[Middle])); 00590 00591 /* Compare the names */ 00592 Result = strcmp(ExportName, (PCHAR)ImportData->Name); 00593 00594 /*TRACE("Binary search: comparing Import '__', Export '%s'\n",*/ 00595 /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/ 00596 /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));*/ 00597 00598 /*TRACE("TE->u1.AOD %p, fulladdr %p\n", 00599 ThunkData->u1.AddressOfData, 00600 ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );*/ 00601 00602 00603 /* Depending on result of strcmp, perform different actions */ 00604 if (Result > 0) 00605 { 00606 /* Adjust top boundary */ 00607 High = Middle - 1; 00608 } 00609 else if (Result < 0) 00610 { 00611 /* Adjust bottom boundary */ 00612 Low = Middle + 1; 00613 } 00614 else 00615 { 00616 /* Yay, found it! */ 00617 break; 00618 } 00619 } 00620 00621 /* If high boundary is less than low boundary, then no result found */ 00622 if (High < Low) 00623 { 00624 //Print(L"Error in binary search\n"); 00625 ERR("Did not find export '%s'!\n", (PCHAR)ImportData->Name); 00626 return FALSE; 00627 } 00628 00629 /* Everything allright, get the ordinal */ 00630 Ordinal = OrdinalTable[Middle]; 00631 00632 //TRACE("WinLdrpBindImportName() found Ordinal %d\n", Ordinal); 00633 } 00634 } 00635 00636 /* Check ordinal number for validity! */ 00637 if (Ordinal >= ExportDirectory->NumberOfFunctions) 00638 { 00639 ERR("Ordinal number is invalid!\n"); 00640 return FALSE; 00641 } 00642 00643 /* Get a pointer to the function table */ 00644 FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions)); 00645 00646 /* Save a pointer to the function */ 00647 ThunkData->u1.Function = (ULONG_PTR)RVA(DllBase, FunctionTable[Ordinal]); 00648 00649 /* Is it a forwarder? (function pointer isn't within the export directory) */ 00650 if (((ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function) > (ULONG_PTR)ExportDirectory) && 00651 ((ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function) < ((ULONG_PTR)ExportDirectory + ExportSize))) 00652 { 00653 PLDR_DATA_TABLE_ENTRY DataTableEntry; 00654 CHAR ForwardDllName[255]; 00655 PIMAGE_EXPORT_DIRECTORY RefExportDirectory; 00656 ULONG RefExportSize; 00657 00658 /* Save the name of the forward dll */ 00659 RtlCopyMemory(ForwardDllName, (PCHAR)VaToPa((PVOID)ThunkData->u1.Function), sizeof(ForwardDllName)); 00660 00661 /* Strip out its extension */ 00662 *strchr(ForwardDllName,'.') = '\0'; 00663 00664 TRACE("WinLdrpBindImportName(): ForwardDllName %s\n", ForwardDllName); 00665 if (!WinLdrCheckForLoadedDll(ModuleListHead, ForwardDllName, &DataTableEntry)) 00666 { 00667 /* We can't continue if DLL couldn't be loaded, so bomb out with an error */ 00668 //Print(L"Error loading DLL!\n"); 00669 ERR("Error loading DLL!\n"); 00670 return FALSE; 00671 } 00672 00673 /* Get pointer to the export directory of loaded DLL */ 00674 RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY) 00675 RtlImageDirectoryEntryToData(VaToPa(DataTableEntry->DllBase), 00676 TRUE, 00677 IMAGE_DIRECTORY_ENTRY_EXPORT, 00678 &RefExportSize); 00679 00680 /* Fail if it's NULL */ 00681 if (RefExportDirectory) 00682 { 00683 UCHAR Buffer[128]; 00684 IMAGE_THUNK_DATA RefThunkData; 00685 PIMAGE_IMPORT_BY_NAME ImportByName; 00686 PCHAR ImportName; 00687 BOOLEAN Status; 00688 00689 /* Get pointer to the import name */ 00690 ImportName = strchr((PCHAR)VaToPa((PVOID)ThunkData->u1.Function), '.') + 1; 00691 00692 /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */ 00693 ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer; 00694 00695 /* Fill the name with the import name */ 00696 RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1); 00697 00698 /* Set Hint to 0 */ 00699 ImportByName->Hint = 0; 00700 00701 /* And finally point ThunkData's AddressOfData to that structure */ 00702 RefThunkData.u1.AddressOfData = (ULONG_PTR)ImportByName; 00703 00704 /* And recursively call ourselves */ 00705 Status = WinLdrpBindImportName( 00706 ModuleListHead, 00707 DataTableEntry->DllBase, 00708 ImageBase, 00709 &RefThunkData, 00710 RefExportDirectory, 00711 RefExportSize, 00712 TRUE); 00713 00714 /* Fill out the ThunkData with data from RefThunkData */ 00715 ThunkData->u1 = RefThunkData.u1; 00716 00717 /* Return what we got from the recursive call */ 00718 return Status; 00719 } 00720 else 00721 { 00722 /* Fail if ExportDirectory is NULL */ 00723 return FALSE; 00724 } 00725 } 00726 00727 /* Success! */ 00728 return TRUE; 00729 } 00730 00731 static BOOLEAN 00732 WinLdrpLoadAndScanReferencedDll(PLIST_ENTRY ModuleListHead, 00733 PCCH DirectoryPath, 00734 PCH ImportName, 00735 PLDR_DATA_TABLE_ENTRY *DataTableEntry) 00736 { 00737 CHAR FullDllName[256]; 00738 BOOLEAN Status; 00739 PVOID BasePA; 00740 00741 /* Prepare the full path to the file to be loaded */ 00742 strcpy(FullDllName, DirectoryPath); 00743 strcat(FullDllName, ImportName); 00744 00745 TRACE("Loading referenced DLL: %s\n", FullDllName); 00746 //Print(L"Loading referenced DLL: %s\n", FullDllName); 00747 00748 /* Load the image */ 00749 Status = WinLdrLoadImage(FullDllName, LoaderBootDriver, &BasePA); 00750 00751 if (!Status) 00752 { 00753 ERR("WinLdrLoadImage() failed\n"); 00754 return Status; 00755 } 00756 00757 /* Allocate DTE for newly loaded DLL */ 00758 Status = WinLdrAllocateDataTableEntry(ModuleListHead, 00759 ImportName, 00760 FullDllName, 00761 BasePA, 00762 DataTableEntry); 00763 00764 if (!Status) 00765 { 00766 ERR("WinLdrAllocateDataTableEntry() failed with Status=0x%X\n", Status); 00767 return Status; 00768 } 00769 00770 /* Scan its dependencies too */ 00771 TRACE("WinLdrScanImportDescriptorTable() calling ourselves for %S\n", 00772 VaToPa((*DataTableEntry)->BaseDllName.Buffer)); 00773 Status = WinLdrScanImportDescriptorTable(ModuleListHead, DirectoryPath, *DataTableEntry); 00774 00775 if (!Status) 00776 { 00777 ERR("WinLdrScanImportDescriptorTable() failed with Status=0x%X\n", Status); 00778 return Status; 00779 } 00780 00781 return TRUE; 00782 } 00783 00784 static BOOLEAN 00785 WinLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead, 00786 IN PVOID DllBase, 00787 IN PVOID ImageBase, 00788 IN PIMAGE_THUNK_DATA ThunkData) 00789 { 00790 PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL; 00791 BOOLEAN Status; 00792 ULONG ExportSize; 00793 00794 TRACE("WinLdrpScanImportAddressTable(): DllBase 0x%X, " 00795 "ImageBase 0x%X, ThunkData 0x%X\n", DllBase, ImageBase, ThunkData); 00796 00797 /* Obtain the export table from the DLL's base */ 00798 if (DllBase == NULL) 00799 { 00800 ERR("Error, DllBase == NULL!\n"); 00801 return FALSE; 00802 } 00803 else 00804 { 00805 ExportDirectory = 00806 (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(VaToPa(DllBase), 00807 TRUE, 00808 IMAGE_DIRECTORY_ENTRY_EXPORT, 00809 &ExportSize); 00810 } 00811 00812 TRACE("WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory); 00813 00814 /* If pointer to Export Directory is */ 00815 if (ExportDirectory == NULL) 00816 { 00817 ERR("DllBase=%p(%p)\n", DllBase, VaToPa(DllBase)); 00818 return FALSE; 00819 } 00820 00821 /* Go through each entry in the thunk table and bind it */ 00822 while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != 0) 00823 { 00824 /* Bind it */ 00825 Status = WinLdrpBindImportName( 00826 ModuleListHead, 00827 DllBase, 00828 ImageBase, 00829 ThunkData, 00830 ExportDirectory, 00831 ExportSize, 00832 FALSE); 00833 00834 /* Move to the next entry */ 00835 ThunkData++; 00836 00837 /* Return error if binding was unsuccessful */ 00838 if (!Status) 00839 return Status; 00840 } 00841 00842 /* Return success */ 00843 return TRUE; 00844 } Generated on Sat May 26 2012 04:18:05 for ReactOS by
1.7.6.1
|