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