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