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