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