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