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