1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/ARM3/sysldr.c 5 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files. 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * ReactOS Portable Systems Group 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 #define MODULE_INVOLVED_IN_ARM3 17 #include <mm/ARM3/miarm.h> 18 19 static 20 inline 21 VOID 22 sprintf_nt(IN PCHAR Buffer, 23 IN PCHAR Format, 24 IN ...) 25 { 26 va_list ap; 27 va_start(ap, Format); 28 vsprintf(Buffer, Format, ap); 29 va_end(ap); 30 } 31 32 /* GLOBALS ********************************************************************/ 33 34 LIST_ENTRY PsLoadedModuleList; 35 LIST_ENTRY MmLoadedUserImageList; 36 KSPIN_LOCK PsLoadedModuleSpinLock; 37 ERESOURCE PsLoadedModuleResource; 38 ULONG_PTR PsNtosImageBase; 39 KMUTANT MmSystemLoadLock; 40 41 PFN_NUMBER MmTotalSystemDriverPages; 42 43 PVOID MmUnloadedDrivers; 44 PVOID MmLastUnloadedDrivers; 45 46 BOOLEAN MmMakeLowMemory; 47 BOOLEAN MmEnforceWriteProtection = TRUE; 48 49 PMMPTE MiKernelResourceStartPte, MiKernelResourceEndPte; 50 ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd; 51 ULONG_PTR MmPteCodeStart, MmPteCodeEnd; 52 53 /* FUNCTIONS ******************************************************************/ 54 55 PVOID 56 NTAPI 57 MiCacheImageSymbols(IN PVOID BaseAddress) 58 { 59 ULONG DebugSize; 60 PVOID DebugDirectory = NULL; 61 PAGED_CODE(); 62 63 /* Make sure it's safe to access the image */ 64 _SEH2_TRY 65 { 66 /* Get the debug directory */ 67 DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress, 68 TRUE, 69 IMAGE_DIRECTORY_ENTRY_DEBUG, 70 &DebugSize); 71 } 72 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 73 { 74 /* Nothing */ 75 } 76 _SEH2_END; 77 78 /* Return the directory */ 79 return DebugDirectory; 80 } 81 82 NTSTATUS 83 NTAPI 84 MiLoadImageSection(IN OUT PVOID *SectionPtr, 85 OUT PVOID *ImageBase, 86 IN PUNICODE_STRING FileName, 87 IN BOOLEAN SessionLoad, 88 IN PLDR_DATA_TABLE_ENTRY LdrEntry) 89 { 90 PROS_SECTION_OBJECT Section = *SectionPtr; 91 NTSTATUS Status; 92 PEPROCESS Process; 93 PVOID Base = NULL; 94 SIZE_T ViewSize = 0; 95 KAPC_STATE ApcState; 96 LARGE_INTEGER SectionOffset = {{0, 0}}; 97 BOOLEAN LoadSymbols = FALSE; 98 PFN_COUNT PteCount; 99 PMMPTE PointerPte, LastPte; 100 PVOID DriverBase; 101 MMPTE TempPte; 102 KIRQL OldIrql; 103 PFN_NUMBER PageFrameIndex; 104 PAGED_CODE(); 105 106 /* Detect session load */ 107 if (SessionLoad) 108 { 109 /* Fail */ 110 UNIMPLEMENTED_DBGBREAK("Session loading not yet supported!\n"); 111 return STATUS_NOT_IMPLEMENTED; 112 } 113 114 /* Not session load, shouldn't have an entry */ 115 ASSERT(LdrEntry == NULL); 116 117 /* Attach to the system process */ 118 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 119 120 /* Check if we need to load symbols */ 121 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD) 122 { 123 /* Yes we do */ 124 LoadSymbols = TRUE; 125 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD; 126 } 127 128 /* Map the driver */ 129 Process = PsGetCurrentProcess(); 130 Status = MmMapViewOfSection(Section, 131 Process, 132 &Base, 133 0, 134 0, 135 &SectionOffset, 136 &ViewSize, 137 ViewUnmap, 138 0, 139 PAGE_EXECUTE); 140 141 /* Re-enable the flag */ 142 if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD; 143 144 /* Check if we failed with distinguished status code */ 145 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) 146 { 147 /* Change it to something more generic */ 148 Status = STATUS_INVALID_IMAGE_FORMAT; 149 } 150 151 /* Now check if we failed */ 152 if (!NT_SUCCESS(Status)) 153 { 154 /* Detach and return */ 155 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status); 156 KeUnstackDetachProcess(&ApcState); 157 return Status; 158 } 159 160 /* Reserve system PTEs needed */ 161 PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageInformation.ImageFileSize) >> PAGE_SHIFT; 162 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace); 163 if (!PointerPte) 164 { 165 DPRINT1("MiReserveSystemPtes failed\n"); 166 KeUnstackDetachProcess(&ApcState); 167 return STATUS_INSUFFICIENT_RESOURCES; 168 } 169 170 /* New driver base */ 171 LastPte = PointerPte + PteCount; 172 DriverBase = MiPteToAddress(PointerPte); 173 174 /* The driver is here */ 175 *ImageBase = DriverBase; 176 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName, DriverBase, PteCount); 177 178 /* Lock the PFN database */ 179 OldIrql = MiAcquirePfnLock(); 180 181 /* Loop the new driver PTEs */ 182 TempPte = ValidKernelPte; 183 while (PointerPte < LastPte) 184 { 185 /* Make sure the PTE is not valid for whatever reason */ 186 ASSERT(PointerPte->u.Hard.Valid == 0); 187 188 /* Some debug stuff */ 189 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE); 190 #if MI_TRACE_PFNS 191 if (FileName->Buffer) 192 { 193 PWCHAR pos = NULL; 194 ULONG len = 0; 195 pos = wcsrchr(FileName->Buffer, '\\'); 196 len = wcslen(pos) * sizeof(WCHAR); 197 if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos); 198 } 199 #endif 200 201 /* Grab a page */ 202 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); 203 204 /* Initialize its PFN entry */ 205 MiInitializePfn(PageFrameIndex, PointerPte, TRUE); 206 207 /* Write the PTE */ 208 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 209 MI_WRITE_VALID_PTE(PointerPte, TempPte); 210 211 /* Move on */ 212 PointerPte++; 213 } 214 215 /* Release the PFN lock */ 216 MiReleasePfnLock(OldIrql); 217 218 /* Copy the image */ 219 RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT); 220 221 /* Now unmap the view */ 222 Status = MmUnmapViewOfSection(Process, Base); 223 ASSERT(NT_SUCCESS(Status)); 224 225 /* Detach and return status */ 226 KeUnstackDetachProcess(&ApcState); 227 return Status; 228 } 229 230 PVOID 231 NTAPI 232 MiLocateExportName(IN PVOID DllBase, 233 IN PCHAR ExportName) 234 { 235 PULONG NameTable; 236 PUSHORT OrdinalTable; 237 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 238 LONG Low = 0, Mid = 0, High, Ret; 239 USHORT Ordinal; 240 PVOID Function; 241 ULONG ExportSize; 242 PULONG ExportTable; 243 PAGED_CODE(); 244 245 /* Get the export directory */ 246 ExportDirectory = RtlImageDirectoryEntryToData(DllBase, 247 TRUE, 248 IMAGE_DIRECTORY_ENTRY_EXPORT, 249 &ExportSize); 250 if (!ExportDirectory) return NULL; 251 252 /* Setup name tables */ 253 NameTable = (PULONG)((ULONG_PTR)DllBase + 254 ExportDirectory->AddressOfNames); 255 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase + 256 ExportDirectory->AddressOfNameOrdinals); 257 258 /* Do a binary search */ 259 High = ExportDirectory->NumberOfNames - 1; 260 while (High >= Low) 261 { 262 /* Get new middle value */ 263 Mid = (Low + High) >> 1; 264 265 /* Compare name */ 266 Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]); 267 if (Ret < 0) 268 { 269 /* Update high */ 270 High = Mid - 1; 271 } 272 else if (Ret > 0) 273 { 274 /* Update low */ 275 Low = Mid + 1; 276 } 277 else 278 { 279 /* We got it */ 280 break; 281 } 282 } 283 284 /* Check if we couldn't find it */ 285 if (High < Low) return NULL; 286 287 /* Otherwise, this is the ordinal */ 288 Ordinal = OrdinalTable[Mid]; 289 290 /* Resolve the address and write it */ 291 ExportTable = (PULONG)((ULONG_PTR)DllBase + 292 ExportDirectory->AddressOfFunctions); 293 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]); 294 295 /* Check if the function is actually a forwarder */ 296 if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) && 297 ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize))) 298 { 299 /* It is, fail */ 300 return NULL; 301 } 302 303 /* We found it */ 304 return Function; 305 } 306 307 NTSTATUS 308 NTAPI 309 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry, 310 IN PLIST_ENTRY ListHead) 311 { 312 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING( 313 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 314 PMM_DLL_INITIALIZE DllInit; 315 UNICODE_STRING RegPath, ImportName; 316 NTSTATUS Status; 317 318 /* Try to see if the image exports a DllInitialize routine */ 319 DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase, 320 "DllInitialize"); 321 if (!DllInit) return STATUS_SUCCESS; 322 323 /* Do a temporary copy of BaseDllName called ImportName 324 * because we'll alter the length of the string 325 */ 326 ImportName.Length = LdrEntry->BaseDllName.Length; 327 ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength; 328 ImportName.Buffer = LdrEntry->BaseDllName.Buffer; 329 330 /* Obtain the path to this dll's service in the registry */ 331 RegPath.MaximumLength = ServicesKeyName.Length + 332 ImportName.Length + sizeof(UNICODE_NULL); 333 RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, 334 RegPath.MaximumLength, 335 TAG_LDR_WSTR); 336 337 /* Check if this allocation was unsuccessful */ 338 if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES; 339 340 /* Build and append the service name itself */ 341 RegPath.Length = ServicesKeyName.Length; 342 RtlCopyMemory(RegPath.Buffer, 343 ServicesKeyName.Buffer, 344 ServicesKeyName.Length); 345 346 /* Check if there is a dot in the filename */ 347 if (wcschr(ImportName.Buffer, L'.')) 348 { 349 /* Remove the extension */ 350 ImportName.Length = (USHORT)(wcschr(ImportName.Buffer, L'.') - 351 ImportName.Buffer) * sizeof(WCHAR); 352 } 353 354 /* Append service name (the basename without extension) */ 355 RtlAppendUnicodeStringToString(&RegPath, &ImportName); 356 357 /* Now call the DllInit func */ 358 DPRINT("Calling DllInit(%wZ)\n", &RegPath); 359 Status = DllInit(&RegPath); 360 361 /* Clean up */ 362 ExFreePoolWithTag(RegPath.Buffer, TAG_LDR_WSTR); 363 364 /* Return status value which DllInitialize returned */ 365 return Status; 366 } 367 368 BOOLEAN 369 NTAPI 370 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 371 { 372 NTSTATUS Status; 373 PMM_DLL_UNLOAD Func; 374 PAGED_CODE(); 375 376 /* Get the unload routine */ 377 Func = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, "DllUnload"); 378 if (!Func) return FALSE; 379 380 /* Call it and check for success */ 381 Status = Func(); 382 if (!NT_SUCCESS(Status)) return FALSE; 383 384 /* Lie about the load count so we can unload the image */ 385 ASSERT(LdrEntry->LoadCount == 0); 386 LdrEntry->LoadCount = 1; 387 388 /* Unload it and return true */ 389 MmUnloadSystemImage(LdrEntry); 390 return TRUE; 391 } 392 393 NTSTATUS 394 NTAPI 395 MiDereferenceImports(IN PLOAD_IMPORTS ImportList) 396 { 397 SIZE_T i; 398 LOAD_IMPORTS SingleEntry; 399 PLDR_DATA_TABLE_ENTRY LdrEntry; 400 PVOID CurrentImports; 401 PAGED_CODE(); 402 403 /* Check if there's no imports or if we're a boot driver */ 404 if ((ImportList == MM_SYSLDR_NO_IMPORTS) || 405 (ImportList == MM_SYSLDR_BOOT_LOADED) || 406 (ImportList->Count == 0)) 407 { 408 /* Then there's nothing to do */ 409 return STATUS_SUCCESS; 410 } 411 412 /* Check for single-entry */ 413 if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY) 414 { 415 /* Set it up */ 416 SingleEntry.Count = 1; 417 SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~ MM_SYSLDR_SINGLE_ENTRY); 418 419 /* Use this as the import list */ 420 ImportList = &SingleEntry; 421 } 422 423 /* Loop the import list */ 424 for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++) 425 { 426 /* Get the entry */ 427 LdrEntry = ImportList->Entry[i]; 428 DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName, &LdrEntry->BaseDllName); 429 430 /* Skip boot loaded images */ 431 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue; 432 433 /* Dereference the entry */ 434 ASSERT(LdrEntry->LoadCount >= 1); 435 if (!--LdrEntry->LoadCount) 436 { 437 /* Save the import data in case unload fails */ 438 CurrentImports = LdrEntry->LoadedImports; 439 440 /* This is the last entry */ 441 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS; 442 if (MiCallDllUnloadAndUnloadDll(LdrEntry)) 443 { 444 /* Unloading worked, parse this DLL's imports too */ 445 MiDereferenceImports(CurrentImports); 446 447 /* Check if we had valid imports */ 448 if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) && 449 (CurrentImports != MM_SYSLDR_NO_IMPORTS) && 450 !((ULONG_PTR)CurrentImports & MM_SYSLDR_SINGLE_ENTRY)) 451 { 452 /* Free them */ 453 ExFreePoolWithTag(CurrentImports, TAG_LDR_IMPORTS); 454 } 455 } 456 else 457 { 458 /* Unload failed, restore imports */ 459 LdrEntry->LoadedImports = CurrentImports; 460 } 461 } 462 } 463 464 /* Done */ 465 return STATUS_SUCCESS; 466 } 467 468 VOID 469 NTAPI 470 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 471 { 472 PAGED_CODE(); 473 474 /* Check if there's no imports or we're a boot driver or only one entry */ 475 if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) || 476 (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) || 477 ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY)) 478 { 479 /* Nothing to do */ 480 return; 481 } 482 483 /* Otherwise, free the import list */ 484 ExFreePoolWithTag(LdrEntry->LoadedImports, TAG_LDR_IMPORTS); 485 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 486 } 487 488 PVOID 489 NTAPI 490 MiFindExportedRoutineByName(IN PVOID DllBase, 491 IN PANSI_STRING ExportName) 492 { 493 PULONG NameTable; 494 PUSHORT OrdinalTable; 495 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 496 LONG Low = 0, Mid = 0, High, Ret; 497 USHORT Ordinal; 498 PVOID Function; 499 ULONG ExportSize; 500 PULONG ExportTable; 501 PAGED_CODE(); 502 503 /* Get the export directory */ 504 ExportDirectory = RtlImageDirectoryEntryToData(DllBase, 505 TRUE, 506 IMAGE_DIRECTORY_ENTRY_EXPORT, 507 &ExportSize); 508 if (!ExportDirectory) return NULL; 509 510 /* Setup name tables */ 511 NameTable = (PULONG)((ULONG_PTR)DllBase + 512 ExportDirectory->AddressOfNames); 513 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase + 514 ExportDirectory->AddressOfNameOrdinals); 515 516 /* Do a binary search */ 517 High = ExportDirectory->NumberOfNames - 1; 518 while (High >= Low) 519 { 520 /* Get new middle value */ 521 Mid = (Low + High) >> 1; 522 523 /* Compare name */ 524 Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]); 525 if (Ret < 0) 526 { 527 /* Update high */ 528 High = Mid - 1; 529 } 530 else if (Ret > 0) 531 { 532 /* Update low */ 533 Low = Mid + 1; 534 } 535 else 536 { 537 /* We got it */ 538 break; 539 } 540 } 541 542 /* Check if we couldn't find it */ 543 if (High < Low) return NULL; 544 545 /* Otherwise, this is the ordinal */ 546 Ordinal = OrdinalTable[Mid]; 547 548 /* Validate the ordinal */ 549 if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL; 550 551 /* Resolve the address and write it */ 552 ExportTable = (PULONG)((ULONG_PTR)DllBase + 553 ExportDirectory->AddressOfFunctions); 554 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]); 555 556 /* We found it! */ 557 ASSERT((Function < (PVOID)ExportDirectory) || 558 (Function > (PVOID)((ULONG_PTR)ExportDirectory + ExportSize))); 559 560 return Function; 561 } 562 563 VOID 564 NTAPI 565 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry, 566 IN BOOLEAN Insert) 567 { 568 KIRQL OldIrql; 569 570 /* Acquire module list lock */ 571 KeEnterCriticalRegion(); 572 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE); 573 574 /* Acquire the spinlock too as we will insert or remove the entry */ 575 OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock); 576 577 /* Insert or remove from the list */ 578 if (Insert) 579 InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks); 580 else 581 RemoveEntryList(&LdrEntry->InLoadOrderLinks); 582 583 /* Release locks */ 584 KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql); 585 ExReleaseResourceLite(&PsLoadedModuleResource); 586 KeLeaveCriticalRegion(); 587 } 588 589 VOID 590 NTAPI 591 INIT_FUNCTION 592 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 593 IN PVOID OldBase, 594 IN PVOID NewBase, 595 IN ULONG Size) 596 { 597 ULONG_PTR OldBaseTop, Delta; 598 PLDR_DATA_TABLE_ENTRY LdrEntry; 599 PLIST_ENTRY NextEntry; 600 ULONG ImportSize; 601 // 602 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load, 603 // since a real version of Windows would fail at this point, but they seem 604 // busy implementing features such as "HotPatch" support in GCC 4.6 instead, 605 // a feature which isn't even used by Windows. Priorities, priorities... 606 // Please note that Microsoft WDK EULA and license prohibits using 607 // the information contained within it for the generation of "non-Windows" 608 // drivers, which is precisely what LD will generate, since an LD driver 609 // will not load on Windows. 610 // 611 #ifdef _WORKING_LINKER_ 612 ULONG i; 613 #endif 614 PULONG_PTR ImageThunk; 615 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 616 617 /* Calculate the top and delta */ 618 OldBaseTop = (ULONG_PTR)OldBase + Size - 1; 619 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase; 620 621 /* Loop the loader block */ 622 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink; 623 NextEntry != &LoaderBlock->LoadOrderListHead; 624 NextEntry = NextEntry->Flink) 625 { 626 /* Get the loader entry */ 627 LdrEntry = CONTAINING_RECORD(NextEntry, 628 LDR_DATA_TABLE_ENTRY, 629 InLoadOrderLinks); 630 #ifdef _WORKING_LINKER_ 631 /* Get the IAT */ 632 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 633 TRUE, 634 IMAGE_DIRECTORY_ENTRY_IAT, 635 &ImportSize); 636 if (!ImageThunk) continue; 637 638 /* Make sure we have an IAT */ 639 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName); 640 for (i = 0; i < ImportSize; i++, ImageThunk++) 641 { 642 /* Check if it's within this module */ 643 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop)) 644 { 645 /* Relocate it */ 646 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n", 647 ImageThunk, *ImageThunk, *ImageThunk + Delta); 648 *ImageThunk += Delta; 649 } 650 } 651 #else 652 /* Get the import table */ 653 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 654 TRUE, 655 IMAGE_DIRECTORY_ENTRY_IMPORT, 656 &ImportSize); 657 if (!ImportDescriptor) continue; 658 659 /* Make sure we have an IAT */ 660 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName); 661 while ((ImportDescriptor->Name) && 662 (ImportDescriptor->OriginalFirstThunk)) 663 { 664 /* Get the image thunk */ 665 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase + 666 ImportDescriptor->FirstThunk); 667 while (*ImageThunk) 668 { 669 /* Check if it's within this module */ 670 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop)) 671 { 672 /* Relocate it */ 673 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n", 674 ImageThunk, *ImageThunk, *ImageThunk + Delta); 675 *ImageThunk += Delta; 676 } 677 678 /* Go to the next thunk */ 679 ImageThunk++; 680 } 681 682 /* Go to the next import */ 683 ImportDescriptor++; 684 } 685 #endif 686 } 687 } 688 689 NTSTATUS 690 NTAPI 691 MiSnapThunk(IN PVOID DllBase, 692 IN PVOID ImageBase, 693 IN PIMAGE_THUNK_DATA Name, 694 IN PIMAGE_THUNK_DATA Address, 695 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, 696 IN ULONG ExportSize, 697 IN BOOLEAN SnapForwarder, 698 OUT PCHAR *MissingApi) 699 { 700 BOOLEAN IsOrdinal; 701 USHORT Ordinal; 702 PULONG NameTable; 703 PUSHORT OrdinalTable; 704 PIMAGE_IMPORT_BY_NAME NameImport; 705 USHORT Hint; 706 ULONG Low = 0, Mid = 0, High; 707 LONG Ret; 708 NTSTATUS Status; 709 PCHAR MissingForwarder; 710 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH]; 711 PULONG ExportTable; 712 ANSI_STRING DllName; 713 UNICODE_STRING ForwarderName; 714 PLIST_ENTRY NextEntry; 715 PLDR_DATA_TABLE_ENTRY LdrEntry; 716 ULONG ForwardExportSize; 717 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory; 718 PIMAGE_IMPORT_BY_NAME ForwardName; 719 SIZE_T ForwardLength; 720 IMAGE_THUNK_DATA ForwardThunk; 721 PAGED_CODE(); 722 723 /* Check if this is an ordinal */ 724 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal); 725 if ((IsOrdinal) && !(SnapForwarder)) 726 { 727 /* Get the ordinal number and set it as missing */ 728 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) - 729 ExportDirectory->Base); 730 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal; 731 } 732 else 733 { 734 /* Get the VA if we don't have to snap */ 735 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase; 736 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData; 737 738 /* Copy the procedure name */ 739 RtlStringCbCopyA(*MissingApi, 740 MAXIMUM_FILENAME_LENGTH, 741 (PCHAR)&NameImport->Name[0]); 742 743 /* Setup name tables */ 744 DPRINT("Import name: %s\n", NameImport->Name); 745 NameTable = (PULONG)((ULONG_PTR)DllBase + 746 ExportDirectory->AddressOfNames); 747 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase + 748 ExportDirectory->AddressOfNameOrdinals); 749 750 /* Get the hint and check if it's valid */ 751 Hint = NameImport->Hint; 752 if ((Hint < ExportDirectory->NumberOfNames) && 753 !(strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Hint]))) 754 { 755 /* We have a match, get the ordinal number from here */ 756 Ordinal = OrdinalTable[Hint]; 757 } 758 else 759 { 760 /* Do a binary search */ 761 High = ExportDirectory->NumberOfNames - 1; 762 while (High >= Low) 763 { 764 /* Get new middle value */ 765 Mid = (Low + High) >> 1; 766 767 /* Compare name */ 768 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]); 769 if (Ret < 0) 770 { 771 /* Update high */ 772 High = Mid - 1; 773 } 774 else if (Ret > 0) 775 { 776 /* Update low */ 777 Low = Mid + 1; 778 } 779 else 780 { 781 /* We got it */ 782 break; 783 } 784 } 785 786 /* Check if we couldn't find it */ 787 if (High < Low) 788 { 789 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport->Name); 790 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 791 } 792 793 /* Otherwise, this is the ordinal */ 794 Ordinal = OrdinalTable[Mid]; 795 } 796 } 797 798 /* Check if the ordinal is invalid */ 799 if (Ordinal >= ExportDirectory->NumberOfFunctions) 800 { 801 /* Fail */ 802 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND; 803 } 804 else 805 { 806 /* In case the forwarder is missing */ 807 MissingForwarder = NameBuffer; 808 809 /* Resolve the address and write it */ 810 ExportTable = (PULONG)((ULONG_PTR)DllBase + 811 ExportDirectory->AddressOfFunctions); 812 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal]; 813 814 /* Assume success from now on */ 815 Status = STATUS_SUCCESS; 816 817 /* Check if the function is actually a forwarder */ 818 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) && 819 (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize))) 820 { 821 /* Now assume failure in case the forwarder doesn't exist */ 822 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 823 824 /* Build the forwarder name */ 825 DllName.Buffer = (PCHAR)Address->u1.Function; 826 DllName.Length = (USHORT)(strchr(DllName.Buffer, '.') - 827 DllName.Buffer) + 828 sizeof(ANSI_NULL); 829 DllName.MaximumLength = DllName.Length; 830 831 /* Convert it */ 832 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName, 833 &DllName, 834 TRUE))) 835 { 836 /* We failed, just return an error */ 837 return Status; 838 } 839 840 /* Loop the module list */ 841 NextEntry = PsLoadedModuleList.Flink; 842 while (NextEntry != &PsLoadedModuleList) 843 { 844 /* Get the loader entry */ 845 LdrEntry = CONTAINING_RECORD(NextEntry, 846 LDR_DATA_TABLE_ENTRY, 847 InLoadOrderLinks); 848 849 /* Check if it matches */ 850 if (RtlPrefixUnicodeString(&ForwarderName, 851 &LdrEntry->BaseDllName, 852 TRUE)) 853 { 854 /* Get the forwarder export directory */ 855 ForwardExportDirectory = 856 RtlImageDirectoryEntryToData(LdrEntry->DllBase, 857 TRUE, 858 IMAGE_DIRECTORY_ENTRY_EXPORT, 859 &ForwardExportSize); 860 if (!ForwardExportDirectory) break; 861 862 /* Allocate a name entry */ 863 ForwardLength = strlen(DllName.Buffer + DllName.Length) + 864 sizeof(ANSI_NULL); 865 ForwardName = ExAllocatePoolWithTag(PagedPool, 866 sizeof(*ForwardName) + 867 ForwardLength, 868 TAG_LDR_WSTR); 869 if (!ForwardName) break; 870 871 /* Copy the data */ 872 RtlCopyMemory(&ForwardName->Name[0], 873 DllName.Buffer + DllName.Length, 874 ForwardLength); 875 ForwardName->Hint = 0; 876 877 /* Set the new address */ 878 ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName; 879 880 /* Snap the forwarder */ 881 Status = MiSnapThunk(LdrEntry->DllBase, 882 ImageBase, 883 &ForwardThunk, 884 &ForwardThunk, 885 ForwardExportDirectory, 886 ForwardExportSize, 887 TRUE, 888 &MissingForwarder); 889 890 /* Free the forwarder name and set the thunk */ 891 ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR); 892 Address->u1 = ForwardThunk.u1; 893 break; 894 } 895 896 /* Go to the next entry */ 897 NextEntry = NextEntry->Flink; 898 } 899 900 /* Free the name */ 901 RtlFreeUnicodeString(&ForwarderName); 902 } 903 } 904 905 /* Return status */ 906 return Status; 907 } 908 909 NTSTATUS 910 NTAPI 911 MmUnloadSystemImage(IN PVOID ImageHandle) 912 { 913 PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle; 914 PVOID BaseAddress = LdrEntry->DllBase; 915 NTSTATUS Status; 916 STRING TempName; 917 BOOLEAN HadEntry = FALSE; 918 919 /* Acquire the loader lock */ 920 KeEnterCriticalRegion(); 921 KeWaitForSingleObject(&MmSystemLoadLock, 922 WrVirtualMemory, 923 KernelMode, 924 FALSE, 925 NULL); 926 927 /* Check if this driver was loaded at boot and didn't get imports parsed */ 928 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) goto Done; 929 930 /* We should still be alive */ 931 ASSERT(LdrEntry->LoadCount != 0); 932 LdrEntry->LoadCount--; 933 934 /* Check if we're still loaded */ 935 if (LdrEntry->LoadCount) goto Done; 936 937 /* We should cleanup... are symbols loaded */ 938 if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED) 939 { 940 /* Create the ANSI name */ 941 Status = RtlUnicodeStringToAnsiString(&TempName, 942 &LdrEntry->BaseDllName, 943 TRUE); 944 if (NT_SUCCESS(Status)) 945 { 946 /* Unload the symbols */ 947 DbgUnLoadImageSymbols(&TempName, 948 BaseAddress, 949 (ULONG_PTR)PsGetCurrentProcessId()); 950 RtlFreeAnsiString(&TempName); 951 } 952 } 953 954 /* FIXME: Free the driver */ 955 DPRINT1("Leaking driver: %wZ\n", &LdrEntry->BaseDllName); 956 //MmFreeSection(LdrEntry->DllBase); 957 958 /* Check if we're linked in */ 959 if (LdrEntry->InLoadOrderLinks.Flink) 960 { 961 /* Remove us */ 962 MiProcessLoaderEntry(LdrEntry, FALSE); 963 HadEntry = TRUE; 964 } 965 966 /* Dereference and clear the imports */ 967 MiDereferenceImports(LdrEntry->LoadedImports); 968 MiClearImports(LdrEntry); 969 970 /* Check if the entry needs to go away */ 971 if (HadEntry) 972 { 973 /* Check if it had a name */ 974 if (LdrEntry->FullDllName.Buffer) 975 { 976 /* Free it */ 977 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR); 978 } 979 980 /* Check if we had a section */ 981 if (LdrEntry->SectionPointer) 982 { 983 /* Dereference it */ 984 ObDereferenceObject(LdrEntry->SectionPointer); 985 } 986 987 /* Free the entry */ 988 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT); 989 } 990 991 /* Release the system lock and return */ 992 Done: 993 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE); 994 KeLeaveCriticalRegion(); 995 return STATUS_SUCCESS; 996 } 997 998 NTSTATUS 999 NTAPI 1000 MiResolveImageReferences(IN PVOID ImageBase, 1001 IN PUNICODE_STRING ImageFileDirectory, 1002 IN PUNICODE_STRING NamePrefix OPTIONAL, 1003 OUT PCHAR *MissingApi, 1004 OUT PWCHAR *MissingDriver, 1005 OUT PLOAD_IMPORTS *LoadImports) 1006 { 1007 static UNICODE_STRING DriversFolderName = RTL_CONSTANT_STRING(L"drivers\\"); 1008 PCHAR MissingApiBuffer = *MissingApi, ImportName; 1009 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport; 1010 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize; 1011 PLOAD_IMPORTS LoadedImports, NewImports; 1012 ULONG GdiLink, NormalLink, i; 1013 BOOLEAN ReferenceNeeded, Loaded; 1014 ANSI_STRING TempString; 1015 UNICODE_STRING NameString, DllName; 1016 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL; 1017 PVOID ImportBase, DllBase; 1018 PLIST_ENTRY NextEntry; 1019 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 1020 NTSTATUS Status; 1021 PIMAGE_THUNK_DATA OrigThunk, FirstThunk; 1022 PAGED_CODE(); 1023 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n", 1024 __FUNCTION__, ImageBase, ImageFileDirectory); 1025 1026 /* No name string buffer yet */ 1027 NameString.Buffer = NULL; 1028 1029 /* Assume no imports */ 1030 *LoadImports = MM_SYSLDR_NO_IMPORTS; 1031 1032 /* Get the import descriptor */ 1033 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase, 1034 TRUE, 1035 IMAGE_DIRECTORY_ENTRY_IMPORT, 1036 &ImportSize); 1037 if (!ImportDescriptor) return STATUS_SUCCESS; 1038 1039 /* Loop all imports to count them */ 1040 for (CurrentImport = ImportDescriptor; 1041 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk); 1042 CurrentImport++) 1043 { 1044 /* One more */ 1045 ImportCount++; 1046 } 1047 1048 /* Make sure we have non-zero imports */ 1049 if (ImportCount) 1050 { 1051 /* Calculate and allocate the list we'll need */ 1052 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T); 1053 LoadedImports = ExAllocatePoolWithTag(PagedPool, 1054 LoadedImportsSize, 1055 TAG_LDR_IMPORTS); 1056 if (LoadedImports) 1057 { 1058 /* Zero it */ 1059 RtlZeroMemory(LoadedImports, LoadedImportsSize); 1060 LoadedImports->Count = ImportCount; 1061 } 1062 } 1063 else 1064 { 1065 /* No table */ 1066 LoadedImports = NULL; 1067 } 1068 1069 /* Reset the import count and loop descriptors again */ 1070 ImportCount = GdiLink = NormalLink = 0; 1071 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk)) 1072 { 1073 /* Get the name */ 1074 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name); 1075 1076 /* Check if this is a GDI driver */ 1077 GdiLink = GdiLink | 1078 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)); 1079 1080 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/ 1081 NormalLink = NormalLink | 1082 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) && 1083 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)) && 1084 (_strnicmp(ImportName, "coverage", sizeof("coverage") - 1)) && 1085 (_strnicmp(ImportName, "irt", sizeof("irt") - 1))); 1086 1087 /* Check if this is a valid GDI driver */ 1088 if ((GdiLink) && (NormalLink)) 1089 { 1090 /* It's not, it's importing stuff it shouldn't be! */ 1091 Status = STATUS_PROCEDURE_NOT_FOUND; 1092 goto Failure; 1093 } 1094 1095 /* Check for user-mode printer or video card drivers, which don't belong */ 1096 if (!(_strnicmp(ImportName, "ntdll", sizeof("ntdll") - 1)) || 1097 !(_strnicmp(ImportName, "winsrv", sizeof("winsrv") - 1)) || 1098 !(_strnicmp(ImportName, "advapi32", sizeof("advapi32") - 1)) || 1099 !(_strnicmp(ImportName, "kernel32", sizeof("kernel32") - 1)) || 1100 !(_strnicmp(ImportName, "user32", sizeof("user32") - 1)) || 1101 !(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1))) 1102 { 1103 /* This is not kernel code */ 1104 Status = STATUS_PROCEDURE_NOT_FOUND; 1105 goto Failure; 1106 } 1107 1108 /* Check if this is a "core" import, which doesn't get referenced */ 1109 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) || 1110 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) || 1111 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1))) 1112 { 1113 /* Don't reference this */ 1114 ReferenceNeeded = FALSE; 1115 } 1116 else 1117 { 1118 /* Reference these modules */ 1119 ReferenceNeeded = TRUE; 1120 } 1121 1122 /* Now setup a unicode string for the import */ 1123 RtlInitAnsiString(&TempString, ImportName); 1124 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE); 1125 if (!NT_SUCCESS(Status)) 1126 { 1127 /* Failed */ 1128 goto Failure; 1129 } 1130 1131 /* We don't support name prefixes yet */ 1132 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n"); 1133 1134 /* Remember that we haven't loaded the import at this point */ 1135 CheckDllState: 1136 Loaded = FALSE; 1137 ImportBase = NULL; 1138 1139 /* Loop the driver list */ 1140 NextEntry = PsLoadedModuleList.Flink; 1141 while (NextEntry != &PsLoadedModuleList) 1142 { 1143 /* Get the loader entry and compare the name */ 1144 LdrEntry = CONTAINING_RECORD(NextEntry, 1145 LDR_DATA_TABLE_ENTRY, 1146 InLoadOrderLinks); 1147 if (RtlEqualUnicodeString(&NameString, 1148 &LdrEntry->BaseDllName, 1149 TRUE)) 1150 { 1151 /* Get the base address */ 1152 ImportBase = LdrEntry->DllBase; 1153 1154 /* Check if we haven't loaded yet, and we need references */ 1155 if (!(Loaded) && (ReferenceNeeded)) 1156 { 1157 /* Make sure we're not already loading */ 1158 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS)) 1159 { 1160 /* Increase the load count */ 1161 LdrEntry->LoadCount++; 1162 } 1163 } 1164 1165 /* Done, break out */ 1166 break; 1167 } 1168 1169 /* Go to the next entry */ 1170 NextEntry = NextEntry->Flink; 1171 } 1172 1173 /* Check if we haven't loaded the import yet */ 1174 if (!ImportBase) 1175 { 1176 /* Setup the import DLL name */ 1177 DllName.MaximumLength = NameString.Length + 1178 ImageFileDirectory->Length + 1179 sizeof(UNICODE_NULL); 1180 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 1181 DllName.MaximumLength, 1182 TAG_LDR_WSTR); 1183 if (!DllName.Buffer) 1184 { 1185 /* We're out of resources */ 1186 Status = STATUS_INSUFFICIENT_RESOURCES; 1187 goto Failure; 1188 } 1189 1190 /* Add the import name to the base directory */ 1191 RtlCopyUnicodeString(&DllName, ImageFileDirectory); 1192 RtlAppendUnicodeStringToString(&DllName, 1193 &NameString); 1194 1195 /* Load the image */ 1196 Status = MmLoadSystemImage(&DllName, 1197 NamePrefix, 1198 NULL, 1199 FALSE, 1200 (PVOID *)&DllEntry, 1201 &DllBase); 1202 1203 /* win32k / GDI drivers can also import from system32 folder */ 1204 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && 1205 (MI_IS_SESSION_ADDRESS(ImageBase) || 1)) // HACK 1206 { 1207 /* Free the old name buffer */ 1208 ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR); 1209 1210 /* Calculate size for a string the adds 'drivers\' */ 1211 DllName.MaximumLength += DriversFolderName.Length; 1212 1213 /* Allocate the new buffer */ 1214 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 1215 DllName.MaximumLength, 1216 TAG_LDR_WSTR); 1217 if (!DllName.Buffer) 1218 { 1219 /* We're out of resources */ 1220 Status = STATUS_INSUFFICIENT_RESOURCES; 1221 goto Failure; 1222 } 1223 1224 /* Copy image directory and append 'drivers\' folder name */ 1225 RtlCopyUnicodeString(&DllName, ImageFileDirectory); 1226 RtlAppendUnicodeStringToString(&DllName, &DriversFolderName); 1227 1228 /* Now add the import name */ 1229 RtlAppendUnicodeStringToString(&DllName, &NameString); 1230 1231 /* Try once again to load the image */ 1232 Status = MmLoadSystemImage(&DllName, 1233 NamePrefix, 1234 NULL, 1235 FALSE, 1236 (PVOID *)&DllEntry, 1237 &DllBase); 1238 } 1239 1240 if (!NT_SUCCESS(Status)) 1241 { 1242 /* Fill out the information for the error */ 1243 *MissingDriver = DllName.Buffer; 1244 *(PULONG)MissingDriver |= 1; 1245 *MissingApi = NULL; 1246 1247 DPRINT1("Failed to load dependency: %wZ\n", &DllName); 1248 1249 /* Don't free the name */ 1250 DllName.Buffer = NULL; 1251 1252 /* Cleanup and return */ 1253 goto Failure; 1254 } 1255 1256 /* We can free the DLL Name */ 1257 ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR); 1258 DllName.Buffer = NULL; 1259 1260 /* We're now loaded */ 1261 Loaded = TRUE; 1262 1263 /* Sanity check */ 1264 ASSERT(DllBase == DllEntry->DllBase); 1265 1266 /* Call the initialization routines */ 1267 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList); 1268 if (!NT_SUCCESS(Status)) 1269 { 1270 /* We failed, unload the image */ 1271 MmUnloadSystemImage(DllEntry); 1272 ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status); 1273 Loaded = FALSE; 1274 } 1275 1276 /* Loop again to make sure that everything is OK */ 1277 goto CheckDllState; 1278 } 1279 1280 /* Check if we're support to reference this import */ 1281 if ((ReferenceNeeded) && (LoadedImports)) 1282 { 1283 /* Make sure we're not already loading */ 1284 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS)) 1285 { 1286 /* Add the entry */ 1287 LoadedImports->Entry[ImportCount] = LdrEntry; 1288 ImportCount++; 1289 } 1290 } 1291 1292 /* Free the import name */ 1293 RtlFreeUnicodeString(&NameString); 1294 1295 /* Set the missing driver name and get the export directory */ 1296 *MissingDriver = LdrEntry->BaseDllName.Buffer; 1297 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase, 1298 TRUE, 1299 IMAGE_DIRECTORY_ENTRY_EXPORT, 1300 &ExportSize); 1301 if (!ExportDirectory) 1302 { 1303 /* Cleanup and return */ 1304 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver); 1305 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 1306 goto Failure; 1307 } 1308 1309 /* Make sure we have an IAT */ 1310 if (ImportDescriptor->OriginalFirstThunk) 1311 { 1312 /* Get the first thunks */ 1313 OrigThunk = (PVOID)((ULONG_PTR)ImageBase + 1314 ImportDescriptor->OriginalFirstThunk); 1315 FirstThunk = (PVOID)((ULONG_PTR)ImageBase + 1316 ImportDescriptor->FirstThunk); 1317 1318 /* Loop the IAT */ 1319 while (OrigThunk->u1.AddressOfData) 1320 { 1321 /* Snap thunk */ 1322 Status = MiSnapThunk(ImportBase, 1323 ImageBase, 1324 OrigThunk++, 1325 FirstThunk++, 1326 ExportDirectory, 1327 ExportSize, 1328 FALSE, 1329 MissingApi); 1330 if (!NT_SUCCESS(Status)) 1331 { 1332 /* Cleanup and return */ 1333 goto Failure; 1334 } 1335 1336 /* Reset the buffer */ 1337 *MissingApi = MissingApiBuffer; 1338 } 1339 } 1340 1341 /* Go to the next import */ 1342 ImportDescriptor++; 1343 } 1344 1345 /* Check if we have an import list */ 1346 if (LoadedImports) 1347 { 1348 /* Reset the count again, and loop entries */ 1349 ImportCount = 0; 1350 for (i = 0; i < LoadedImports->Count; i++) 1351 { 1352 if (LoadedImports->Entry[i]) 1353 { 1354 /* Got an entry, OR it with 1 in case it's the single entry */ 1355 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1356 MM_SYSLDR_SINGLE_ENTRY); 1357 ImportCount++; 1358 } 1359 } 1360 1361 /* Check if we had no imports */ 1362 if (!ImportCount) 1363 { 1364 /* Free the list and set it to no imports */ 1365 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 1366 LoadedImports = MM_SYSLDR_NO_IMPORTS; 1367 } 1368 else if (ImportCount == 1) 1369 { 1370 /* Just one entry, we can free the table and only use our entry */ 1371 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 1372 LoadedImports = (PLOAD_IMPORTS)ImportEntry; 1373 } 1374 else if (ImportCount != LoadedImports->Count) 1375 { 1376 /* Allocate a new list */ 1377 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T); 1378 NewImports = ExAllocatePoolWithTag(PagedPool, 1379 LoadedImportsSize, 1380 TAG_LDR_IMPORTS); 1381 if (NewImports) 1382 { 1383 /* Set count */ 1384 NewImports->Count = 0; 1385 1386 /* Loop all the imports */ 1387 for (i = 0; i < LoadedImports->Count; i++) 1388 { 1389 /* Make sure it's valid */ 1390 if (LoadedImports->Entry[i]) 1391 { 1392 /* Copy it */ 1393 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i]; 1394 NewImports->Count++; 1395 } 1396 } 1397 1398 /* Free the old copy */ 1399 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 1400 LoadedImports = NewImports; 1401 } 1402 } 1403 1404 /* Return the list */ 1405 *LoadImports = LoadedImports; 1406 } 1407 1408 /* Return success */ 1409 return STATUS_SUCCESS; 1410 1411 Failure: 1412 1413 /* Cleanup and return */ 1414 RtlFreeUnicodeString(&NameString); 1415 1416 if (LoadedImports) 1417 { 1418 MiDereferenceImports(LoadedImports); 1419 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 1420 } 1421 1422 return Status; 1423 } 1424 1425 VOID 1426 NTAPI 1427 MiFreeInitializationCode(IN PVOID InitStart, 1428 IN PVOID InitEnd) 1429 { 1430 PMMPTE PointerPte; 1431 PFN_NUMBER PagesFreed; 1432 1433 /* Get the start PTE */ 1434 PointerPte = MiAddressToPte(InitStart); 1435 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart) == FALSE); 1436 1437 /* Compute the number of pages we expect to free */ 1438 PagesFreed = (PFN_NUMBER)(MiAddressToPte(InitEnd) - PointerPte + 1); 1439 1440 /* Try to actually free them */ 1441 PagesFreed = MiDeleteSystemPageableVm(PointerPte, 1442 PagesFreed, 1443 0, 1444 NULL); 1445 } 1446 1447 VOID 1448 NTAPI 1449 INIT_FUNCTION 1450 MiFindInitializationCode(OUT PVOID *StartVa, 1451 OUT PVOID *EndVa) 1452 { 1453 ULONG Size, SectionCount, Alignment; 1454 PLDR_DATA_TABLE_ENTRY LdrEntry; 1455 ULONG_PTR DllBase, InitStart, InitEnd, ImageEnd, InitCode; 1456 PLIST_ENTRY NextEntry; 1457 PIMAGE_NT_HEADERS NtHeader; 1458 PIMAGE_SECTION_HEADER Section, LastSection; 1459 BOOLEAN InitFound; 1460 1461 /* So we don't free our own code yet */ 1462 InitCode = (ULONG_PTR)&MiFindInitializationCode; 1463 1464 /* Assume failure */ 1465 *StartVa = NULL; 1466 1467 /* Enter a critical region while we loop the list */ 1468 KeEnterCriticalRegion(); 1469 1470 /* Loop all loaded modules */ 1471 NextEntry = PsLoadedModuleList.Flink; 1472 while (NextEntry != &PsLoadedModuleList) 1473 { 1474 /* Get the loader entry and its DLL base */ 1475 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 1476 DllBase = (ULONG_PTR)LdrEntry->DllBase; 1477 1478 /* Only process boot loaded images. Other drivers are processed by 1479 MmFreeDriverInitialization */ 1480 if (LdrEntry->Flags & LDRP_MM_LOADED) 1481 { 1482 /* Keep going */ 1483 NextEntry = NextEntry->Flink; 1484 continue; 1485 } 1486 1487 /* Get the NT header */ 1488 NtHeader = RtlImageNtHeader((PVOID)DllBase); 1489 if (!NtHeader) 1490 { 1491 /* Keep going */ 1492 NextEntry = NextEntry->Flink; 1493 continue; 1494 } 1495 1496 /* Get the first section, the section count, and scan them all */ 1497 Section = IMAGE_FIRST_SECTION(NtHeader); 1498 SectionCount = NtHeader->FileHeader.NumberOfSections; 1499 InitStart = 0; 1500 while (SectionCount > 0) 1501 { 1502 /* Assume failure */ 1503 InitFound = FALSE; 1504 1505 /* Is this the INIT section or a discardable section? */ 1506 if ((*(PULONG)Section->Name == 'TINI') || 1507 ((Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))) 1508 { 1509 /* Remember this */ 1510 InitFound = TRUE; 1511 } 1512 1513 if (InitFound) 1514 { 1515 /* Pick the biggest size -- either raw or virtual */ 1516 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 1517 1518 /* Read the section alignment */ 1519 Alignment = NtHeader->OptionalHeader.SectionAlignment; 1520 1521 /* Align the start and end addresses appropriately */ 1522 InitStart = DllBase + Section->VirtualAddress; 1523 InitEnd = ((Alignment + InitStart + Size - 2) & 0xFFFFF000) - 1; 1524 InitStart = (InitStart + (PAGE_SIZE - 1)) & 0xFFFFF000; 1525 1526 /* Have we reached the last section? */ 1527 if (SectionCount == 1) 1528 { 1529 /* Remember this */ 1530 LastSection = Section; 1531 } 1532 else 1533 { 1534 /* We have not, loop all the sections */ 1535 LastSection = NULL; 1536 do 1537 { 1538 /* Keep going until we find a non-discardable section range */ 1539 SectionCount--; 1540 Section++; 1541 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 1542 { 1543 /* Discardable, so record it, then keep going */ 1544 LastSection = Section; 1545 } 1546 else 1547 { 1548 /* Non-contigous discard flag, or no flag, break out */ 1549 break; 1550 } 1551 } 1552 while (SectionCount > 1); 1553 } 1554 1555 /* Have we found a discardable or init section? */ 1556 if (LastSection) 1557 { 1558 /* Pick the biggest size -- either raw or virtual */ 1559 Size = max(LastSection->SizeOfRawData, LastSection->Misc.VirtualSize); 1560 1561 /* Use this as the end of the section address */ 1562 InitEnd = DllBase + LastSection->VirtualAddress + Size - 1; 1563 1564 /* Have we reached the last section yet? */ 1565 if (SectionCount != 1) 1566 { 1567 /* Then align this accross the session boundary */ 1568 InitEnd = ((Alignment + InitEnd - 1) & 0XFFFFF000) - 1; 1569 } 1570 } 1571 1572 /* Make sure we don't let the init section go past the image */ 1573 ImageEnd = DllBase + LdrEntry->SizeOfImage; 1574 if (InitEnd > ImageEnd) InitEnd = (ImageEnd - 1) | (PAGE_SIZE - 1); 1575 1576 /* Make sure we have a valid, non-zero init section */ 1577 if (InitStart <= InitEnd) 1578 { 1579 /* Make sure we are not within this code itself */ 1580 if ((InitCode >= InitStart) && (InitCode <= InitEnd)) 1581 { 1582 /* Return it, we can't free ourselves now */ 1583 ASSERT(*StartVa == 0); 1584 *StartVa = (PVOID)InitStart; 1585 *EndVa = (PVOID)InitEnd; 1586 } 1587 else 1588 { 1589 /* This isn't us -- go ahead and free it */ 1590 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID)InitStart) == FALSE); 1591 MiFreeInitializationCode((PVOID)InitStart, (PVOID)InitEnd); 1592 } 1593 } 1594 } 1595 1596 /* Move to the next section */ 1597 SectionCount--; 1598 Section++; 1599 } 1600 1601 /* Move to the next module */ 1602 NextEntry = NextEntry->Flink; 1603 } 1604 1605 /* Leave the critical region and return */ 1606 KeLeaveCriticalRegion(); 1607 } 1608 1609 /* 1610 * Note: This function assumes that all discardable sections are at the end of 1611 * the PE file. It searches backwards until it finds the non-discardable section 1612 */ 1613 VOID 1614 NTAPI 1615 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 1616 { 1617 PMMPTE StartPte, EndPte; 1618 PFN_NUMBER PageCount; 1619 PVOID DllBase; 1620 ULONG i; 1621 PIMAGE_NT_HEADERS NtHeader; 1622 PIMAGE_SECTION_HEADER Section, DiscardSection; 1623 1624 /* Get the base address and the page count */ 1625 DllBase = LdrEntry->DllBase; 1626 PageCount = LdrEntry->SizeOfImage >> PAGE_SHIFT; 1627 1628 /* Get the last PTE in this image */ 1629 EndPte = MiAddressToPte(DllBase) + PageCount; 1630 1631 /* Get the NT header */ 1632 NtHeader = RtlImageNtHeader(DllBase); 1633 if (!NtHeader) return; 1634 1635 /* Get the last section and loop each section backwards */ 1636 Section = IMAGE_FIRST_SECTION(NtHeader) + NtHeader->FileHeader.NumberOfSections; 1637 DiscardSection = NULL; 1638 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++) 1639 { 1640 /* Go back a section and check if it's discardable */ 1641 Section--; 1642 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 1643 { 1644 /* It is, select it for freeing */ 1645 DiscardSection = Section; 1646 } 1647 else 1648 { 1649 /* No more discardable sections exist, bail out */ 1650 break; 1651 } 1652 } 1653 1654 /* Bail out if there's nothing to free */ 1655 if (!DiscardSection) return; 1656 1657 /* Push the DLL base to the first disacrable section, and get its PTE */ 1658 DllBase = (PVOID)ROUND_TO_PAGES((ULONG_PTR)DllBase + DiscardSection->VirtualAddress); 1659 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase) == FALSE); 1660 StartPte = MiAddressToPte(DllBase); 1661 1662 /* Check how many pages to free total */ 1663 PageCount = (PFN_NUMBER)(EndPte - StartPte); 1664 if (!PageCount) return; 1665 1666 /* Delete this many PTEs */ 1667 MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL); 1668 } 1669 1670 VOID 1671 NTAPI 1672 INIT_FUNCTION 1673 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 1674 { 1675 PLIST_ENTRY NextEntry; 1676 ULONG i = 0; 1677 PIMAGE_NT_HEADERS NtHeader; 1678 PLDR_DATA_TABLE_ENTRY LdrEntry; 1679 PIMAGE_FILE_HEADER FileHeader; 1680 BOOLEAN ValidRelocs; 1681 PIMAGE_DATA_DIRECTORY DataDirectory; 1682 PVOID DllBase, NewImageAddress; 1683 NTSTATUS Status; 1684 PMMPTE PointerPte, StartPte, LastPte; 1685 PFN_COUNT PteCount; 1686 PMMPFN Pfn1; 1687 MMPTE TempPte, OldPte; 1688 1689 /* Loop driver list */ 1690 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink; 1691 NextEntry != &LoaderBlock->LoadOrderListHead; 1692 NextEntry = NextEntry->Flink) 1693 { 1694 /* Get the loader entry and NT header */ 1695 LdrEntry = CONTAINING_RECORD(NextEntry, 1696 LDR_DATA_TABLE_ENTRY, 1697 InLoadOrderLinks); 1698 NtHeader = RtlImageNtHeader(LdrEntry->DllBase); 1699 1700 /* Debug info */ 1701 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n", 1702 LdrEntry->DllBase, 1703 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage, 1704 &LdrEntry->FullDllName); 1705 1706 /* Get the first PTE and the number of PTEs we'll need */ 1707 PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase); 1708 PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT; 1709 LastPte = StartPte + PteCount; 1710 1711 #if MI_TRACE_PFNS 1712 /* Loop the PTEs */ 1713 while (PointerPte < LastPte) 1714 { 1715 ULONG len; 1716 ASSERT(PointerPte->u.Hard.Valid == 1); 1717 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte)); 1718 len = wcslen(LdrEntry->BaseDllName.Buffer) * sizeof(WCHAR); 1719 snprintf(Pfn1->ProcessName, min(16, len), "%S", LdrEntry->BaseDllName.Buffer); 1720 PointerPte++; 1721 } 1722 #endif 1723 /* Skip kernel and HAL */ 1724 /* ROS HACK: Skip BOOTVID/KDCOM too */ 1725 i++; 1726 if (i <= 4) continue; 1727 1728 /* Skip non-drivers */ 1729 if (!NtHeader) continue; 1730 1731 /* Get the file header and make sure we can relocate */ 1732 FileHeader = &NtHeader->FileHeader; 1733 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue; 1734 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes < 1735 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue; 1736 1737 /* Everything made sense until now, check the relocation section too */ 1738 DataDirectory = &NtHeader->OptionalHeader. 1739 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 1740 if (!DataDirectory->VirtualAddress) 1741 { 1742 /* We don't really have relocations */ 1743 ValidRelocs = FALSE; 1744 } 1745 else 1746 { 1747 /* Make sure the size is valid */ 1748 if ((DataDirectory->VirtualAddress + DataDirectory->Size) > 1749 LdrEntry->SizeOfImage) 1750 { 1751 /* They're not, skip */ 1752 continue; 1753 } 1754 1755 /* We have relocations */ 1756 ValidRelocs = TRUE; 1757 } 1758 1759 /* Remember the original address */ 1760 DllBase = LdrEntry->DllBase; 1761 1762 /* Loop the PTEs */ 1763 PointerPte = StartPte; 1764 while (PointerPte < LastPte) 1765 { 1766 /* Mark the page modified in the PFN database */ 1767 ASSERT(PointerPte->u.Hard.Valid == 1); 1768 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte)); 1769 ASSERT(Pfn1->u3.e1.Rom == 0); 1770 Pfn1->u3.e1.Modified = TRUE; 1771 1772 /* Next */ 1773 PointerPte++; 1774 } 1775 1776 /* Now reserve system PTEs for the image */ 1777 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace); 1778 if (!PointerPte) 1779 { 1780 /* Shouldn't happen */ 1781 ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n"); 1782 return; 1783 } 1784 1785 /* This is the new virtual address for the module */ 1786 LastPte = PointerPte + PteCount; 1787 NewImageAddress = MiPteToAddress(PointerPte); 1788 1789 /* Sanity check */ 1790 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress); 1791 ASSERT(ExpInitializationPhase == 0); 1792 1793 /* Loop the new driver PTEs */ 1794 TempPte = ValidKernelPte; 1795 while (PointerPte < LastPte) 1796 { 1797 /* Copy the old data */ 1798 OldPte = *StartPte; 1799 ASSERT(OldPte.u.Hard.Valid == 1); 1800 1801 /* Set page number from the loader's memory */ 1802 TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber; 1803 1804 /* Write it */ 1805 MI_WRITE_VALID_PTE(PointerPte, TempPte); 1806 1807 /* Move on */ 1808 PointerPte++; 1809 StartPte++; 1810 } 1811 1812 /* Update position */ 1813 PointerPte -= PteCount; 1814 1815 /* Sanity check */ 1816 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase); 1817 1818 /* Set the image base to the address where the loader put it */ 1819 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase; 1820 1821 /* Check if we had relocations */ 1822 if (ValidRelocs) 1823 { 1824 /* Relocate the image */ 1825 Status = LdrRelocateImageWithBias(NewImageAddress, 1826 0, 1827 "SYSLDR", 1828 STATUS_SUCCESS, 1829 STATUS_CONFLICTING_ADDRESSES, 1830 STATUS_INVALID_IMAGE_FORMAT); 1831 if (!NT_SUCCESS(Status)) 1832 { 1833 /* This shouldn't happen */ 1834 ERROR_FATAL("Relocations failed!\n"); 1835 return; 1836 } 1837 } 1838 1839 /* Update the loader entry */ 1840 LdrEntry->DllBase = NewImageAddress; 1841 1842 /* Update the thunks */ 1843 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName); 1844 MiUpdateThunks(LoaderBlock, 1845 DllBase, 1846 NewImageAddress, 1847 LdrEntry->SizeOfImage); 1848 1849 /* Update the loader entry */ 1850 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED; 1851 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress + 1852 NtHeader->OptionalHeader.AddressOfEntryPoint); 1853 LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT; 1854 1855 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */ 1856 } 1857 } 1858 1859 NTSTATUS 1860 NTAPI 1861 INIT_FUNCTION 1862 MiBuildImportsForBootDrivers(VOID) 1863 { 1864 PLIST_ENTRY NextEntry, NextEntry2; 1865 PLDR_DATA_TABLE_ENTRY LdrEntry, KernelEntry, HalEntry, LdrEntry2, LastEntry; 1866 PLDR_DATA_TABLE_ENTRY* EntryArray; 1867 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe"); 1868 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll"); 1869 PLOAD_IMPORTS LoadedImports; 1870 ULONG LoadedImportsSize, ImportSize; 1871 PULONG_PTR ImageThunk; 1872 ULONG_PTR DllBase, DllEnd; 1873 ULONG Modules = 0, i, j = 0; 1874 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 1875 1876 /* Initialize variables */ 1877 KernelEntry = HalEntry = LastEntry = NULL; 1878 1879 /* Loop the loaded module list... we are early enough that no lock is needed */ 1880 NextEntry = PsLoadedModuleList.Flink; 1881 while (NextEntry != &PsLoadedModuleList) 1882 { 1883 /* Get the entry */ 1884 LdrEntry = CONTAINING_RECORD(NextEntry, 1885 LDR_DATA_TABLE_ENTRY, 1886 InLoadOrderLinks); 1887 1888 /* Check if it's the kernel or HAL */ 1889 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE)) 1890 { 1891 /* Found it */ 1892 KernelEntry = LdrEntry; 1893 } 1894 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE)) 1895 { 1896 /* Found it */ 1897 HalEntry = LdrEntry; 1898 } 1899 1900 /* Check if this is a driver DLL */ 1901 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL) 1902 { 1903 /* Check if this is the HAL or kernel */ 1904 if ((LdrEntry == HalEntry) || (LdrEntry == KernelEntry)) 1905 { 1906 /* Add a reference */ 1907 LdrEntry->LoadCount = 1; 1908 } 1909 else 1910 { 1911 /* No referencing needed */ 1912 LdrEntry->LoadCount = 0; 1913 } 1914 } 1915 else 1916 { 1917 /* Add a reference for all other modules as well */ 1918 LdrEntry->LoadCount = 1; 1919 } 1920 1921 /* Remember this came from the loader */ 1922 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 1923 1924 /* Keep looping */ 1925 NextEntry = NextEntry->Flink; 1926 Modules++; 1927 } 1928 1929 /* We must have at least found the kernel and HAL */ 1930 if (!(HalEntry) || (!KernelEntry)) return STATUS_NOT_FOUND; 1931 1932 /* Allocate the list */ 1933 EntryArray = ExAllocatePoolWithTag(PagedPool, Modules * sizeof(PVOID), TAG_LDR_IMPORTS); 1934 if (!EntryArray) return STATUS_INSUFFICIENT_RESOURCES; 1935 1936 /* Loop the loaded module list again */ 1937 NextEntry = PsLoadedModuleList.Flink; 1938 while (NextEntry != &PsLoadedModuleList) 1939 { 1940 /* Get the entry */ 1941 LdrEntry = CONTAINING_RECORD(NextEntry, 1942 LDR_DATA_TABLE_ENTRY, 1943 InLoadOrderLinks); 1944 #ifdef _WORKING_LOADER_ 1945 /* Get its imports */ 1946 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 1947 TRUE, 1948 IMAGE_DIRECTORY_ENTRY_IAT, 1949 &ImportSize); 1950 if (!ImageThunk) 1951 #else 1952 /* Get its imports */ 1953 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 1954 TRUE, 1955 IMAGE_DIRECTORY_ENTRY_IMPORT, 1956 &ImportSize); 1957 if (!ImportDescriptor) 1958 #endif 1959 { 1960 /* None present */ 1961 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS; 1962 NextEntry = NextEntry->Flink; 1963 continue; 1964 } 1965 1966 /* Clear the list and count the number of IAT thunks */ 1967 RtlZeroMemory(EntryArray, Modules * sizeof(PVOID)); 1968 #ifdef _WORKING_LOADER_ 1969 ImportSize /= sizeof(ULONG_PTR); 1970 1971 /* Scan the thunks */ 1972 for (i = 0, DllBase = 0, DllEnd = 0; i < ImportSize; i++, ImageThunk++) 1973 #else 1974 DllBase = DllEnd = i = 0; 1975 while ((ImportDescriptor->Name) && 1976 (ImportDescriptor->OriginalFirstThunk)) 1977 { 1978 /* Get the image thunk */ 1979 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase + 1980 ImportDescriptor->FirstThunk); 1981 while (*ImageThunk) 1982 #endif 1983 { 1984 /* Do we already have an address? */ 1985 if (DllBase) 1986 { 1987 /* Is the thunk in the same address? */ 1988 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd)) 1989 { 1990 /* Skip it, we already have a reference for it */ 1991 ASSERT(EntryArray[j]); 1992 ImageThunk++; 1993 continue; 1994 } 1995 } 1996 1997 /* Loop the loaded module list to locate this address owner */ 1998 j = 0; 1999 NextEntry2 = PsLoadedModuleList.Flink; 2000 while (NextEntry2 != &PsLoadedModuleList) 2001 { 2002 /* Get the entry */ 2003 LdrEntry2 = CONTAINING_RECORD(NextEntry2, 2004 LDR_DATA_TABLE_ENTRY, 2005 InLoadOrderLinks); 2006 2007 /* Get the address range for this module */ 2008 DllBase = (ULONG_PTR)LdrEntry2->DllBase; 2009 DllEnd = DllBase + LdrEntry2->SizeOfImage; 2010 2011 /* Check if this IAT entry matches it */ 2012 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd)) 2013 { 2014 /* Save it */ 2015 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName); 2016 EntryArray[j] = LdrEntry2; 2017 break; 2018 } 2019 2020 /* Keep searching */ 2021 NextEntry2 = NextEntry2->Flink; 2022 j++; 2023 } 2024 2025 /* Do we have a thunk outside the range? */ 2026 if ((*ImageThunk < DllBase) || (*ImageThunk >= DllEnd)) 2027 { 2028 /* Could be 0... */ 2029 if (*ImageThunk) 2030 { 2031 /* Should not be happening */ 2032 ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n", 2033 LdrEntry, ImageThunk, *ImageThunk); 2034 } 2035 2036 /* Reset if we hit this */ 2037 DllBase = 0; 2038 } 2039 #ifndef _WORKING_LOADER_ 2040 ImageThunk++; 2041 } 2042 2043 i++; 2044 ImportDescriptor++; 2045 #endif 2046 } 2047 2048 /* Now scan how many imports we really have */ 2049 for (i = 0, ImportSize = 0; i < Modules; i++) 2050 { 2051 /* Skip HAL and kernel */ 2052 if ((EntryArray[i]) && 2053 (EntryArray[i] != HalEntry) && 2054 (EntryArray[i] != KernelEntry)) 2055 { 2056 /* A valid reference */ 2057 LastEntry = EntryArray[i]; 2058 ImportSize++; 2059 } 2060 } 2061 2062 /* Do we have any imports after all? */ 2063 if (!ImportSize) 2064 { 2065 /* No */ 2066 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS; 2067 } 2068 else if (ImportSize == 1) 2069 { 2070 /* A single entry import */ 2071 LdrEntry->LoadedImports = (PVOID)((ULONG_PTR)LastEntry | MM_SYSLDR_SINGLE_ENTRY); 2072 LastEntry->LoadCount++; 2073 } 2074 else 2075 { 2076 /* We need an import table */ 2077 LoadedImportsSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T); 2078 LoadedImports = ExAllocatePoolWithTag(PagedPool, 2079 LoadedImportsSize, 2080 TAG_LDR_IMPORTS); 2081 ASSERT(LoadedImports); 2082 2083 /* Save the count */ 2084 LoadedImports->Count = ImportSize; 2085 2086 /* Now copy all imports */ 2087 for (i = 0, j = 0; i < Modules; i++) 2088 { 2089 /* Skip HAL and kernel */ 2090 if ((EntryArray[i]) && 2091 (EntryArray[i] != HalEntry) && 2092 (EntryArray[i] != KernelEntry)) 2093 { 2094 /* A valid reference */ 2095 //DPRINT1("Found valid entry: %p\n", EntryArray[i]); 2096 LoadedImports->Entry[j] = EntryArray[i]; 2097 EntryArray[i]->LoadCount++; 2098 j++; 2099 } 2100 } 2101 2102 /* Should had as many entries as we expected */ 2103 ASSERT(j == ImportSize); 2104 LdrEntry->LoadedImports = LoadedImports; 2105 } 2106 2107 /* Next */ 2108 NextEntry = NextEntry->Flink; 2109 } 2110 2111 /* Free the initial array */ 2112 ExFreePoolWithTag(EntryArray, TAG_LDR_IMPORTS); 2113 2114 /* FIXME: Might not need to keep the HAL/Kernel imports around */ 2115 2116 /* Kernel and HAL are loaded at boot */ 2117 KernelEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 2118 HalEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 2119 2120 /* All worked well */ 2121 return STATUS_SUCCESS; 2122 } 2123 2124 VOID 2125 NTAPI 2126 INIT_FUNCTION 2127 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 2128 { 2129 ULONG_PTR DllBase; 2130 PIMAGE_NT_HEADERS NtHeaders; 2131 PIMAGE_SECTION_HEADER SectionHeader; 2132 ULONG Sections, Size; 2133 2134 /* Get the kernel section header */ 2135 DllBase = (ULONG_PTR)LdrEntry->DllBase; 2136 NtHeaders = RtlImageNtHeader((PVOID)DllBase); 2137 SectionHeader = IMAGE_FIRST_SECTION(NtHeaders); 2138 2139 /* Loop all the sections */ 2140 Sections = NtHeaders->FileHeader.NumberOfSections; 2141 while (Sections) 2142 { 2143 /* Grab the size of the section */ 2144 Size = max(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize); 2145 2146 /* Check for .RSRC section */ 2147 if (*(PULONG)SectionHeader->Name == 'rsr.') 2148 { 2149 /* Remember the PTEs so we can modify them later */ 2150 MiKernelResourceStartPte = MiAddressToPte(DllBase + 2151 SectionHeader->VirtualAddress); 2152 MiKernelResourceEndPte = MiKernelResourceStartPte + 2153 BYTES_TO_PAGES(SectionHeader->VirtualAddress + Size); 2154 } 2155 else if (*(PULONG)SectionHeader->Name == 'LOOP') 2156 { 2157 /* POOLCODE vs. POOLMI */ 2158 if (*(PULONG)&SectionHeader->Name[4] == 'EDOC') 2159 { 2160 /* Found Ex* Pool code */ 2161 ExPoolCodeStart = DllBase + SectionHeader->VirtualAddress; 2162 ExPoolCodeEnd = ExPoolCodeStart + Size; 2163 } 2164 else if (*(PUSHORT)&SectionHeader->Name[4] == 'MI') 2165 { 2166 /* Found Mm* Pool code */ 2167 MmPoolCodeStart = DllBase + SectionHeader->VirtualAddress; 2168 MmPoolCodeEnd = ExPoolCodeStart + Size; 2169 } 2170 } 2171 else if ((*(PULONG)SectionHeader->Name == 'YSIM') && 2172 (*(PULONG)&SectionHeader->Name[4] == 'ETPS')) 2173 { 2174 /* Found MISYSPTE (Mm System PTE code)*/ 2175 MmPteCodeStart = DllBase + SectionHeader->VirtualAddress; 2176 MmPteCodeEnd = ExPoolCodeStart + Size; 2177 } 2178 2179 /* Keep going */ 2180 Sections--; 2181 SectionHeader++; 2182 } 2183 } 2184 2185 BOOLEAN 2186 NTAPI 2187 INIT_FUNCTION 2188 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 2189 { 2190 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry; 2191 PLIST_ENTRY ListHead, NextEntry; 2192 ULONG EntrySize; 2193 2194 /* Setup the loaded module list and locks */ 2195 ExInitializeResourceLite(&PsLoadedModuleResource); 2196 KeInitializeSpinLock(&PsLoadedModuleSpinLock); 2197 InitializeListHead(&PsLoadedModuleList); 2198 2199 /* Get loop variables and the kernel entry */ 2200 ListHead = &LoaderBlock->LoadOrderListHead; 2201 NextEntry = ListHead->Flink; 2202 LdrEntry = CONTAINING_RECORD(NextEntry, 2203 LDR_DATA_TABLE_ENTRY, 2204 InLoadOrderLinks); 2205 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase; 2206 2207 /* Locate resource section, pool code, and system pte code */ 2208 MiLocateKernelSections(LdrEntry); 2209 2210 /* Loop the loader block */ 2211 while (NextEntry != ListHead) 2212 { 2213 /* Get the loader entry */ 2214 LdrEntry = CONTAINING_RECORD(NextEntry, 2215 LDR_DATA_TABLE_ENTRY, 2216 InLoadOrderLinks); 2217 2218 /* FIXME: ROS HACK. Make sure this is a driver */ 2219 if (!RtlImageNtHeader(LdrEntry->DllBase)) 2220 { 2221 /* Skip this entry */ 2222 NextEntry = NextEntry->Flink; 2223 continue; 2224 } 2225 2226 /* Calculate the size we'll need and allocate a copy */ 2227 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) + 2228 LdrEntry->BaseDllName.MaximumLength + 2229 sizeof(UNICODE_NULL); 2230 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT); 2231 if (!NewEntry) return FALSE; 2232 2233 /* Copy the entry over */ 2234 *NewEntry = *LdrEntry; 2235 2236 /* Allocate the name */ 2237 NewEntry->FullDllName.Buffer = 2238 ExAllocatePoolWithTag(PagedPool, 2239 LdrEntry->FullDllName.MaximumLength + 2240 sizeof(UNICODE_NULL), 2241 TAG_LDR_WSTR); 2242 if (!NewEntry->FullDllName.Buffer) 2243 { 2244 ExFreePoolWithTag(NewEntry, TAG_MODULE_OBJECT); 2245 return FALSE; 2246 } 2247 2248 /* Set the base name */ 2249 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1); 2250 2251 /* Copy the full and base name */ 2252 RtlCopyMemory(NewEntry->FullDllName.Buffer, 2253 LdrEntry->FullDllName.Buffer, 2254 LdrEntry->FullDllName.MaximumLength); 2255 RtlCopyMemory(NewEntry->BaseDllName.Buffer, 2256 LdrEntry->BaseDllName.Buffer, 2257 LdrEntry->BaseDllName.MaximumLength); 2258 2259 /* Null-terminate the base name */ 2260 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length / 2261 sizeof(WCHAR)] = UNICODE_NULL; 2262 2263 /* Insert the entry into the list */ 2264 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks); 2265 NextEntry = NextEntry->Flink; 2266 } 2267 2268 /* Build the import lists for the boot drivers */ 2269 MiBuildImportsForBootDrivers(); 2270 2271 /* We're done */ 2272 return TRUE; 2273 } 2274 2275 LOGICAL 2276 NTAPI 2277 MiUseLargeDriverPage(IN ULONG NumberOfPtes, 2278 IN OUT PVOID *ImageBaseAddress, 2279 IN PUNICODE_STRING BaseImageName, 2280 IN BOOLEAN BootDriver) 2281 { 2282 PLIST_ENTRY NextEntry; 2283 BOOLEAN DriverFound = FALSE; 2284 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry; 2285 ASSERT(KeGetCurrentIrql () <= APC_LEVEL); 2286 ASSERT(*ImageBaseAddress >= MmSystemRangeStart); 2287 2288 #ifdef _X86_ 2289 if (!(KeFeatureBits & KF_LARGE_PAGE)) return FALSE; 2290 if (!(__readcr4() & CR4_PSE)) return FALSE; 2291 #endif 2292 2293 /* Make sure there's enough system PTEs for a large page driver */ 2294 if (MmTotalFreeSystemPtes[SystemPteSpace] < (16 * (PDE_MAPPED_VA >> PAGE_SHIFT))) 2295 { 2296 return FALSE; 2297 } 2298 2299 /* This happens if the registry key had a "*" (wildcard) in it */ 2300 if (MiLargePageAllDrivers == 0) 2301 { 2302 /* It didn't, so scan the list */ 2303 NextEntry = MiLargePageDriverList.Flink; 2304 while (NextEntry != &MiLargePageDriverList) 2305 { 2306 /* Check if the driver name matches */ 2307 LargePageDriverEntry = CONTAINING_RECORD(NextEntry, 2308 MI_LARGE_PAGE_DRIVER_ENTRY, 2309 Links); 2310 if (RtlEqualUnicodeString(BaseImageName, 2311 &LargePageDriverEntry->BaseName, 2312 TRUE)) 2313 { 2314 /* Enable large pages for this driver */ 2315 DriverFound = TRUE; 2316 break; 2317 } 2318 2319 /* Keep trying */ 2320 NextEntry = NextEntry->Flink; 2321 } 2322 2323 /* If we didn't find the driver, it doesn't need large pages */ 2324 if (DriverFound == FALSE) return FALSE; 2325 } 2326 2327 /* Nothing to do yet */ 2328 DPRINT1("Large pages not supported!\n"); 2329 return FALSE; 2330 } 2331 2332 ULONG 2333 NTAPI 2334 MiComputeDriverProtection(IN BOOLEAN SessionSpace, 2335 IN ULONG SectionProtection) 2336 { 2337 ULONG Protection = MM_ZERO_ACCESS; 2338 2339 /* Check if the caller gave anything */ 2340 if (SectionProtection) 2341 { 2342 /* Always turn on execute access */ 2343 SectionProtection |= IMAGE_SCN_MEM_EXECUTE; 2344 2345 /* Check if the registry setting is on or not */ 2346 if (!MmEnforceWriteProtection) 2347 { 2348 /* Turn on write access too */ 2349 SectionProtection |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE); 2350 } 2351 } 2352 2353 /* Convert to internal PTE flags */ 2354 if (SectionProtection & IMAGE_SCN_MEM_EXECUTE) Protection |= MM_EXECUTE; 2355 if (SectionProtection & IMAGE_SCN_MEM_READ) Protection |= MM_READONLY; 2356 2357 /* Check for write access */ 2358 if (SectionProtection & IMAGE_SCN_MEM_WRITE) 2359 { 2360 /* Session space is not supported */ 2361 if (SessionSpace) 2362 { 2363 DPRINT1("Session drivers not supported\n"); 2364 ASSERT(SessionSpace == FALSE); 2365 } 2366 else 2367 { 2368 /* Convert to internal PTE flag */ 2369 Protection = (Protection & MM_EXECUTE) ? MM_EXECUTE_READWRITE : MM_READWRITE; 2370 } 2371 } 2372 2373 /* If there's no access at all by now, convert to internal no access flag */ 2374 if (Protection == MM_ZERO_ACCESS) Protection = MM_NOACCESS; 2375 2376 /* Return the computed PTE protection */ 2377 return Protection; 2378 } 2379 2380 VOID 2381 NTAPI 2382 MiSetSystemCodeProtection(IN PMMPTE FirstPte, 2383 IN PMMPTE LastPte, 2384 IN ULONG ProtectionMask) 2385 { 2386 /* I'm afraid to introduce regressions at the moment... */ 2387 return; 2388 } 2389 2390 VOID 2391 NTAPI 2392 MiWriteProtectSystemImage(IN PVOID ImageBase) 2393 { 2394 PIMAGE_NT_HEADERS NtHeaders; 2395 PIMAGE_SECTION_HEADER Section; 2396 PFN_NUMBER DriverPages; 2397 ULONG CurrentProtection, SectionProtection, CombinedProtection = 0, ProtectionMask; 2398 ULONG Sections, Size; 2399 ULONG_PTR BaseAddress, CurrentAddress; 2400 PMMPTE PointerPte, StartPte, LastPte, CurrentPte, ComboPte = NULL; 2401 ULONG CurrentMask, CombinedMask = 0; 2402 PAGED_CODE(); 2403 2404 /* No need to write protect physical memory-backed drivers (large pages) */ 2405 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return; 2406 2407 /* Get the image headers */ 2408 NtHeaders = RtlImageNtHeader(ImageBase); 2409 if (!NtHeaders) return; 2410 2411 /* Check if this is a session driver or not */ 2412 if (!MI_IS_SESSION_ADDRESS(ImageBase)) 2413 { 2414 /* Don't touch NT4 drivers */ 2415 if (NtHeaders->OptionalHeader.MajorOperatingSystemVersion < 5) return; 2416 if (NtHeaders->OptionalHeader.MajorImageVersion < 5) return; 2417 } 2418 else 2419 { 2420 /* Not supported */ 2421 UNIMPLEMENTED_DBGBREAK("Session drivers not supported\n"); 2422 } 2423 2424 /* These are the only protection masks we care about */ 2425 ProtectionMask = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE; 2426 2427 /* Calculate the number of pages this driver is occupying */ 2428 DriverPages = BYTES_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage); 2429 2430 /* Get the number of sections and the first section header */ 2431 Sections = NtHeaders->FileHeader.NumberOfSections; 2432 ASSERT(Sections != 0); 2433 Section = IMAGE_FIRST_SECTION(NtHeaders); 2434 2435 /* Loop all the sections */ 2436 CurrentAddress = (ULONG_PTR)ImageBase; 2437 while (Sections) 2438 { 2439 /* Get the section size */ 2440 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 2441 2442 /* Get its virtual address */ 2443 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress; 2444 if (BaseAddress < CurrentAddress) 2445 { 2446 /* Windows doesn't like these */ 2447 DPRINT1("Badly linked image!\n"); 2448 return; 2449 } 2450 2451 /* Remember the current address */ 2452 CurrentAddress = BaseAddress + Size - 1; 2453 2454 /* Next */ 2455 Sections--; 2456 Section++; 2457 } 2458 2459 /* Get the number of sections and the first section header */ 2460 Sections = NtHeaders->FileHeader.NumberOfSections; 2461 ASSERT(Sections != 0); 2462 Section = IMAGE_FIRST_SECTION(NtHeaders); 2463 2464 /* Set the address at the end to initialize the loop */ 2465 CurrentAddress = (ULONG_PTR)Section + Sections - 1; 2466 CurrentProtection = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ; 2467 2468 /* Set the PTE points for the image, and loop its sections */ 2469 StartPte = MiAddressToPte(ImageBase); 2470 LastPte = StartPte + DriverPages; 2471 while (Sections) 2472 { 2473 /* Get the section size */ 2474 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 2475 2476 /* Get its virtual address and PTE */ 2477 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress; 2478 PointerPte = MiAddressToPte(BaseAddress); 2479 2480 /* Check if we were already protecting a run, and found a new run */ 2481 if ((ComboPte) && (PointerPte > ComboPte)) 2482 { 2483 /* Compute protection */ 2484 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection); 2485 2486 /* Set it */ 2487 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask); 2488 2489 /* Check for overlap */ 2490 if (ComboPte == StartPte) StartPte++; 2491 2492 /* One done, reset variables */ 2493 ComboPte = NULL; 2494 CombinedProtection = 0; 2495 } 2496 2497 /* Break out when needed */ 2498 if (PointerPte >= LastPte) break; 2499 2500 /* Get the requested protection from the image header */ 2501 SectionProtection = Section->Characteristics & ProtectionMask; 2502 if (SectionProtection == CurrentProtection) 2503 { 2504 /* Same protection, so merge the request */ 2505 CurrentAddress = BaseAddress + Size - 1; 2506 2507 /* Next */ 2508 Sections--; 2509 Section++; 2510 continue; 2511 } 2512 2513 /* This is now a new section, so close up the old one */ 2514 CurrentPte = MiAddressToPte(CurrentAddress); 2515 2516 /* Check for overlap */ 2517 if (CurrentPte == PointerPte) 2518 { 2519 /* Skip the last PTE, since it overlaps with us */ 2520 CurrentPte--; 2521 2522 /* And set the PTE we will merge with */ 2523 ASSERT((ComboPte == NULL) || (ComboPte == PointerPte)); 2524 ComboPte = PointerPte; 2525 2526 /* Get the most flexible protection by merging both */ 2527 CombinedMask |= (SectionProtection | CurrentProtection); 2528 } 2529 2530 /* Loop any PTEs left */ 2531 if (CurrentPte >= StartPte) 2532 { 2533 /* Sanity check */ 2534 ASSERT(StartPte < LastPte); 2535 2536 /* Make sure we don't overflow past the last PTE in the driver */ 2537 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1; 2538 ASSERT(CurrentPte >= StartPte); 2539 2540 /* Compute the protection and set it */ 2541 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection); 2542 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask); 2543 } 2544 2545 /* Set new state */ 2546 StartPte = PointerPte; 2547 CurrentAddress = BaseAddress + Size - 1; 2548 CurrentProtection = SectionProtection; 2549 2550 /* Next */ 2551 Sections--; 2552 Section++; 2553 } 2554 2555 /* Is there a leftover section to merge? */ 2556 if (ComboPte) 2557 { 2558 /* Compute and set the protection */ 2559 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection); 2560 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask); 2561 2562 /* Handle overlap */ 2563 if (ComboPte == StartPte) StartPte++; 2564 } 2565 2566 /* Finally, handle the last section */ 2567 CurrentPte = MiAddressToPte(CurrentAddress); 2568 if ((StartPte < LastPte) && (CurrentPte >= StartPte)) 2569 { 2570 /* Handle overlap */ 2571 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1; 2572 ASSERT(CurrentPte >= StartPte); 2573 2574 /* Compute and set the protection */ 2575 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection); 2576 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask); 2577 } 2578 } 2579 2580 VOID 2581 NTAPI 2582 MiSetPagingOfDriver(IN PMMPTE PointerPte, 2583 IN PMMPTE LastPte) 2584 { 2585 PVOID ImageBase; 2586 PETHREAD CurrentThread = PsGetCurrentThread(); 2587 PFN_COUNT PageCount = 0; 2588 PFN_NUMBER PageFrameIndex; 2589 PMMPFN Pfn1; 2590 PAGED_CODE(); 2591 2592 /* The page fault handler is broken and doesn't page back in! */ 2593 DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n"); 2594 return; 2595 2596 /* Get the driver's base address */ 2597 ImageBase = MiPteToAddress(PointerPte); 2598 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE); 2599 2600 /* If this is a large page, it's stuck in physical memory */ 2601 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return; 2602 2603 /* Lock the working set */ 2604 MiLockWorkingSet(CurrentThread, &MmSystemCacheWs); 2605 2606 /* Loop the PTEs */ 2607 while (PointerPte <= LastPte) 2608 { 2609 /* Check for valid PTE */ 2610 if (PointerPte->u.Hard.Valid == 1) 2611 { 2612 PageFrameIndex = PFN_FROM_PTE(PointerPte); 2613 Pfn1 = MiGetPfnEntry(PageFrameIndex); 2614 ASSERT(Pfn1->u2.ShareCount == 1); 2615 2616 /* No working sets in ReactOS yet */ 2617 PageCount++; 2618 } 2619 2620 ImageBase = (PVOID)((ULONG_PTR)ImageBase + PAGE_SIZE); 2621 PointerPte++; 2622 } 2623 2624 /* Release the working set */ 2625 MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs); 2626 2627 /* Do we have any driver pages? */ 2628 if (PageCount) 2629 { 2630 /* Update counters */ 2631 InterlockedExchangeAdd((PLONG)&MmTotalSystemDriverPages, PageCount); 2632 } 2633 } 2634 2635 VOID 2636 NTAPI 2637 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 2638 { 2639 ULONG_PTR ImageBase; 2640 PIMAGE_NT_HEADERS NtHeaders; 2641 ULONG Sections, Alignment, Size; 2642 PIMAGE_SECTION_HEADER Section; 2643 PMMPTE PointerPte = NULL, LastPte = NULL; 2644 if (MmDisablePagingExecutive) return; 2645 2646 /* Get the driver base address and its NT header */ 2647 ImageBase = (ULONG_PTR)LdrEntry->DllBase; 2648 NtHeaders = RtlImageNtHeader((PVOID)ImageBase); 2649 if (!NtHeaders) return; 2650 2651 /* Get the sections and their alignment */ 2652 Sections = NtHeaders->FileHeader.NumberOfSections; 2653 Alignment = NtHeaders->OptionalHeader.SectionAlignment - 1; 2654 2655 /* Loop each section */ 2656 Section = IMAGE_FIRST_SECTION(NtHeaders); 2657 while (Sections) 2658 { 2659 /* Find PAGE or .edata */ 2660 if ((*(PULONG)Section->Name == 'EGAP') || 2661 (*(PULONG)Section->Name == 'ade.')) 2662 { 2663 /* Had we already done some work? */ 2664 if (!PointerPte) 2665 { 2666 /* Nope, setup the first PTE address */ 2667 PointerPte = MiAddressToPte(ROUND_TO_PAGES(ImageBase + 2668 Section-> 2669 VirtualAddress)); 2670 } 2671 2672 /* Compute the size */ 2673 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 2674 2675 /* Find the last PTE that maps this section */ 2676 LastPte = MiAddressToPte(ImageBase + 2677 Section->VirtualAddress + 2678 Alignment + 2679 Size - 2680 PAGE_SIZE); 2681 } 2682 else 2683 { 2684 /* Had we found a section before? */ 2685 if (PointerPte) 2686 { 2687 /* Mark it as pageable */ 2688 MiSetPagingOfDriver(PointerPte, LastPte); 2689 PointerPte = NULL; 2690 } 2691 } 2692 2693 /* Keep searching */ 2694 Sections--; 2695 Section++; 2696 } 2697 2698 /* Handle the straggler */ 2699 if (PointerPte) MiSetPagingOfDriver(PointerPte, LastPte); 2700 } 2701 2702 BOOLEAN 2703 NTAPI 2704 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress) 2705 { 2706 PIMAGE_NT_HEADERS NtHeader; 2707 PAGED_CODE(); 2708 2709 /* Get NT Headers */ 2710 NtHeader = RtlImageNtHeader(BaseAddress); 2711 if (NtHeader) 2712 { 2713 /* Check if this image is only safe for UP while we have 2+ CPUs */ 2714 if ((KeNumberProcessors > 1) && 2715 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)) 2716 { 2717 /* Fail */ 2718 return FALSE; 2719 } 2720 } 2721 2722 /* Otherwise, it's safe */ 2723 return TRUE; 2724 } 2725 2726 NTSTATUS 2727 NTAPI 2728 MmCheckSystemImage(IN HANDLE ImageHandle, 2729 IN BOOLEAN PurgeSection) 2730 { 2731 NTSTATUS Status; 2732 HANDLE SectionHandle; 2733 PVOID ViewBase = NULL; 2734 SIZE_T ViewSize = 0; 2735 IO_STATUS_BLOCK IoStatusBlock; 2736 FILE_STANDARD_INFORMATION FileStandardInfo; 2737 KAPC_STATE ApcState; 2738 PIMAGE_NT_HEADERS NtHeaders; 2739 OBJECT_ATTRIBUTES ObjectAttributes; 2740 PAGED_CODE(); 2741 2742 /* Setup the object attributes */ 2743 InitializeObjectAttributes(&ObjectAttributes, 2744 NULL, 2745 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2746 NULL, 2747 NULL); 2748 2749 /* Create a section for the DLL */ 2750 Status = ZwCreateSection(&SectionHandle, 2751 SECTION_MAP_EXECUTE, 2752 &ObjectAttributes, 2753 NULL, 2754 PAGE_EXECUTE, 2755 SEC_IMAGE, 2756 ImageHandle); 2757 if (!NT_SUCCESS(Status)) 2758 { 2759 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status); 2760 return Status; 2761 } 2762 2763 /* Make sure we're in the system process */ 2764 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 2765 2766 /* Map it */ 2767 Status = ZwMapViewOfSection(SectionHandle, 2768 NtCurrentProcess(), 2769 &ViewBase, 2770 0, 2771 0, 2772 NULL, 2773 &ViewSize, 2774 ViewShare, 2775 0, 2776 PAGE_EXECUTE); 2777 if (!NT_SUCCESS(Status)) 2778 { 2779 /* We failed, close the handle and return */ 2780 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status); 2781 KeUnstackDetachProcess(&ApcState); 2782 ZwClose(SectionHandle); 2783 return Status; 2784 } 2785 2786 /* Now query image information */ 2787 Status = ZwQueryInformationFile(ImageHandle, 2788 &IoStatusBlock, 2789 &FileStandardInfo, 2790 sizeof(FileStandardInfo), 2791 FileStandardInformation); 2792 if (NT_SUCCESS(Status)) 2793 { 2794 /* First, verify the checksum */ 2795 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase, 2796 ViewSize, 2797 FileStandardInfo. 2798 EndOfFile.LowPart)) 2799 { 2800 /* Set checksum failure */ 2801 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 2802 goto Fail; 2803 } 2804 2805 /* Make sure it's a real image */ 2806 NtHeaders = RtlImageNtHeader(ViewBase); 2807 if (!NtHeaders) 2808 { 2809 /* Set checksum failure */ 2810 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 2811 goto Fail; 2812 } 2813 2814 /* Make sure it's for the correct architecture */ 2815 if ((NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE) || 2816 (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) 2817 { 2818 /* Set protection failure */ 2819 Status = STATUS_INVALID_IMAGE_PROTECT; 2820 goto Fail; 2821 } 2822 2823 /* Check that it's a valid SMP image if we have more then one CPU */ 2824 if (!MmVerifyImageIsOkForMpUse(ViewBase)) 2825 { 2826 /* Otherwise it's not the right image */ 2827 Status = STATUS_IMAGE_MP_UP_MISMATCH; 2828 } 2829 } 2830 2831 /* Unmap the section, close the handle, and return status */ 2832 Fail: 2833 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase); 2834 KeUnstackDetachProcess(&ApcState); 2835 ZwClose(SectionHandle); 2836 return Status; 2837 } 2838 2839 NTSTATUS 2840 NTAPI 2841 MmLoadSystemImage(IN PUNICODE_STRING FileName, 2842 IN PUNICODE_STRING NamePrefix OPTIONAL, 2843 IN PUNICODE_STRING LoadedName OPTIONAL, 2844 IN ULONG Flags, 2845 OUT PVOID *ModuleObject, 2846 OUT PVOID *ImageBaseAddress) 2847 { 2848 PVOID ModuleLoadBase = NULL; 2849 NTSTATUS Status; 2850 HANDLE FileHandle = NULL; 2851 OBJECT_ATTRIBUTES ObjectAttributes; 2852 IO_STATUS_BLOCK IoStatusBlock; 2853 PIMAGE_NT_HEADERS NtHeader; 2854 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp; 2855 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL; 2856 ULONG EntrySize, DriverSize; 2857 PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS; 2858 PCHAR MissingApiName, Buffer; 2859 PWCHAR MissingDriverName; 2860 HANDLE SectionHandle; 2861 ACCESS_MASK DesiredAccess; 2862 PVOID Section = NULL; 2863 BOOLEAN LockOwned = FALSE; 2864 PLIST_ENTRY NextEntry; 2865 IMAGE_INFO ImageInfo; 2866 STRING AnsiTemp; 2867 PAGED_CODE(); 2868 2869 /* Detect session-load */ 2870 if (Flags) 2871 { 2872 /* Sanity checks */ 2873 ASSERT(NamePrefix == NULL); 2874 ASSERT(LoadedName == NULL); 2875 2876 /* Make sure the process is in session too */ 2877 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY; 2878 } 2879 2880 /* Allocate a buffer we'll use for names */ 2881 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR); 2882 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 2883 2884 /* Check for a separator */ 2885 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) 2886 { 2887 PWCHAR p; 2888 ULONG BaseLength; 2889 2890 /* Loop the path until we get to the base name */ 2891 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)]; 2892 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--; 2893 2894 /* Get the length */ 2895 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p); 2896 BaseLength *= sizeof(WCHAR); 2897 2898 /* Setup the string */ 2899 BaseName.Length = (USHORT)BaseLength; 2900 BaseName.Buffer = p; 2901 } 2902 else 2903 { 2904 /* Otherwise, we already have a base name */ 2905 BaseName.Length = FileName->Length; 2906 BaseName.Buffer = FileName->Buffer; 2907 } 2908 2909 /* Setup the maximum length */ 2910 BaseName.MaximumLength = BaseName.Length; 2911 2912 /* Now compute the base directory */ 2913 BaseDirectory = *FileName; 2914 BaseDirectory.Length -= BaseName.Length; 2915 BaseDirectory.MaximumLength = BaseDirectory.Length; 2916 2917 /* And the prefix, which for now is just the name itself */ 2918 PrefixName = *FileName; 2919 2920 /* Check if we have a prefix */ 2921 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n"); 2922 2923 /* Check if we already have a name, use it instead */ 2924 if (LoadedName) BaseName = *LoadedName; 2925 2926 /* Check for loader snap debugging */ 2927 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) 2928 { 2929 /* Print out standard string */ 2930 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n", 2931 &PrefixName, &BaseName, Flags ? "in session space" : ""); 2932 } 2933 2934 /* Acquire the load lock */ 2935 LoaderScan: 2936 ASSERT(LockOwned == FALSE); 2937 LockOwned = TRUE; 2938 KeEnterCriticalRegion(); 2939 KeWaitForSingleObject(&MmSystemLoadLock, 2940 WrVirtualMemory, 2941 KernelMode, 2942 FALSE, 2943 NULL); 2944 2945 /* Scan the module list */ 2946 NextEntry = PsLoadedModuleList.Flink; 2947 while (NextEntry != &PsLoadedModuleList) 2948 { 2949 /* Get the entry and compare the names */ 2950 LdrEntry = CONTAINING_RECORD(NextEntry, 2951 LDR_DATA_TABLE_ENTRY, 2952 InLoadOrderLinks); 2953 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE)) 2954 { 2955 /* Found it, break out */ 2956 break; 2957 } 2958 2959 /* Keep scanning */ 2960 NextEntry = NextEntry->Flink; 2961 } 2962 2963 /* Check if we found the image */ 2964 if (NextEntry != &PsLoadedModuleList) 2965 { 2966 /* Check if we had already mapped a section */ 2967 if (Section) 2968 { 2969 /* Dereference and clear */ 2970 ObDereferenceObject(Section); 2971 Section = NULL; 2972 } 2973 2974 /* Check if this was supposed to be a session load */ 2975 if (!Flags) 2976 { 2977 /* It wasn't, so just return the data */ 2978 *ModuleObject = LdrEntry; 2979 *ImageBaseAddress = LdrEntry->DllBase; 2980 Status = STATUS_IMAGE_ALREADY_LOADED; 2981 } 2982 else 2983 { 2984 /* We don't support session loading yet */ 2985 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n"); 2986 Status = STATUS_NOT_IMPLEMENTED; 2987 } 2988 2989 /* Do cleanup */ 2990 goto Quickie; 2991 } 2992 else if (!Section) 2993 { 2994 /* It wasn't loaded, and we didn't have a previous attempt */ 2995 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE); 2996 KeLeaveCriticalRegion(); 2997 LockOwned = FALSE; 2998 2999 /* Check if KD is enabled */ 3000 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent)) 3001 { 3002 /* FIXME: Attempt to get image from KD */ 3003 } 3004 3005 /* We don't have a valid entry */ 3006 LdrEntry = NULL; 3007 3008 /* Setup image attributes */ 3009 InitializeObjectAttributes(&ObjectAttributes, 3010 FileName, 3011 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3012 NULL, 3013 NULL); 3014 3015 /* Open the image */ 3016 Status = ZwOpenFile(&FileHandle, 3017 FILE_EXECUTE, 3018 &ObjectAttributes, 3019 &IoStatusBlock, 3020 FILE_SHARE_READ | FILE_SHARE_DELETE, 3021 0); 3022 if (!NT_SUCCESS(Status)) 3023 { 3024 DPRINT1("ZwOpenFile failed for '%wZ' with status 0x%x\n", 3025 FileName, Status); 3026 goto Quickie; 3027 } 3028 3029 /* Validate it */ 3030 Status = MmCheckSystemImage(FileHandle, FALSE); 3031 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) || 3032 (Status == STATUS_IMAGE_MP_UP_MISMATCH) || 3033 (Status == STATUS_INVALID_IMAGE_PROTECT)) 3034 { 3035 /* Fail loading */ 3036 goto Quickie; 3037 } 3038 3039 /* Check if this is a session-load */ 3040 if (Flags) 3041 { 3042 /* Then we only need read and execute */ 3043 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE; 3044 } 3045 else 3046 { 3047 /* Otherwise, we can allow write access */ 3048 DesiredAccess = SECTION_ALL_ACCESS; 3049 } 3050 3051 /* Initialize the attributes for the section */ 3052 InitializeObjectAttributes(&ObjectAttributes, 3053 NULL, 3054 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 3055 NULL, 3056 NULL); 3057 3058 /* Create the section */ 3059 Status = ZwCreateSection(&SectionHandle, 3060 DesiredAccess, 3061 &ObjectAttributes, 3062 NULL, 3063 PAGE_EXECUTE, 3064 SEC_IMAGE, 3065 FileHandle); 3066 if (!NT_SUCCESS(Status)) 3067 { 3068 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status); 3069 goto Quickie; 3070 } 3071 3072 /* Now get the section pointer */ 3073 Status = ObReferenceObjectByHandle(SectionHandle, 3074 SECTION_MAP_EXECUTE, 3075 MmSectionObjectType, 3076 KernelMode, 3077 &Section, 3078 NULL); 3079 ZwClose(SectionHandle); 3080 if (!NT_SUCCESS(Status)) goto Quickie; 3081 3082 /* Check if this was supposed to be a session-load */ 3083 if (Flags) 3084 { 3085 /* We don't support session loading yet */ 3086 UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n"); 3087 goto Quickie; 3088 } 3089 3090 /* Check the loader list again, we should end up in the path below */ 3091 goto LoaderScan; 3092 } 3093 else 3094 { 3095 /* We don't have a valid entry */ 3096 LdrEntry = NULL; 3097 } 3098 3099 /* Load the image */ 3100 Status = MiLoadImageSection(&Section, 3101 &ModuleLoadBase, 3102 FileName, 3103 FALSE, 3104 NULL); 3105 ASSERT(Status != STATUS_ALREADY_COMMITTED); 3106 3107 /* Get the size of the driver */ 3108 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageInformation.ImageFileSize; 3109 3110 /* Make sure we're not being loaded into session space */ 3111 if (!Flags) 3112 { 3113 /* Check for success */ 3114 if (NT_SUCCESS(Status)) 3115 { 3116 /* Support large pages for drivers */ 3117 MiUseLargeDriverPage(DriverSize / PAGE_SIZE, 3118 &ModuleLoadBase, 3119 &BaseName, 3120 TRUE); 3121 } 3122 3123 /* Dereference the section */ 3124 ObDereferenceObject(Section); 3125 Section = NULL; 3126 } 3127 3128 /* Check for failure of the load earlier */ 3129 if (!NT_SUCCESS(Status)) 3130 { 3131 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status); 3132 goto Quickie; 3133 } 3134 3135 /* Relocate the driver */ 3136 Status = LdrRelocateImageWithBias(ModuleLoadBase, 3137 0, 3138 "SYSLDR", 3139 STATUS_SUCCESS, 3140 STATUS_CONFLICTING_ADDRESSES, 3141 STATUS_INVALID_IMAGE_FORMAT); 3142 if (!NT_SUCCESS(Status)) 3143 { 3144 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status); 3145 goto Quickie; 3146 } 3147 3148 /* Get the NT Header */ 3149 NtHeader = RtlImageNtHeader(ModuleLoadBase); 3150 3151 /* Calculate the size we'll need for the entry and allocate it */ 3152 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) + 3153 BaseName.Length + 3154 sizeof(UNICODE_NULL); 3155 3156 /* Allocate the entry */ 3157 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT); 3158 if (!LdrEntry) 3159 { 3160 /* Fail */ 3161 Status = STATUS_INSUFFICIENT_RESOURCES; 3162 goto Quickie; 3163 } 3164 3165 /* Setup the entry */ 3166 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS; 3167 LdrEntry->LoadCount = 1; 3168 LdrEntry->LoadedImports = LoadedImports; 3169 LdrEntry->PatchInformation = NULL; 3170 3171 /* Check the version */ 3172 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) && 3173 (NtHeader->OptionalHeader.MajorImageVersion >= 5)) 3174 { 3175 /* Mark this image as a native image */ 3176 LdrEntry->Flags |= LDRP_ENTRY_NATIVE; 3177 } 3178 3179 /* Setup the rest of the entry */ 3180 LdrEntry->DllBase = ModuleLoadBase; 3181 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase + 3182 NtHeader->OptionalHeader.AddressOfEntryPoint); 3183 LdrEntry->SizeOfImage = DriverSize; 3184 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum; 3185 LdrEntry->SectionPointer = Section; 3186 3187 /* Now write the DLL name */ 3188 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1); 3189 LdrEntry->BaseDllName.Length = BaseName.Length; 3190 LdrEntry->BaseDllName.MaximumLength = BaseName.Length; 3191 3192 /* Copy and null-terminate it */ 3193 RtlCopyMemory(LdrEntry->BaseDllName.Buffer, 3194 BaseName.Buffer, 3195 BaseName.Length); 3196 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL; 3197 3198 /* Now allocate the full name */ 3199 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool, 3200 PrefixName.Length + 3201 sizeof(UNICODE_NULL), 3202 TAG_LDR_WSTR); 3203 if (!LdrEntry->FullDllName.Buffer) 3204 { 3205 /* Don't fail, just set it to zero */ 3206 LdrEntry->FullDllName.Length = 0; 3207 LdrEntry->FullDllName.MaximumLength = 0; 3208 } 3209 else 3210 { 3211 /* Set it up */ 3212 LdrEntry->FullDllName.Length = PrefixName.Length; 3213 LdrEntry->FullDllName.MaximumLength = PrefixName.Length; 3214 3215 /* Copy and null-terminate */ 3216 RtlCopyMemory(LdrEntry->FullDllName.Buffer, 3217 PrefixName.Buffer, 3218 PrefixName.Length); 3219 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL; 3220 } 3221 3222 /* Add the entry */ 3223 MiProcessLoaderEntry(LdrEntry, TRUE); 3224 3225 /* Resolve imports */ 3226 MissingApiName = Buffer; 3227 MissingDriverName = NULL; 3228 Status = MiResolveImageReferences(ModuleLoadBase, 3229 &BaseDirectory, 3230 NULL, 3231 &MissingApiName, 3232 &MissingDriverName, 3233 &LoadedImports); 3234 if (!NT_SUCCESS(Status)) 3235 { 3236 BOOLEAN NeedToFreeString = FALSE; 3237 3238 /* If the lowest bit is set to 1, this is a hint that we need to free */ 3239 if (*(ULONG_PTR*)&MissingDriverName & 1) 3240 { 3241 NeedToFreeString = TRUE; 3242 *(ULONG_PTR*)&MissingDriverName &= ~1; 3243 } 3244 3245 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status); 3246 DPRINT1(" Missing driver '%ls', missing API '%s'\n", 3247 MissingDriverName, MissingApiName); 3248 3249 if (NeedToFreeString) 3250 { 3251 ExFreePoolWithTag(MissingDriverName, TAG_LDR_WSTR); 3252 } 3253 3254 /* Fail */ 3255 MiProcessLoaderEntry(LdrEntry, FALSE); 3256 3257 /* Check if we need to free the name */ 3258 if (LdrEntry->FullDllName.Buffer) 3259 { 3260 /* Free it */ 3261 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR); 3262 } 3263 3264 /* Free the entry itself */ 3265 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT); 3266 LdrEntry = NULL; 3267 goto Quickie; 3268 } 3269 3270 /* Update the loader entry */ 3271 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED | 3272 LDRP_ENTRY_PROCESSED | 3273 LDRP_MM_LOADED); 3274 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS; 3275 LdrEntry->LoadedImports = LoadedImports; 3276 3277 /* FIXME: Call driver verifier's loader function */ 3278 3279 /* Write-protect the system image */ 3280 MiWriteProtectSystemImage(LdrEntry->DllBase); 3281 3282 /* Check if notifications are enabled */ 3283 if (PsImageNotifyEnabled) 3284 { 3285 /* Fill out the notification data */ 3286 ImageInfo.Properties = 0; 3287 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; 3288 ImageInfo.SystemModeImage = TRUE; 3289 ImageInfo.ImageSize = LdrEntry->SizeOfImage; 3290 ImageInfo.ImageBase = LdrEntry->DllBase; 3291 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0; 3292 3293 /* Send the notification */ 3294 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo); 3295 } 3296 3297 #if defined(KDBG) || defined(_WINKD_) 3298 /* MiCacheImageSymbols doesn't detect rossym */ 3299 if (TRUE) 3300 #else 3301 /* Check if there's symbols */ 3302 if (MiCacheImageSymbols(LdrEntry->DllBase)) 3303 #endif 3304 { 3305 /* Check if the system root is present */ 3306 if ((PrefixName.Length > (11 * sizeof(WCHAR))) && 3307 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11))) 3308 { 3309 /* Add the system root */ 3310 UnicodeTemp = PrefixName; 3311 UnicodeTemp.Buffer += 11; 3312 UnicodeTemp.Length -= (11 * sizeof(WCHAR)); 3313 sprintf_nt(Buffer, 3314 "%ws%wZ", 3315 &SharedUserData->NtSystemRoot[2], 3316 &UnicodeTemp); 3317 } 3318 else 3319 { 3320 /* Build the name */ 3321 sprintf_nt(Buffer, "%wZ", &BaseName); 3322 } 3323 3324 /* Setup the ansi string */ 3325 RtlInitString(&AnsiTemp, Buffer); 3326 3327 /* Notify the debugger */ 3328 DbgLoadImageSymbols(&AnsiTemp, 3329 LdrEntry->DllBase, 3330 (ULONG_PTR)PsGetCurrentProcessId()); 3331 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED; 3332 } 3333 3334 /* Page the driver */ 3335 ASSERT(Section == NULL); 3336 MiEnablePagingOfDriver(LdrEntry); 3337 3338 /* Return pointers */ 3339 *ModuleObject = LdrEntry; 3340 *ImageBaseAddress = LdrEntry->DllBase; 3341 3342 Quickie: 3343 /* Check if we have the lock acquired */ 3344 if (LockOwned) 3345 { 3346 /* Release the lock */ 3347 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE); 3348 KeLeaveCriticalRegion(); 3349 LockOwned = FALSE; 3350 } 3351 3352 /* If we have a file handle, close it */ 3353 if (FileHandle) ZwClose(FileHandle); 3354 3355 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */ 3356 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */ 3357 3358 /* Free the name buffer and return status */ 3359 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR); 3360 return Status; 3361 } 3362 3363 PLDR_DATA_TABLE_ENTRY 3364 NTAPI 3365 MiLookupDataTableEntry(IN PVOID Address) 3366 { 3367 PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL; 3368 PLIST_ENTRY NextEntry; 3369 PAGED_CODE(); 3370 3371 /* Loop entries */ 3372 NextEntry = PsLoadedModuleList.Flink; 3373 do 3374 { 3375 /* Get the loader entry */ 3376 LdrEntry = CONTAINING_RECORD(NextEntry, 3377 LDR_DATA_TABLE_ENTRY, 3378 InLoadOrderLinks); 3379 3380 /* Check if the address matches */ 3381 if ((Address >= LdrEntry->DllBase) && 3382 (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase + 3383 LdrEntry->SizeOfImage))) 3384 { 3385 /* Found a match */ 3386 FoundEntry = LdrEntry; 3387 break; 3388 } 3389 3390 /* Move on */ 3391 NextEntry = NextEntry->Flink; 3392 } while(NextEntry != &PsLoadedModuleList); 3393 3394 /* Return the entry */ 3395 return FoundEntry; 3396 } 3397 3398 /* PUBLIC FUNCTIONS ***********************************************************/ 3399 3400 /* 3401 * @implemented 3402 */ 3403 PVOID 3404 NTAPI 3405 MmPageEntireDriver(IN PVOID AddressWithinSection) 3406 { 3407 PMMPTE StartPte, EndPte; 3408 PLDR_DATA_TABLE_ENTRY LdrEntry; 3409 PAGED_CODE(); 3410 3411 /* Get the loader entry */ 3412 LdrEntry = MiLookupDataTableEntry(AddressWithinSection); 3413 if (!LdrEntry) return NULL; 3414 3415 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */ 3416 if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer)) 3417 { 3418 /* Don't do anything, just return the base address */ 3419 return LdrEntry->DllBase; 3420 } 3421 3422 /* Wait for active DPCs to finish before we page out the driver */ 3423 KeFlushQueuedDpcs(); 3424 3425 /* Get the PTE range for the whole driver image */ 3426 StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase); 3427 EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage); 3428 3429 /* Enable paging for the PTE range */ 3430 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE); 3431 MiSetPagingOfDriver(StartPte, EndPte); 3432 3433 /* Return the base address */ 3434 return LdrEntry->DllBase; 3435 } 3436 3437 /* 3438 * @unimplemented 3439 */ 3440 VOID 3441 NTAPI 3442 MmResetDriverPaging(IN PVOID AddressWithinSection) 3443 { 3444 UNIMPLEMENTED; 3445 } 3446 3447 /* 3448 * @implemented 3449 */ 3450 PVOID 3451 NTAPI 3452 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName) 3453 { 3454 PVOID ProcAddress = NULL; 3455 ANSI_STRING AnsiRoutineName; 3456 NTSTATUS Status; 3457 PLIST_ENTRY NextEntry; 3458 PLDR_DATA_TABLE_ENTRY LdrEntry; 3459 BOOLEAN Found = FALSE; 3460 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe"); 3461 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll"); 3462 ULONG Modules = 0; 3463 3464 /* Convert routine to ansi name */ 3465 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName, 3466 SystemRoutineName, 3467 TRUE); 3468 if (!NT_SUCCESS(Status)) return NULL; 3469 3470 /* Lock the list */ 3471 KeEnterCriticalRegion(); 3472 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE); 3473 3474 /* Loop the loaded module list */ 3475 NextEntry = PsLoadedModuleList.Flink; 3476 while (NextEntry != &PsLoadedModuleList) 3477 { 3478 /* Get the entry */ 3479 LdrEntry = CONTAINING_RECORD(NextEntry, 3480 LDR_DATA_TABLE_ENTRY, 3481 InLoadOrderLinks); 3482 3483 /* Check if it's the kernel or HAL */ 3484 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE)) 3485 { 3486 /* Found it */ 3487 Found = TRUE; 3488 Modules++; 3489 } 3490 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE)) 3491 { 3492 /* Found it */ 3493 Found = TRUE; 3494 Modules++; 3495 } 3496 3497 /* Check if we found a valid binary */ 3498 if (Found) 3499 { 3500 /* Find the procedure name */ 3501 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase, 3502 &AnsiRoutineName); 3503 3504 /* Break out if we found it or if we already tried both modules */ 3505 if (ProcAddress) break; 3506 if (Modules == 2) break; 3507 } 3508 3509 /* Keep looping */ 3510 NextEntry = NextEntry->Flink; 3511 } 3512 3513 /* Release the lock */ 3514 ExReleaseResourceLite(&PsLoadedModuleResource); 3515 KeLeaveCriticalRegion(); 3516 3517 /* Free the string and return */ 3518 RtlFreeAnsiString(&AnsiRoutineName); 3519 return ProcAddress; 3520 } 3521 3522 /* EOF */ 3523