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