[NTOS]: Support unload of system modules by parsing the LoadedImports (implement...
[reactos.git] / reactos / ntoskrnl / mm / sysldr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/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 #line 16 "ARM³::LOADER"
17 #define MODULE_INVOLVED_IN_ARM3
18 #include "./ARM3/miarm.h"
19
20 /* GCC's incompetence strikes again */
21 __inline
22 VOID
23 sprintf_nt(IN PCHAR Buffer,
24 IN PCHAR Format,
25 IN ...)
26 {
27 va_list ap;
28 va_start(ap, Format);
29 vsprintf(Buffer, Format, ap);
30 va_end(ap);
31 }
32
33 /* GLOBALS ********************************************************************/
34
35 LIST_ENTRY PsLoadedModuleList;
36 LIST_ENTRY MmLoadedUserImageList;
37 KSPIN_LOCK PsLoadedModuleSpinLock;
38 ERESOURCE PsLoadedModuleResource;
39 ULONG_PTR PsNtosImageBase;
40 KMUTANT MmSystemLoadLock;
41
42 PFN_NUMBER MmTotalSystemDriverPages;
43
44 PVOID MmUnloadedDrivers;
45 PVOID MmLastUnloadedDrivers;
46
47 BOOLEAN MmMakeLowMemory;
48 BOOLEAN MmEnforceWriteProtection = TRUE;
49
50 /* FUNCTIONS ******************************************************************/
51
52 PVOID
53 NTAPI
54 MiCacheImageSymbols(IN PVOID BaseAddress)
55 {
56 ULONG DebugSize;
57 PVOID DebugDirectory = NULL;
58 PAGED_CODE();
59
60 /* Make sure it's safe to access the image */
61 _SEH2_TRY
62 {
63 /* Get the debug directory */
64 DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
65 TRUE,
66 IMAGE_DIRECTORY_ENTRY_DEBUG,
67 &DebugSize);
68 }
69 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
70 {
71 /* Nothing */
72 }
73 _SEH2_END;
74
75 /* Return the directory */
76 return DebugDirectory;
77 }
78
79 NTSTATUS
80 NTAPI
81 MiLoadImageSection(IN OUT PVOID *SectionPtr,
82 OUT PVOID *ImageBase,
83 IN PUNICODE_STRING FileName,
84 IN BOOLEAN SessionLoad,
85 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
86 {
87 PROS_SECTION_OBJECT Section = *SectionPtr;
88 NTSTATUS Status;
89 PEPROCESS Process;
90 PVOID Base = NULL;
91 SIZE_T ViewSize = 0;
92 KAPC_STATE ApcState;
93 LARGE_INTEGER SectionOffset = {{0, 0}};
94 BOOLEAN LoadSymbols = FALSE;
95 PFN_NUMBER PteCount;
96 PMMPTE PointerPte, LastPte;
97 PVOID DriverBase;
98 MMPTE TempPte;
99 PAGED_CODE();
100
101 /* Detect session load */
102 if (SessionLoad)
103 {
104 /* Fail */
105 DPRINT1("Session loading not yet supported!\n");
106 while (TRUE);
107 }
108
109 /* Not session load, shouldn't have an entry */
110 ASSERT(LdrEntry == NULL);
111
112 /* Attach to the system process */
113 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
114
115 /* Check if we need to load symbols */
116 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
117 {
118 /* Yes we do */
119 LoadSymbols = TRUE;
120 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
121 }
122
123 /* Map the driver */
124 Process = PsGetCurrentProcess();
125 Status = MmMapViewOfSection(Section,
126 Process,
127 &Base,
128 0,
129 0,
130 &SectionOffset,
131 &ViewSize,
132 ViewUnmap,
133 0,
134 PAGE_EXECUTE);
135
136 /* Re-enable the flag */
137 if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
138
139 /* Check if we failed with distinguished status code */
140 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
141 {
142 /* Change it to something more generic */
143 Status = STATUS_INVALID_IMAGE_FORMAT;
144 }
145
146 /* Now check if we failed */
147 if (!NT_SUCCESS(Status))
148 {
149 /* Detach and return */
150 KeUnstackDetachProcess(&ApcState);
151 return Status;
152 }
153
154 /* Reserve system PTEs needed */
155 PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT;
156 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
157 if (!PointerPte) return STATUS_INSUFFICIENT_RESOURCES;
158
159 /* New driver base */
160 LastPte = PointerPte + PteCount;
161 DriverBase = MiPteToAddress(PointerPte);
162
163 /* The driver is here */
164 *ImageBase = DriverBase;
165
166 /* Loop the new driver PTEs */
167 TempPte = ValidKernelPte;
168 while (PointerPte < LastPte)
169 {
170 /* Allocate a page */
171 TempPte.u.Hard.PageFrameNumber = MmAllocPage(MC_NPPOOL);
172
173 /* Write it */
174 ASSERT(PointerPte->u.Hard.Valid == 0);
175 ASSERT(TempPte.u.Hard.Valid == 1);
176 *PointerPte = TempPte;
177
178 /* Move on */
179 PointerPte++;
180 }
181
182 /* Copy the image */
183 RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
184
185 /* Now unmap the view */
186 Status = MmUnmapViewOfSection(Process, Base);
187 ASSERT(NT_SUCCESS(Status));
188
189 /* Detach and return status */
190 KeUnstackDetachProcess(&ApcState);
191 return Status;
192 }
193
194 PVOID
195 NTAPI
196 MiLocateExportName(IN PVOID DllBase,
197 IN PCHAR ExportName)
198 {
199 PULONG NameTable;
200 PUSHORT OrdinalTable;
201 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
202 LONG Low = 0, Mid = 0, High, Ret;
203 USHORT Ordinal;
204 PVOID Function;
205 ULONG ExportSize;
206 PULONG ExportTable;
207 PAGED_CODE();
208
209 /* Get the export directory */
210 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
211 TRUE,
212 IMAGE_DIRECTORY_ENTRY_EXPORT,
213 &ExportSize);
214 if (!ExportDirectory) return NULL;
215
216 /* Setup name tables */
217 NameTable = (PULONG)((ULONG_PTR)DllBase +
218 ExportDirectory->AddressOfNames);
219 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
220 ExportDirectory->AddressOfNameOrdinals);
221
222 /* Do a binary search */
223 High = ExportDirectory->NumberOfNames - 1;
224 while (High >= Low)
225 {
226 /* Get new middle value */
227 Mid = (Low + High) >> 1;
228
229 /* Compare name */
230 Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
231 if (Ret < 0)
232 {
233 /* Update high */
234 High = Mid - 1;
235 }
236 else if (Ret > 0)
237 {
238 /* Update low */
239 Low = Mid + 1;
240 }
241 else
242 {
243 /* We got it */
244 break;
245 }
246 }
247
248 /* Check if we couldn't find it */
249 if (High < Low) return NULL;
250
251 /* Otherwise, this is the ordinal */
252 Ordinal = OrdinalTable[Mid];
253
254 /* Resolve the address and write it */
255 ExportTable = (PULONG)((ULONG_PTR)DllBase +
256 ExportDirectory->AddressOfFunctions);
257 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
258
259 /* Check if the function is actually a forwarder */
260 if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
261 ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
262 {
263 /* It is, fail */
264 return NULL;
265 }
266
267 /* We found it */
268 return Function;
269 }
270
271 NTSTATUS
272 NTAPI
273 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
274 IN PLIST_ENTRY ListHead)
275 {
276 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
277 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
278 PMM_DLL_INITIALIZE DllInit;
279 UNICODE_STRING RegPath, ImportName;
280 NTSTATUS Status;
281
282 /* Try to see if the image exports a DllInitialize routine */
283 DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
284 "DllInitialize");
285 if (!DllInit) return STATUS_SUCCESS;
286
287 /* Do a temporary copy of BaseDllName called ImportName
288 * because we'll alter the length of the string
289 */
290 ImportName.Length = LdrEntry->BaseDllName.Length;
291 ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
292 ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
293
294 /* Obtain the path to this dll's service in the registry */
295 RegPath.MaximumLength = ServicesKeyName.Length +
296 ImportName.Length + sizeof(UNICODE_NULL);
297 RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
298 RegPath.MaximumLength,
299 TAG_LDR_WSTR);
300
301 /* Check if this allocation was unsuccessful */
302 if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
303
304 /* Build and append the service name itself */
305 RegPath.Length = ServicesKeyName.Length;
306 RtlCopyMemory(RegPath.Buffer,
307 ServicesKeyName.Buffer,
308 ServicesKeyName.Length);
309
310 /* Check if there is a dot in the filename */
311 if (wcschr(ImportName.Buffer, L'.'))
312 {
313 /* Remove the extension */
314 ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
315 ImportName.Buffer) * sizeof(WCHAR);
316 }
317
318 /* Append service name (the basename without extension) */
319 RtlAppendUnicodeStringToString(&RegPath, &ImportName);
320
321 /* Now call the DllInit func */
322 DPRINT("Calling DllInit(%wZ)\n", &RegPath);
323 Status = DllInit(&RegPath);
324
325 /* Clean up */
326 ExFreePool(RegPath.Buffer);
327
328 /* Return status value which DllInitialize returned */
329 return Status;
330 }
331
332 BOOLEAN
333 NTAPI
334 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
335 {
336 NTSTATUS Status;
337 PMM_DLL_UNLOAD Func;
338 PAGED_CODE();
339
340 /* Get the unload routine */
341 Func = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, "DllUnload");
342 if (!Func) return FALSE;
343
344 /* Call it and check for success */
345 Status = Func();
346 if (!NT_SUCCESS(Status)) return FALSE;
347
348 /* Lie about the load count so we can unload the image */
349 ASSERT(LdrEntry->LoadCount == 0);
350 LdrEntry->LoadCount = 1;
351
352 /* Unload it and return true */
353 MmUnloadSystemImage(LdrEntry);
354 return TRUE;
355 }
356
357 NTSTATUS
358 NTAPI
359 MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
360 {
361 SIZE_T i;
362 LOAD_IMPORTS SingleEntry;
363 PLDR_DATA_TABLE_ENTRY LdrEntry;
364 PVOID CurrentImports;
365 PAGED_CODE();
366
367 /* Check if there's no imports or if we're a boot driver */
368 if ((ImportList == MM_SYSLDR_NO_IMPORTS) ||
369 (ImportList == MM_SYSLDR_BOOT_LOADED) ||
370 (ImportList->Count == 0))
371 {
372 /* Then there's nothing to do */
373 return STATUS_SUCCESS;
374 }
375
376 /* Check for single-entry */
377 if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY)
378 {
379 /* Set it up */
380 SingleEntry.Count = 1;
381 SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~ MM_SYSLDR_SINGLE_ENTRY);
382
383 /* Use this as the import list */
384 ImportList = &SingleEntry;
385 }
386
387 /* Loop the import list */
388 for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++)
389 {
390 /* Get the entry */
391 LdrEntry = ImportList->Entry[i];
392 DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName, &LdrEntry->BaseDllName);
393
394 /* Skip boot loaded images */
395 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue;
396
397 /* Dereference the entry */
398 ASSERT(LdrEntry->LoadCount >= 1);
399 if (!--LdrEntry->LoadCount)
400 {
401 /* Save the import data in case unload fails */
402 CurrentImports = LdrEntry->LoadedImports;
403
404 /* This is the last entry */
405 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
406 if (MiCallDllUnloadAndUnloadDll(LdrEntry))
407 {
408 /* Unloading worked, parse this DLL's imports too */
409 MiDereferenceImports(CurrentImports);
410
411 /* Check if we had valid imports */
412 if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) ||
413 (CurrentImports != MM_SYSLDR_NO_IMPORTS) ||
414 !((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
415 {
416 /* Free them */
417 ExFreePool(CurrentImports);
418 }
419 }
420 else
421 {
422 /* Unload failed, restore imports */
423 LdrEntry->LoadedImports = CurrentImports;
424 }
425 }
426 }
427
428 /* Done */
429 return STATUS_SUCCESS;
430 }
431
432 VOID
433 NTAPI
434 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
435 {
436 PAGED_CODE();
437
438 /* Check if there's no imports or we're a boot driver or only one entry */
439 if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) ||
440 (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) ||
441 ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
442 {
443 /* Nothing to do */
444 return;
445 }
446
447 /* Otherwise, free the import list */
448 ExFreePool(LdrEntry->LoadedImports);
449 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
450 }
451
452 PVOID
453 NTAPI
454 MiFindExportedRoutineByName(IN PVOID DllBase,
455 IN PANSI_STRING ExportName)
456 {
457 PULONG NameTable;
458 PUSHORT OrdinalTable;
459 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
460 LONG Low = 0, Mid = 0, High, Ret;
461 USHORT Ordinal;
462 PVOID Function;
463 ULONG ExportSize;
464 PULONG ExportTable;
465 PAGED_CODE();
466
467 /* Get the export directory */
468 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
469 TRUE,
470 IMAGE_DIRECTORY_ENTRY_EXPORT,
471 &ExportSize);
472 if (!ExportDirectory) return NULL;
473
474 /* Setup name tables */
475 NameTable = (PULONG)((ULONG_PTR)DllBase +
476 ExportDirectory->AddressOfNames);
477 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
478 ExportDirectory->AddressOfNameOrdinals);
479
480 /* Do a binary search */
481 High = ExportDirectory->NumberOfNames - 1;
482 while (High >= Low)
483 {
484 /* Get new middle value */
485 Mid = (Low + High) >> 1;
486
487 /* Compare name */
488 Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
489 if (Ret < 0)
490 {
491 /* Update high */
492 High = Mid - 1;
493 }
494 else if (Ret > 0)
495 {
496 /* Update low */
497 Low = Mid + 1;
498 }
499 else
500 {
501 /* We got it */
502 break;
503 }
504 }
505
506 /* Check if we couldn't find it */
507 if (High < Low) return NULL;
508
509 /* Otherwise, this is the ordinal */
510 Ordinal = OrdinalTable[Mid];
511
512 /* Resolve the address and write it */
513 ExportTable = (PULONG)((ULONG_PTR)DllBase +
514 ExportDirectory->AddressOfFunctions);
515 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
516
517 /* We found it! */
518 ASSERT(!(Function > (PVOID)ExportDirectory) &&
519 (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
520 return Function;
521 }
522
523 VOID
524 NTAPI
525 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
526 IN BOOLEAN Insert)
527 {
528 KIRQL OldIrql;
529
530 /* Acquire module list lock */
531 KeEnterCriticalRegion();
532 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
533
534 /* Acquire the spinlock too as we will insert or remove the entry */
535 OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
536
537 /* Insert or remove from the list */
538 Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
539 RemoveEntryList(&LdrEntry->InLoadOrderLinks);
540
541 /* Release locks */
542 KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
543 ExReleaseResourceLite(&PsLoadedModuleResource);
544 KeLeaveCriticalRegion();
545 }
546
547 VOID
548 NTAPI
549 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
550 IN PVOID OldBase,
551 IN PVOID NewBase,
552 IN ULONG Size)
553 {
554 ULONG_PTR OldBaseTop, Delta;
555 PLDR_DATA_TABLE_ENTRY LdrEntry;
556 PLIST_ENTRY NextEntry;
557 ULONG ImportSize;
558 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
559 PULONG ImageThunk;
560
561 /* Calculate the top and delta */
562 OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
563 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
564
565 /* Loop the loader block */
566 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
567 NextEntry != &LoaderBlock->LoadOrderListHead;
568 NextEntry = NextEntry->Flink)
569 {
570 /* Get the loader entry */
571 LdrEntry = CONTAINING_RECORD(NextEntry,
572 LDR_DATA_TABLE_ENTRY,
573 InLoadOrderLinks);
574
575 /* Get the import table */
576 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
577 TRUE,
578 IMAGE_DIRECTORY_ENTRY_IMPORT,
579 &ImportSize);
580 if (!ImportDescriptor) continue;
581
582 /* Make sure we have an IAT */
583 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
584 while ((ImportDescriptor->Name) &&
585 (ImportDescriptor->OriginalFirstThunk))
586 {
587 /* Get the image thunk */
588 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
589 ImportDescriptor->FirstThunk);
590 while (*ImageThunk)
591 {
592 /* Check if it's within this module */
593 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
594 {
595 /* Relocate it */
596 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
597 ImageThunk, *ImageThunk, *ImageThunk + Delta);
598 *ImageThunk += Delta;
599 }
600
601 /* Go to the next thunk */
602 ImageThunk++;
603 }
604
605 /* Go to the next import */
606 ImportDescriptor++;
607 }
608 }
609 }
610
611 NTSTATUS
612 NTAPI
613 MiSnapThunk(IN PVOID DllBase,
614 IN PVOID ImageBase,
615 IN PIMAGE_THUNK_DATA Name,
616 IN PIMAGE_THUNK_DATA Address,
617 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
618 IN ULONG ExportSize,
619 IN BOOLEAN SnapForwarder,
620 OUT PCHAR *MissingApi)
621 {
622 BOOLEAN IsOrdinal;
623 USHORT Ordinal;
624 PULONG NameTable;
625 PUSHORT OrdinalTable;
626 PIMAGE_IMPORT_BY_NAME NameImport;
627 USHORT Hint;
628 ULONG Low = 0, Mid = 0, High;
629 LONG Ret;
630 NTSTATUS Status;
631 PCHAR MissingForwarder;
632 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
633 PULONG ExportTable;
634 ANSI_STRING DllName;
635 UNICODE_STRING ForwarderName;
636 PLIST_ENTRY NextEntry;
637 PLDR_DATA_TABLE_ENTRY LdrEntry;
638 ULONG ForwardExportSize;
639 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
640 PIMAGE_IMPORT_BY_NAME ForwardName;
641 ULONG ForwardLength;
642 IMAGE_THUNK_DATA ForwardThunk;
643 PAGED_CODE();
644
645 /* Check if this is an ordinal */
646 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
647 if ((IsOrdinal) && !(SnapForwarder))
648 {
649 /* Get the ordinal number and set it as missing */
650 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
651 ExportDirectory->Base);
652 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
653 }
654 else
655 {
656 /* Get the VA if we don't have to snap */
657 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
658 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
659
660 /* Copy the procedure name */
661 strncpy(*MissingApi,
662 (PCHAR)&NameImport->Name[0],
663 MAXIMUM_FILENAME_LENGTH - 1);
664
665 /* Setup name tables */
666 DPRINT("Import name: %s\n", NameImport->Name);
667 NameTable = (PULONG)((ULONG_PTR)DllBase +
668 ExportDirectory->AddressOfNames);
669 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
670 ExportDirectory->AddressOfNameOrdinals);
671
672 /* Get the hint and check if it's valid */
673 Hint = NameImport->Hint;
674 if ((Hint < ExportDirectory->NumberOfNames) &&
675 !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
676 {
677 /* We have a match, get the ordinal number from here */
678 Ordinal = OrdinalTable[Hint];
679 }
680 else
681 {
682 /* Do a binary search */
683 High = ExportDirectory->NumberOfNames - 1;
684 while (High >= Low)
685 {
686 /* Get new middle value */
687 Mid = (Low + High) >> 1;
688
689 /* Compare name */
690 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
691 if (Ret < 0)
692 {
693 /* Update high */
694 High = Mid - 1;
695 }
696 else if (Ret > 0)
697 {
698 /* Update low */
699 Low = Mid + 1;
700 }
701 else
702 {
703 /* We got it */
704 break;
705 }
706 }
707
708 /* Check if we couldn't find it */
709 if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
710
711 /* Otherwise, this is the ordinal */
712 Ordinal = OrdinalTable[Mid];
713 }
714 }
715
716 /* Check if the ordinal is invalid */
717 if (Ordinal >= ExportDirectory->NumberOfFunctions)
718 {
719 /* Fail */
720 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
721 }
722 else
723 {
724 /* In case the forwarder is missing */
725 MissingForwarder = NameBuffer;
726
727 /* Resolve the address and write it */
728 ExportTable = (PULONG)((ULONG_PTR)DllBase +
729 ExportDirectory->AddressOfFunctions);
730 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
731
732 /* Assume success from now on */
733 Status = STATUS_SUCCESS;
734
735 /* Check if the function is actually a forwarder */
736 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
737 (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
738 {
739 /* Now assume failure in case the forwarder doesn't exist */
740 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
741
742 /* Build the forwarder name */
743 DllName.Buffer = (PCHAR)Address->u1.Function;
744 DllName.Length = strchr(DllName.Buffer, '.') -
745 DllName.Buffer +
746 sizeof(ANSI_NULL);
747 DllName.MaximumLength = DllName.Length;
748
749 /* Convert it */
750 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
751 &DllName,
752 TRUE)))
753 {
754 /* We failed, just return an error */
755 return Status;
756 }
757
758 /* Loop the module list */
759 NextEntry = PsLoadedModuleList.Flink;
760 while (NextEntry != &PsLoadedModuleList)
761 {
762 /* Get the loader entry */
763 LdrEntry = CONTAINING_RECORD(NextEntry,
764 LDR_DATA_TABLE_ENTRY,
765 InLoadOrderLinks);
766
767 /* Check if it matches */
768 if (RtlPrefixString((PSTRING)&ForwarderName,
769 (PSTRING)&LdrEntry->BaseDllName,
770 TRUE))
771 {
772 /* Get the forwarder export directory */
773 ForwardExportDirectory =
774 RtlImageDirectoryEntryToData(LdrEntry->DllBase,
775 TRUE,
776 IMAGE_DIRECTORY_ENTRY_EXPORT,
777 &ForwardExportSize);
778 if (!ForwardExportDirectory) break;
779
780 /* Allocate a name entry */
781 ForwardLength = strlen(DllName.Buffer + DllName.Length) +
782 sizeof(ANSI_NULL);
783 ForwardName = ExAllocatePoolWithTag(PagedPool,
784 sizeof(*ForwardName) +
785 ForwardLength,
786 TAG_LDR_WSTR);
787 if (!ForwardName) break;
788
789 /* Copy the data */
790 RtlCopyMemory(&ForwardName->Name[0],
791 DllName.Buffer + DllName.Length,
792 ForwardLength);
793 ForwardName->Hint = 0;
794
795 /* Set the new address */
796 ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
797
798 /* Snap the forwarder */
799 Status = MiSnapThunk(LdrEntry->DllBase,
800 ImageBase,
801 &ForwardThunk,
802 &ForwardThunk,
803 ForwardExportDirectory,
804 ForwardExportSize,
805 TRUE,
806 &MissingForwarder);
807
808 /* Free the forwarder name and set the thunk */
809 ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
810 Address->u1 = ForwardThunk.u1;
811 break;
812 }
813
814 /* Go to the next entry */
815 NextEntry = NextEntry->Flink;
816 }
817
818 /* Free the name */
819 RtlFreeUnicodeString(&ForwarderName);
820 }
821 }
822
823 /* Return status */
824 return Status;
825 }
826
827 NTSTATUS
828 NTAPI
829 MmUnloadSystemImage(IN PVOID ImageHandle)
830 {
831 PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
832 PVOID BaseAddress = LdrEntry->DllBase;
833 NTSTATUS Status;
834 STRING TempName;
835 BOOLEAN HadEntry = FALSE;
836
837 /* Acquire the loader lock */
838 KeEnterCriticalRegion();
839 KeWaitForSingleObject(&MmSystemLoadLock,
840 WrVirtualMemory,
841 KernelMode,
842 FALSE,
843 NULL);
844
845 /* Check if this driver was loaded at boot and didn't get imports parsed */
846 if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;
847
848 /* We should still be alive */
849 ASSERT(LdrEntry->LoadCount != 0);
850 LdrEntry->LoadCount--;
851
852 /* Check if we're still loaded */
853 if (LdrEntry->LoadCount) goto Done;
854
855 /* We should cleanup... are symbols loaded */
856 if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
857 {
858 /* Create the ANSI name */
859 Status = RtlUnicodeStringToAnsiString(&TempName,
860 &LdrEntry->BaseDllName,
861 TRUE);
862 if (NT_SUCCESS(Status))
863 {
864 /* Unload the symbols */
865 DbgUnLoadImageSymbols(&TempName,
866 BaseAddress,
867 (ULONG_PTR)ZwCurrentProcess());
868 RtlFreeAnsiString(&TempName);
869 }
870 }
871
872 /* FIXME: Free the driver */
873 //MmFreeSection(LdrEntry->DllBase);
874
875 /* Check if we're linked in */
876 if (LdrEntry->InLoadOrderLinks.Flink)
877 {
878 /* Remove us */
879 MiProcessLoaderEntry(LdrEntry, FALSE);
880 HadEntry = TRUE;
881 }
882
883 /* Dereference and clear the imports */
884 MiDereferenceImports(LdrEntry->LoadedImports);
885 MiClearImports(LdrEntry);
886
887 /* Check if the entry needs to go away */
888 if (HadEntry)
889 {
890 /* Check if it had a name */
891 if (LdrEntry->FullDllName.Buffer)
892 {
893 /* Free it */
894 ExFreePool(LdrEntry->FullDllName.Buffer);
895 }
896
897 /* Check if we had a section */
898 if (LdrEntry->SectionPointer)
899 {
900 /* Dereference it */
901 ObDereferenceObject(LdrEntry->SectionPointer);
902 }
903
904 /* Free the entry */
905 ExFreePool(LdrEntry);
906 }
907
908 /* Release the system lock and return */
909 Done:
910 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
911 KeLeaveCriticalRegion();
912 return STATUS_SUCCESS;
913 }
914
915 NTSTATUS
916 NTAPI
917 MiResolveImageReferences(IN PVOID ImageBase,
918 IN PUNICODE_STRING ImageFileDirectory,
919 IN PUNICODE_STRING NamePrefix OPTIONAL,
920 OUT PCHAR *MissingApi,
921 OUT PWCHAR *MissingDriver,
922 OUT PLOAD_IMPORTS *LoadImports)
923 {
924 PCHAR MissingApiBuffer = *MissingApi, ImportName;
925 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
926 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
927 PLOAD_IMPORTS LoadedImports, NewImports;
928 ULONG GdiLink, NormalLink, i;
929 BOOLEAN ReferenceNeeded, Loaded;
930 ANSI_STRING TempString;
931 UNICODE_STRING NameString, DllName;
932 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
933 PVOID ImportBase, DllBase;
934 PLIST_ENTRY NextEntry;
935 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
936 NTSTATUS Status;
937 PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
938 PAGED_CODE();
939 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
940 __FUNCTION__, ImageBase, ImageFileDirectory);
941
942 /* Assume no imports */
943 *LoadImports = (PVOID)-2;
944
945 /* Get the import descriptor */
946 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
947 TRUE,
948 IMAGE_DIRECTORY_ENTRY_IMPORT,
949 &ImportSize);
950 if (!ImportDescriptor) return STATUS_SUCCESS;
951
952 /* Loop all imports to count them */
953 for (CurrentImport = ImportDescriptor;
954 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
955 CurrentImport++)
956 {
957 /* One more */
958 ImportCount++;
959 }
960
961 /* Make sure we have non-zero imports */
962 if (ImportCount)
963 {
964 /* Calculate and allocate the list we'll need */
965 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
966 LoadedImports = ExAllocatePoolWithTag(PagedPool,
967 LoadedImportsSize,
968 TAG_LDR_WSTR);
969 if (LoadedImports)
970 {
971 /* Zero it */
972 RtlZeroMemory(LoadedImports, LoadedImportsSize);
973 }
974 }
975 else
976 {
977 /* No table */
978 LoadedImports = NULL;
979 }
980
981 /* Reset the import count and loop descriptors again */
982 ImportCount = GdiLink = NormalLink = 0;
983 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
984 {
985 /* Get the name */
986 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
987
988 /* Check if this is a GDI driver */
989 GdiLink = GdiLink |
990 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
991
992 /* We can also allow dxapi */
993 NormalLink = NormalLink |
994 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
995 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));
996
997 /* Check if this is a valid GDI driver */
998 if ((GdiLink) && (NormalLink))
999 {
1000 /* It's not, it's importing stuff it shouldn't be! */
1001 MiDereferenceImports(LoadedImports);
1002 if (LoadedImports) ExFreePool(LoadedImports);
1003 return STATUS_PROCEDURE_NOT_FOUND;
1004 }
1005
1006 /* Check if this is a "core" import, which doesn't get referenced */
1007 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
1008 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
1009 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
1010 {
1011 /* Don't reference this */
1012 ReferenceNeeded = FALSE;
1013 }
1014 else
1015 {
1016 /* Reference these modules */
1017 ReferenceNeeded = TRUE;
1018 }
1019
1020 /* Now setup a unicode string for the import */
1021 RtlInitAnsiString(&TempString, ImportName);
1022 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
1023 if (!NT_SUCCESS(Status))
1024 {
1025 /* Failed */
1026 MiDereferenceImports(LoadedImports);
1027 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1028 return Status;
1029 }
1030
1031 /* We don't support name prefixes yet */
1032 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
1033
1034 /* Remember that we haven't loaded the import at this point */
1035 CheckDllState:
1036 Loaded = FALSE;
1037 ImportBase = NULL;
1038
1039 /* Loop the driver list */
1040 NextEntry = PsLoadedModuleList.Flink;
1041 while (NextEntry != &PsLoadedModuleList)
1042 {
1043 /* Get the loader entry and compare the name */
1044 LdrEntry = CONTAINING_RECORD(NextEntry,
1045 LDR_DATA_TABLE_ENTRY,
1046 InLoadOrderLinks);
1047 if (RtlEqualUnicodeString(&NameString,
1048 &LdrEntry->BaseDllName,
1049 TRUE))
1050 {
1051 /* Get the base address */
1052 ImportBase = LdrEntry->DllBase;
1053
1054 /* Check if we haven't loaded yet, and we need references */
1055 if (!(Loaded) && (ReferenceNeeded))
1056 {
1057 /* Make sure we're not already loading */
1058 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1059 {
1060 /* Increase the load count */
1061 LdrEntry->LoadCount++;
1062 }
1063 }
1064
1065 /* Done, break out */
1066 break;
1067 }
1068
1069 /* Go to the next entry */
1070 NextEntry = NextEntry->Flink;
1071 }
1072
1073 /* Check if we haven't loaded the import yet */
1074 if (!ImportBase)
1075 {
1076 /* Setup the import DLL name */
1077 DllName.MaximumLength = NameString.Length +
1078 ImageFileDirectory->Length +
1079 sizeof(UNICODE_NULL);
1080 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1081 DllName.MaximumLength,
1082 TAG_LDR_WSTR);
1083 if (DllName.Buffer)
1084 {
1085 /* Setup the base length and copy it */
1086 DllName.Length = ImageFileDirectory->Length;
1087 RtlCopyMemory(DllName.Buffer,
1088 ImageFileDirectory->Buffer,
1089 ImageFileDirectory->Length);
1090
1091 /* Now add the import name and null-terminate it */
1092 RtlAppendStringToString((PSTRING)&DllName,
1093 (PSTRING)&NameString);
1094 DllName.Buffer[(DllName.MaximumLength - 1) / sizeof(WCHAR)] = UNICODE_NULL;
1095
1096 /* Load the image */
1097 Status = MmLoadSystemImage(&DllName,
1098 NamePrefix,
1099 NULL,
1100 0,
1101 (PVOID)&DllEntry,
1102 &DllBase);
1103 if (NT_SUCCESS(Status))
1104 {
1105 /* We can free the DLL Name */
1106 ExFreePool(DllName.Buffer);
1107 }
1108 else
1109 {
1110 /* Fill out the information for the error */
1111 *MissingDriver = DllName.Buffer;
1112 *(PULONG)MissingDriver |= 1;
1113 *MissingApi = NULL;
1114 }
1115 }
1116 else
1117 {
1118 /* We're out of resources */
1119 Status = STATUS_INSUFFICIENT_RESOURCES;
1120 }
1121
1122 /* Check if we're OK until now */
1123 if (NT_SUCCESS(Status))
1124 {
1125 /* We're now loaded */
1126 Loaded = TRUE;
1127
1128 /* Sanity check */
1129 ASSERT(DllBase = DllEntry->DllBase);
1130
1131 /* Call the initialization routines */
1132 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
1133 if (!NT_SUCCESS(Status))
1134 {
1135 /* We failed, unload the image */
1136 MmUnloadSystemImage(DllEntry);
1137 while (TRUE);
1138 Loaded = FALSE;
1139 }
1140 }
1141
1142 /* Check if we failed by here */
1143 if (!NT_SUCCESS(Status))
1144 {
1145 /* Cleanup and return */
1146 RtlFreeUnicodeString(&NameString);
1147 MiDereferenceImports(LoadedImports);
1148 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1149 return Status;
1150 }
1151
1152 /* Loop again to make sure that everything is OK */
1153 goto CheckDllState;
1154 }
1155
1156 /* Check if we're support to reference this import */
1157 if ((ReferenceNeeded) && (LoadedImports))
1158 {
1159 /* Make sure we're not already loading */
1160 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1161 {
1162 /* Add the entry */
1163 LoadedImports->Entry[LoadedImports->Count] = LdrEntry;
1164 LoadedImports->Count++;
1165 }
1166 }
1167
1168 /* Free the import name */
1169 RtlFreeUnicodeString(&NameString);
1170
1171 /* Set the missing driver name and get the export directory */
1172 *MissingDriver = LdrEntry->BaseDllName.Buffer;
1173 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
1174 TRUE,
1175 IMAGE_DIRECTORY_ENTRY_EXPORT,
1176 &ExportSize);
1177 if (!ExportDirectory)
1178 {
1179 /* Cleanup and return */
1180 MiDereferenceImports(LoadedImports);
1181 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1182 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
1183 }
1184
1185 /* Make sure we have an IAT */
1186 if (ImportDescriptor->OriginalFirstThunk)
1187 {
1188 /* Get the first thunks */
1189 OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
1190 ImportDescriptor->OriginalFirstThunk);
1191 FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
1192 ImportDescriptor->FirstThunk);
1193
1194 /* Loop the IAT */
1195 while (OrigThunk->u1.AddressOfData)
1196 {
1197 /* Snap thunk */
1198 Status = MiSnapThunk(ImportBase,
1199 ImageBase,
1200 OrigThunk++,
1201 FirstThunk++,
1202 ExportDirectory,
1203 ExportSize,
1204 FALSE,
1205 MissingApi);
1206 if (!NT_SUCCESS(Status))
1207 {
1208 /* Cleanup and return */
1209 MiDereferenceImports(LoadedImports);
1210 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1211 return Status;
1212 }
1213
1214 /* Reset the buffer */
1215 *MissingApi = MissingApiBuffer;
1216 }
1217 }
1218
1219 /* Go to the next import */
1220 ImportDescriptor++;
1221 }
1222
1223 /* Check if we have an import list */
1224 if (LoadedImports)
1225 {
1226 /* Reset the count again, and loop entries*/
1227 ImportCount = 0;
1228 for (i = 0; i < LoadedImports->Count; i++)
1229 {
1230 if (LoadedImports->Entry[i])
1231 {
1232 /* Got an entry, OR it with 1 in case it's the single entry */
1233 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);
1234 ImportCount++;
1235 }
1236 }
1237
1238 /* Check if we had no imports */
1239 if (!ImportCount)
1240 {
1241 /* Free the list and set it to no imports */
1242 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1243 LoadedImports = (PVOID)-2;
1244 }
1245 else if (ImportCount == 1)
1246 {
1247 /* Just one entry, we can free the table and only use our entry */
1248 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1249 LoadedImports = (PLOAD_IMPORTS)ImportEntry;
1250 }
1251 else if (ImportCount != LoadedImports->Count)
1252 {
1253 /* Allocate a new list */
1254 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1255 NewImports = ExAllocatePoolWithTag(PagedPool,
1256 LoadedImportsSize,
1257 TAG_LDR_WSTR);
1258 if (NewImports)
1259 {
1260 /* Set count */
1261 NewImports->Count = 0;
1262
1263 /* Loop all the imports */
1264 for (i = 0; i < LoadedImports->Count; i++)
1265 {
1266 /* Make sure it's valid */
1267 if (LoadedImports->Entry[i])
1268 {
1269 /* Copy it */
1270 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
1271 NewImports->Count++;
1272 }
1273 }
1274
1275 /* Free the old copy */
1276 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1277 LoadedImports = NewImports;
1278 }
1279 }
1280
1281 /* Return the list */
1282 *LoadImports = LoadedImports;
1283 }
1284
1285 /* Return success */
1286 return STATUS_SUCCESS;
1287 }
1288
1289 VOID
1290 NTAPI
1291 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1292 {
1293 PLIST_ENTRY NextEntry;
1294 ULONG i = 0;
1295 PIMAGE_NT_HEADERS NtHeader;
1296 PLDR_DATA_TABLE_ENTRY LdrEntry;
1297 PIMAGE_FILE_HEADER FileHeader;
1298 BOOLEAN ValidRelocs;
1299 PIMAGE_DATA_DIRECTORY DataDirectory;
1300 PVOID DllBase, NewImageAddress;
1301 NTSTATUS Status;
1302 PMMPTE PointerPte, StartPte, LastPte;
1303 PFN_NUMBER PteCount;
1304 PMMPFN Pfn1;
1305 MMPTE TempPte, OldPte;
1306
1307 /* Loop driver list */
1308 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
1309 NextEntry != &LoaderBlock->LoadOrderListHead;
1310 NextEntry = NextEntry->Flink)
1311 {
1312 /* Get the loader entry and NT header */
1313 LdrEntry = CONTAINING_RECORD(NextEntry,
1314 LDR_DATA_TABLE_ENTRY,
1315 InLoadOrderLinks);
1316 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
1317
1318 /* Debug info */
1319 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1320 LdrEntry->DllBase,
1321 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
1322 &LdrEntry->FullDllName);
1323
1324 /* Skip kernel and HAL */
1325 /* ROS HACK: Skip BOOTVID/KDCOM too */
1326 i++;
1327 if (i <= 4) continue;
1328
1329 /* Skip non-drivers */
1330 if (!NtHeader) continue;
1331
1332 /* Get the file header and make sure we can relocate */
1333 FileHeader = &NtHeader->FileHeader;
1334 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
1335 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
1336 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
1337
1338 /* Everything made sense until now, check the relocation section too */
1339 DataDirectory = &NtHeader->OptionalHeader.
1340 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1341 if (!DataDirectory->VirtualAddress)
1342 {
1343 /* We don't really have relocations */
1344 ValidRelocs = FALSE;
1345 }
1346 else
1347 {
1348 /* Make sure the size is valid */
1349 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
1350 LdrEntry->SizeOfImage)
1351 {
1352 /* They're not, skip */
1353 continue;
1354 }
1355
1356 /* We have relocations */
1357 ValidRelocs = TRUE;
1358 }
1359
1360 /* Remember the original address */
1361 DllBase = LdrEntry->DllBase;
1362
1363 /* Get the first PTE and the number of PTEs we'll need */
1364 PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase);
1365 PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT;
1366 LastPte = StartPte + PteCount;
1367
1368 /* Loop the PTEs */
1369 while (PointerPte < LastPte)
1370 {
1371 /* Mark the page modified in the PFN database */
1372 ASSERT(PointerPte->u.Hard.Valid == 1);
1373 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
1374 ASSERT(Pfn1->u3.e1.Rom == 0);
1375 Pfn1->u3.e1.Modified = TRUE;
1376
1377 /* Next */
1378 PointerPte++;
1379 }
1380
1381 /* Now reserve system PTEs for the image */
1382 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
1383 if (!PointerPte)
1384 {
1385 /* Shouldn't happen */
1386 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1387 while (TRUE);
1388 }
1389
1390 /* This is the new virtual address for the module */
1391 LastPte = PointerPte + PteCount;
1392 NewImageAddress = MiPteToAddress(PointerPte);
1393
1394 /* Sanity check */
1395 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
1396 ASSERT(ExpInitializationPhase == 0);
1397
1398 /* Loop the new driver PTEs */
1399 TempPte = ValidKernelPte;
1400 while (PointerPte < LastPte)
1401 {
1402 /* Copy the old data */
1403 OldPte = *StartPte;
1404 ASSERT(OldPte.u.Hard.Valid == 1);
1405
1406 /* Set page number from the loader's memory */
1407 TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber;
1408
1409 /* Write it */
1410 ASSERT(PointerPte->u.Hard.Valid == 0);
1411 ASSERT(TempPte.u.Hard.Valid == 1);
1412 *PointerPte = TempPte;
1413
1414 /* Move on */
1415 PointerPte++;
1416 StartPte++;
1417 }
1418
1419 /* Update position */
1420 PointerPte -= PteCount;
1421
1422 /* Sanity check */
1423 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
1424
1425 /* Set the image base to the address where the loader put it */
1426 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1427
1428 /* Check if we had relocations */
1429 if (ValidRelocs)
1430 {
1431 /* Relocate the image */
1432 Status = LdrRelocateImageWithBias(NewImageAddress,
1433 0,
1434 "SYSLDR",
1435 STATUS_SUCCESS,
1436 STATUS_CONFLICTING_ADDRESSES,
1437 STATUS_INVALID_IMAGE_FORMAT);
1438 if (!NT_SUCCESS(Status))
1439 {
1440 /* This shouldn't happen */
1441 DPRINT1("Relocations failed!\n");
1442 while (TRUE);
1443 }
1444 }
1445
1446 /* Update the loader entry */
1447 LdrEntry->DllBase = NewImageAddress;
1448
1449 /* Update the thunks */
1450 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
1451 MiUpdateThunks(LoaderBlock,
1452 DllBase,
1453 NewImageAddress,
1454 LdrEntry->SizeOfImage);
1455
1456 /* Update the loader entry */
1457 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
1458 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
1459 NtHeader->OptionalHeader.AddressOfEntryPoint);
1460 LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT;
1461
1462 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */
1463 }
1464 }
1465
1466 BOOLEAN
1467 NTAPI
1468 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1469 {
1470 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
1471 PLIST_ENTRY ListHead, NextEntry;
1472 ULONG EntrySize;
1473
1474 /* Setup the loaded module list and locks */
1475 ExInitializeResourceLite(&PsLoadedModuleResource);
1476 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
1477 InitializeListHead(&PsLoadedModuleList);
1478
1479 /* Get loop variables and the kernel entry */
1480 ListHead = &LoaderBlock->LoadOrderListHead;
1481 NextEntry = ListHead->Flink;
1482 LdrEntry = CONTAINING_RECORD(NextEntry,
1483 LDR_DATA_TABLE_ENTRY,
1484 InLoadOrderLinks);
1485 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
1486
1487 /* Loop the loader block */
1488 while (NextEntry != ListHead)
1489 {
1490 /* Get the loader entry */
1491 LdrEntry = CONTAINING_RECORD(NextEntry,
1492 LDR_DATA_TABLE_ENTRY,
1493 InLoadOrderLinks);
1494
1495 /* FIXME: ROS HACK. Make sure this is a driver */
1496 if (!RtlImageNtHeader(LdrEntry->DllBase))
1497 {
1498 /* Skip this entry */
1499 NextEntry= NextEntry->Flink;
1500 continue;
1501 }
1502
1503 /* Calculate the size we'll need and allocate a copy */
1504 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1505 LdrEntry->BaseDllName.MaximumLength +
1506 sizeof(UNICODE_NULL);
1507 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
1508 if (!NewEntry) return FALSE;
1509
1510 /* Copy the entry over */
1511 *NewEntry = *LdrEntry;
1512
1513 /* Allocate the name */
1514 NewEntry->FullDllName.Buffer =
1515 ExAllocatePoolWithTag(PagedPool,
1516 LdrEntry->FullDllName.MaximumLength +
1517 sizeof(UNICODE_NULL),
1518 TAG_LDR_WSTR);
1519 if (!NewEntry->FullDllName.Buffer) return FALSE;
1520
1521 /* Set the base name */
1522 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
1523
1524 /* Copy the full and base name */
1525 RtlCopyMemory(NewEntry->FullDllName.Buffer,
1526 LdrEntry->FullDllName.Buffer,
1527 LdrEntry->FullDllName.MaximumLength);
1528 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
1529 LdrEntry->BaseDllName.Buffer,
1530 LdrEntry->BaseDllName.MaximumLength);
1531
1532 /* Null-terminate the base name */
1533 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
1534 sizeof(WCHAR)] = UNICODE_NULL;
1535
1536 /* Insert the entry into the list */
1537 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
1538 NextEntry = NextEntry->Flink;
1539 }
1540
1541 /* Build the import lists for the boot drivers */
1542 //MiBuildImportsForBootDrivers();
1543
1544 /* We're done */
1545 return TRUE;
1546 }
1547
1548 ULONG
1549 NTAPI
1550 MiComputeDriverProtection(IN BOOLEAN SessionSpace,
1551 IN ULONG SectionProtection)
1552 {
1553 ULONG Protection = MM_ZERO_ACCESS;
1554
1555 /* Check if the caller gave anything */
1556 if (SectionProtection)
1557 {
1558 /* Always turn on execute access */
1559 SectionProtection |= IMAGE_SCN_MEM_EXECUTE;
1560
1561 /* Check if the registry setting is on or not */
1562 if (!MmEnforceWriteProtection)
1563 {
1564 /* Turn on write access too */
1565 SectionProtection |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE);
1566 }
1567 }
1568
1569 /* Convert to internal PTE flags */
1570 if (SectionProtection & IMAGE_SCN_MEM_EXECUTE) Protection |= MM_EXECUTE;
1571 if (SectionProtection & IMAGE_SCN_MEM_READ) Protection |= MM_READONLY;
1572
1573 /* Check for write access */
1574 if (SectionProtection & IMAGE_SCN_MEM_WRITE)
1575 {
1576 /* Session space is not supported */
1577 if (SessionSpace)
1578 {
1579 DPRINT1("Session drivers not supported\n");
1580 ASSERT(SessionSpace == FALSE);
1581 }
1582 else
1583 {
1584 /* Convert to internal PTE flag */
1585 Protection = (Protection & MM_EXECUTE) ? MM_EXECUTE_READWRITE : MM_READWRITE;
1586 }
1587 }
1588
1589 /* If there's no access at all by now, convert to internal no access flag */
1590 if (Protection == MM_ZERO_ACCESS) Protection = MM_NOACCESS;
1591
1592 /* Return the computed PTE protection */
1593 return Protection;
1594 }
1595
1596 VOID
1597 NTAPI
1598 MiSetSystemCodeProtection(IN PMMPTE FirstPte,
1599 IN PMMPTE LastPte,
1600 IN ULONG ProtectionMask)
1601 {
1602 /* I'm afraid to introduce regressions at the moment... */
1603 return;
1604 }
1605
1606 VOID
1607 NTAPI
1608 MiWriteProtectSystemImage(IN PVOID ImageBase)
1609 {
1610 PIMAGE_NT_HEADERS NtHeaders;
1611 PIMAGE_SECTION_HEADER Section;
1612 PFN_NUMBER DriverPages;
1613 ULONG CurrentProtection, SectionProtection, CombinedProtection, ProtectionMask;
1614 ULONG Sections, Size;
1615 ULONG_PTR BaseAddress, CurrentAddress;
1616 PMMPTE PointerPte, StartPte, LastPte, CurrentPte, ComboPte = NULL;
1617 ULONG CurrentMask, CombinedMask = 0;
1618 PAGED_CODE();
1619
1620 /* No need to write protect physical memory-backed drivers (large pages) */
1621 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
1622
1623 /* Get the image headers */
1624 NtHeaders = RtlImageNtHeader(ImageBase);
1625 if (!NtHeaders) return;
1626
1627 /* Check if this is a session driver or not */
1628 if (!MI_IS_SESSION_ADDRESS(ImageBase))
1629 {
1630 /* Don't touch NT4 drivers */
1631 if (NtHeaders->OptionalHeader.MajorOperatingSystemVersion < 5) return;
1632 if (NtHeaders->OptionalHeader.MajorImageVersion < 5) return;
1633 }
1634 else
1635 {
1636 /* Not supported */
1637 DPRINT1("Session drivers not supported\n");
1638 ASSERT(FALSE);
1639 }
1640
1641 /* These are the only protection masks we care about */
1642 ProtectionMask = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1643
1644 /* Calculate the number of pages this driver is occupying */
1645 DriverPages = BYTES_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage);
1646
1647 /* Get the number of sections and the first section header */
1648 Sections = NtHeaders->FileHeader.NumberOfSections;
1649 ASSERT(Sections != 0);
1650 Section = IMAGE_FIRST_SECTION(NtHeaders);
1651
1652 /* Loop all the sections */
1653 CurrentAddress = (ULONG_PTR)ImageBase;
1654 while (Sections)
1655 {
1656 /* Get the section size */
1657 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
1658
1659 /* Get its virtual address */
1660 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
1661 if (BaseAddress < CurrentAddress)
1662 {
1663 /* Windows doesn't like these */
1664 DPRINT1("Badly linked image!\n");
1665 return;
1666 }
1667
1668 /* Remember the current address */
1669 CurrentAddress = BaseAddress + Size - 1;
1670
1671 /* Next */
1672 Sections--;
1673 Section++;
1674 }
1675
1676 /* Get the number of sections and the first section header */
1677 Sections = NtHeaders->FileHeader.NumberOfSections;
1678 ASSERT(Sections != 0);
1679 Section = IMAGE_FIRST_SECTION(NtHeaders);
1680
1681 /* Set the address at the end to initialize the loop */
1682 CurrentAddress = (ULONG_PTR)Section + Sections - 1;
1683 CurrentProtection = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ;
1684
1685 /* Set the PTE points for the image, and loop its sections */
1686 StartPte = MiAddressToPte(ImageBase);
1687 LastPte = StartPte + DriverPages;
1688 while (Sections)
1689 {
1690 /* Get the section size */
1691 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
1692
1693 /* Get its virtual address and PTE */
1694 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress;
1695 PointerPte = MiAddressToPte(BaseAddress);
1696
1697 /* Check if we were already protecting a run, and found a new run */
1698 if ((ComboPte) && (PointerPte > ComboPte))
1699 {
1700 /* Compute protection */
1701 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
1702
1703 /* Set it */
1704 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
1705
1706 /* Check for overlap */
1707 if (ComboPte == StartPte) StartPte++;
1708
1709 /* One done, reset variables */
1710 ComboPte = NULL;
1711 CombinedProtection = 0;
1712 }
1713
1714 /* Break out when needed */
1715 if (PointerPte >= LastPte) break;
1716
1717 /* Get the requested protection from the image header */
1718 SectionProtection = Section->Characteristics & ProtectionMask;
1719 if (SectionProtection == CurrentProtection)
1720 {
1721 /* Same protection, so merge the request */
1722 CurrentAddress = BaseAddress + Size - 1;
1723 continue;
1724 }
1725
1726 /* This is now a new section, so close up the old one */
1727 CurrentPte = MiAddressToPte(CurrentAddress);
1728
1729 /* Check for overlap */
1730 if (CurrentPte == PointerPte)
1731 {
1732 /* Skip the last PTE, since it overlaps with us */
1733 CurrentPte--;
1734
1735 /* And set the PTE we will merge with */
1736 ASSERT((ComboPte == NULL) || (ComboPte == PointerPte));
1737 ComboPte = PointerPte;
1738
1739 /* Get the most flexible protection by merging both */
1740 CombinedMask |= (SectionProtection | CurrentProtection);
1741 }
1742
1743 /* Loop any PTEs left */
1744 if (CurrentPte >= StartPte)
1745 {
1746 /* Sanity check */
1747 ASSERT(StartPte < LastPte);
1748
1749 /* Make sure we don't overflow past the last PTE in the driver */
1750 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
1751 ASSERT(CurrentPte >= StartPte);
1752
1753 /* Compute the protection and set it */
1754 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
1755 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
1756 }
1757
1758 /* Set new state */
1759 StartPte = PointerPte;
1760 CurrentAddress = BaseAddress + Size - 1;
1761 CurrentProtection = SectionProtection;
1762
1763 /* Next */
1764 Sections--;
1765 Section++;
1766 }
1767
1768 /* Is there a leftover section to merge? */
1769 if (ComboPte)
1770 {
1771 /* Compute and set the protection */
1772 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection);
1773 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask);
1774
1775 /* Handle overlap */
1776 if (ComboPte == StartPte) StartPte++;
1777 }
1778
1779 /* Finally, handle the last section */
1780 CurrentPte = MiPteToAddress(CurrentAddress);
1781 if ((StartPte < LastPte) && (CurrentPte >= StartPte))
1782 {
1783 /* Handle overlap */
1784 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1;
1785 ASSERT(CurrentPte >= StartPte);
1786
1787 /* Compute and set the protection */
1788 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection);
1789 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask);
1790 }
1791 }
1792
1793 VOID
1794 NTAPI
1795 MiSetPagingOfDriver(IN PMMPTE PointerPte,
1796 IN PMMPTE LastPte)
1797 {
1798 PVOID ImageBase;
1799 PETHREAD CurrentThread;
1800 PFN_NUMBER PageCount = 0, PageFrameIndex;
1801 PMMPFN Pfn1;
1802 PAGED_CODE();
1803
1804 /* Get the driver's base address */
1805 ImageBase = MiPteToAddress(PointerPte);
1806 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE);
1807
1808 /* If this is a large page, it's stuck in physical memory */
1809 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return;
1810
1811 /* We should lock the system working set -- we don't have one yet, so just be consistent */
1812 CurrentThread = PsGetCurrentThread();
1813 KeEnterGuardedRegion();
1814 ASSERT((CurrentThread->OwnsSystemWorkingSetExclusive == 0) &&
1815 (CurrentThread->OwnsSystemWorkingSetShared == 0));
1816 CurrentThread->OwnsSystemWorkingSetExclusive = 1;
1817
1818 /* Loop the PTEs */
1819 while (PointerPte <= LastPte)
1820 {
1821 /* Check for valid PTE */
1822 if (PointerPte->u.Hard.Valid == 1)
1823 {
1824 PageFrameIndex = PFN_FROM_PTE(PointerPte);
1825 Pfn1 = MiGetPfnEntry(PageFrameIndex);
1826 ASSERT(Pfn1->u2.ShareCount == 1);
1827
1828 /* No working sets in ReactOS yet */
1829 PageCount++;
1830 }
1831
1832 ImageBase = (PVOID)((ULONG_PTR)ImageBase + PAGE_SIZE);
1833 PointerPte++;
1834 }
1835
1836 /* Release the working set "lock" */
1837 ASSERT(KeAreAllApcsDisabled() == TRUE);
1838 CurrentThread->OwnsSystemWorkingSetExclusive = 0;
1839 KeLeaveGuardedRegion();
1840
1841 /* Do we have any driver pages? */
1842 if (PageCount)
1843 {
1844 /* Update counters */
1845 InterlockedExchangeAdd((PLONG)&MmTotalSystemDriverPages, PageCount);
1846 }
1847 }
1848
1849 VOID
1850 NTAPI
1851 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
1852 {
1853 ULONG_PTR ImageBase;
1854 PIMAGE_NT_HEADERS NtHeaders;
1855 ULONG Sections, Alignment, Size;
1856 PIMAGE_SECTION_HEADER Section;
1857 PMMPTE PointerPte = NULL, LastPte = NULL;
1858 if (MmDisablePagingExecutive) return;
1859
1860 /* Get the driver base address and its NT header */
1861 ImageBase = (ULONG_PTR)LdrEntry->DllBase;
1862 NtHeaders = RtlImageNtHeader((PVOID)ImageBase);
1863 if (!NtHeaders) return;
1864
1865 /* Get the sections and their alignment */
1866 Sections = NtHeaders->FileHeader.NumberOfSections;
1867 Alignment = NtHeaders->OptionalHeader.SectionAlignment - 1;
1868
1869 /* Loop each section */
1870 Section = IMAGE_FIRST_SECTION(NtHeaders);
1871 while (Sections)
1872 {
1873 /* Find PAGE or .edata */
1874 if ((*(PULONG)Section->Name == 'EGAP') ||
1875 (*(PULONG)Section->Name == 'ade.'))
1876 {
1877 /* Had we already done some work? */
1878 if (!PointerPte)
1879 {
1880 /* Nope, setup the first PTE address */
1881 PointerPte = MiAddressToPte(ROUND_TO_PAGES(ImageBase +
1882 Section->
1883 VirtualAddress));
1884 }
1885
1886 /* Compute the size */
1887 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize);
1888
1889 /* Find the last PTE that maps this section */
1890 LastPte = MiAddressToPte(ImageBase +
1891 Section->VirtualAddress +
1892 Alignment +
1893 Size -
1894 PAGE_SIZE);
1895 }
1896 else
1897 {
1898 /* Had we found a section before? */
1899 if (PointerPte)
1900 {
1901 /* Mark it as pageable */
1902 MiSetPagingOfDriver(PointerPte, LastPte);
1903 PointerPte = NULL;
1904 }
1905 }
1906
1907 /* Keep searching */
1908 Sections--;
1909 Section++;
1910 }
1911
1912 /* Handle the straggler */
1913 if (PointerPte) MiSetPagingOfDriver(PointerPte, LastPte);
1914 }
1915
1916 BOOLEAN
1917 NTAPI
1918 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
1919 {
1920 PIMAGE_NT_HEADERS NtHeader;
1921 PAGED_CODE();
1922
1923 /* Get NT Headers */
1924 NtHeader = RtlImageNtHeader(BaseAddress);
1925 if (NtHeader)
1926 {
1927 /* Check if this image is only safe for UP while we have 2+ CPUs */
1928 if ((KeNumberProcessors > 1) &&
1929 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
1930 {
1931 /* Fail */
1932 return FALSE;
1933 }
1934 }
1935
1936 /* Otherwise, it's safe */
1937 return TRUE;
1938 }
1939
1940 NTSTATUS
1941 NTAPI
1942 MmCheckSystemImage(IN HANDLE ImageHandle,
1943 IN BOOLEAN PurgeSection)
1944 {
1945 NTSTATUS Status;
1946 HANDLE SectionHandle;
1947 PVOID ViewBase = NULL;
1948 SIZE_T ViewSize = 0;
1949 IO_STATUS_BLOCK IoStatusBlock;
1950 FILE_STANDARD_INFORMATION FileStandardInfo;
1951 KAPC_STATE ApcState;
1952 PAGED_CODE();
1953
1954 /* Create a section for the DLL */
1955 Status = ZwCreateSection(&SectionHandle,
1956 SECTION_MAP_EXECUTE,
1957 NULL,
1958 NULL,
1959 PAGE_EXECUTE,
1960 SEC_COMMIT,
1961 ImageHandle);
1962 if (!NT_SUCCESS(Status)) return Status;
1963
1964 /* Make sure we're in the system process */
1965 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1966
1967 /* Map it */
1968 Status = ZwMapViewOfSection(SectionHandle,
1969 NtCurrentProcess(),
1970 &ViewBase,
1971 0,
1972 0,
1973 NULL,
1974 &ViewSize,
1975 ViewShare,
1976 0,
1977 PAGE_EXECUTE);
1978 if (!NT_SUCCESS(Status))
1979 {
1980 /* We failed, close the handle and return */
1981 KeUnstackDetachProcess(&ApcState);
1982 ZwClose(SectionHandle);
1983 return Status;
1984 }
1985
1986 /* Now query image information */
1987 Status = ZwQueryInformationFile(ImageHandle,
1988 &IoStatusBlock,
1989 &FileStandardInfo,
1990 sizeof(FileStandardInfo),
1991 FileStandardInformation);
1992 if ( NT_SUCCESS(Status) )
1993 {
1994 /* First, verify the checksum */
1995 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
1996 FileStandardInfo.
1997 EndOfFile.LowPart,
1998 FileStandardInfo.
1999 EndOfFile.LowPart))
2000 {
2001 /* Set checksum failure */
2002 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2003 }
2004
2005 /* Check that it's a valid SMP image if we have more then one CPU */
2006 if (!MmVerifyImageIsOkForMpUse(ViewBase))
2007 {
2008 /* Otherwise it's not the right image */
2009 Status = STATUS_IMAGE_MP_UP_MISMATCH;
2010 }
2011 }
2012
2013 /* Unmap the section, close the handle, and return status */
2014 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2015 KeUnstackDetachProcess(&ApcState);
2016 ZwClose(SectionHandle);
2017 return Status;
2018 }
2019
2020 NTSTATUS
2021 NTAPI
2022 MmLoadSystemImage(IN PUNICODE_STRING FileName,
2023 IN PUNICODE_STRING NamePrefix OPTIONAL,
2024 IN PUNICODE_STRING LoadedName OPTIONAL,
2025 IN ULONG Flags,
2026 OUT PVOID *ModuleObject,
2027 OUT PVOID *ImageBaseAddress)
2028 {
2029 PVOID ModuleLoadBase = NULL;
2030 NTSTATUS Status;
2031 HANDLE FileHandle = NULL;
2032 OBJECT_ATTRIBUTES ObjectAttributes;
2033 IO_STATUS_BLOCK IoStatusBlock;
2034 PIMAGE_NT_HEADERS NtHeader;
2035 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
2036 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
2037 ULONG EntrySize, DriverSize;
2038 PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS;
2039 PCHAR MissingApiName, Buffer;
2040 PWCHAR MissingDriverName;
2041 HANDLE SectionHandle;
2042 ACCESS_MASK DesiredAccess;
2043 PVOID Section = NULL;
2044 BOOLEAN LockOwned = FALSE;
2045 PLIST_ENTRY NextEntry;
2046 IMAGE_INFO ImageInfo;
2047 STRING AnsiTemp;
2048 PAGED_CODE();
2049
2050 /* Detect session-load */
2051 if (Flags)
2052 {
2053 /* Sanity checks */
2054 ASSERT(NamePrefix == NULL);
2055 ASSERT(LoadedName == NULL);
2056
2057 /* Make sure the process is in session too */
2058 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
2059 }
2060
2061 /* Allocate a buffer we'll use for names */
2062 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, 'nLmM');
2063 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2064
2065 /* Check for a separator */
2066 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
2067 {
2068 PWCHAR p;
2069 ULONG BaseLength;
2070
2071 /* Loop the path until we get to the base name */
2072 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
2073 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
2074
2075 /* Get the length */
2076 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
2077 BaseLength *= sizeof(WCHAR);
2078
2079 /* Setup the string */
2080 BaseName.Length = (USHORT)BaseLength;
2081 BaseName.Buffer = p;
2082 }
2083 else
2084 {
2085 /* Otherwise, we already have a base name */
2086 BaseName.Length = FileName->Length;
2087 BaseName.Buffer = FileName->Buffer;
2088 }
2089
2090 /* Setup the maximum length */
2091 BaseName.MaximumLength = BaseName.Length;
2092
2093 /* Now compute the base directory */
2094 BaseDirectory = *FileName;
2095 BaseDirectory.Length -= BaseName.Length;
2096 BaseDirectory.MaximumLength = BaseDirectory.Length;
2097
2098 /* And the prefix, which for now is just the name itself */
2099 PrefixName = *FileName;
2100
2101 /* Check if we have a prefix */
2102 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
2103
2104 /* Check if we already have a name, use it instead */
2105 if (LoadedName) BaseName = *LoadedName;
2106
2107 /* Check for loader snap debugging */
2108 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS)
2109 {
2110 /* Print out standard string */
2111 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n",
2112 &PrefixName, &BaseName, Flags ? "in session space" : "");
2113 }
2114
2115 /* Acquire the load lock */
2116 LoaderScan:
2117 ASSERT(LockOwned == FALSE);
2118 LockOwned = TRUE;
2119 KeEnterCriticalRegion();
2120 KeWaitForSingleObject(&MmSystemLoadLock,
2121 WrVirtualMemory,
2122 KernelMode,
2123 FALSE,
2124 NULL);
2125
2126 /* Scan the module list */
2127 NextEntry = PsLoadedModuleList.Flink;
2128 while (NextEntry != &PsLoadedModuleList)
2129 {
2130 /* Get the entry and compare the names */
2131 LdrEntry = CONTAINING_RECORD(NextEntry,
2132 LDR_DATA_TABLE_ENTRY,
2133 InLoadOrderLinks);
2134 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
2135 {
2136 /* Found it, break out */
2137 break;
2138 }
2139
2140 /* Keep scanning */
2141 NextEntry = NextEntry->Flink;
2142 }
2143
2144 /* Check if we found the image */
2145 if (NextEntry != &PsLoadedModuleList)
2146 {
2147 /* Check if we had already mapped a section */
2148 if (Section)
2149 {
2150 /* Dereference and clear */
2151 ObDereferenceObject(Section);
2152 Section = NULL;
2153 }
2154
2155 /* Check if this was supposed to be a session load */
2156 if (!Flags)
2157 {
2158 /* It wasn't, so just return the data */
2159 *ModuleObject = LdrEntry;
2160 *ImageBaseAddress = LdrEntry->DllBase;
2161 Status = STATUS_IMAGE_ALREADY_LOADED;
2162 }
2163 else
2164 {
2165 /* We don't support session loading yet */
2166 DPRINT1("Unsupported Session-Load!\n");
2167 while (TRUE);
2168 }
2169
2170 /* Do cleanup */
2171 goto Quickie;
2172 }
2173 else if (!Section)
2174 {
2175 /* It wasn't loaded, and we didn't have a previous attempt */
2176 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
2177 KeLeaveCriticalRegion();
2178 LockOwned = FALSE;
2179
2180 /* Check if KD is enabled */
2181 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
2182 {
2183 /* FIXME: Attempt to get image from KD */
2184 }
2185
2186 /* We don't have a valid entry */
2187 LdrEntry = NULL;
2188
2189 /* Setup image attributes */
2190 InitializeObjectAttributes(&ObjectAttributes,
2191 FileName,
2192 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2193 NULL,
2194 NULL);
2195
2196 /* Open the image */
2197 Status = ZwOpenFile(&FileHandle,
2198 FILE_EXECUTE,
2199 &ObjectAttributes,
2200 &IoStatusBlock,
2201 FILE_SHARE_READ | FILE_SHARE_DELETE,
2202 0);
2203 if (!NT_SUCCESS(Status)) goto Quickie;
2204
2205 /* Validate it */
2206 Status = MmCheckSystemImage(FileHandle, FALSE);
2207 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
2208 (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
2209 (Status == STATUS_INVALID_IMAGE_PROTECT))
2210 {
2211 /* Fail loading */
2212 goto Quickie;
2213 }
2214
2215 /* Check if this is a session-load */
2216 if (Flags)
2217 {
2218 /* Then we only need read and execute */
2219 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
2220 }
2221 else
2222 {
2223 /* Otherwise, we can allow write access */
2224 DesiredAccess = SECTION_ALL_ACCESS;
2225 }
2226
2227 /* Initialize the attributes for the section */
2228 InitializeObjectAttributes(&ObjectAttributes,
2229 NULL,
2230 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2231 NULL,
2232 NULL);
2233
2234 /* Create the section */
2235 Status = ZwCreateSection(&SectionHandle,
2236 DesiredAccess,
2237 &ObjectAttributes,
2238 NULL,
2239 PAGE_EXECUTE,
2240 SEC_IMAGE,
2241 FileHandle);
2242 if (!NT_SUCCESS(Status)) goto Quickie;
2243
2244 /* Now get the section pointer */
2245 Status = ObReferenceObjectByHandle(SectionHandle,
2246 SECTION_MAP_EXECUTE,
2247 MmSectionObjectType,
2248 KernelMode,
2249 &Section,
2250 NULL);
2251 ZwClose(SectionHandle);
2252 if (!NT_SUCCESS(Status)) goto Quickie;
2253
2254 /* Check if this was supposed to be a session-load */
2255 if (Flags)
2256 {
2257 /* We don't support session loading yet */
2258 DPRINT1("Unsupported Session-Load!\n");
2259 while (TRUE);
2260 }
2261
2262 /* Check the loader list again, we should end up in the path below */
2263 goto LoaderScan;
2264 }
2265 else
2266 {
2267 /* We don't have a valid entry */
2268 LdrEntry = NULL;
2269 }
2270
2271 /* Load the image */
2272 Status = MiLoadImageSection(&Section,
2273 &ModuleLoadBase,
2274 FileName,
2275 FALSE,
2276 NULL);
2277 ASSERT(Status != STATUS_ALREADY_COMMITTED);
2278
2279 /* Get the size of the driver */
2280 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
2281
2282 /* Make sure we're not being loaded into session space */
2283 if (!Flags)
2284 {
2285 /* Check for success */
2286 if (NT_SUCCESS(Status))
2287 {
2288 #if 0
2289 /* Support large pages for drivers */
2290 MiUseLargeDriverPage(DriverSize / PAGE_SIZE,
2291 &ModuleLoadBase,
2292 &BaseName,
2293 TRUE);
2294 #endif
2295 }
2296
2297 /* Dereference the section */
2298 ObDereferenceObject(Section);
2299 Section = NULL;
2300 }
2301
2302 /* Check for failure of the load earlier */
2303 if (!NT_SUCCESS(Status)) goto Quickie;
2304
2305 /* Relocate the driver */
2306 Status = LdrRelocateImageWithBias(ModuleLoadBase,
2307 0,
2308 "SYSLDR",
2309 STATUS_SUCCESS,
2310 STATUS_CONFLICTING_ADDRESSES,
2311 STATUS_INVALID_IMAGE_FORMAT);
2312 if (!NT_SUCCESS(Status)) goto Quickie;
2313
2314
2315 /* Get the NT Header */
2316 NtHeader = RtlImageNtHeader(ModuleLoadBase);
2317
2318 /* Calculate the size we'll need for the entry and allocate it */
2319 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
2320 BaseName.Length +
2321 sizeof(UNICODE_NULL);
2322
2323 /* Allocate the entry */
2324 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
2325 if (!LdrEntry)
2326 {
2327 /* Fail */
2328 Status = STATUS_INSUFFICIENT_RESOURCES;
2329 goto Quickie;
2330 }
2331
2332 /* Setup the entry */
2333 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
2334 LdrEntry->LoadCount = 1;
2335 LdrEntry->LoadedImports = LoadedImports;
2336 LdrEntry->PatchInformation = NULL;
2337
2338 /* Check the version */
2339 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
2340 (NtHeader->OptionalHeader.MajorImageVersion >= 5))
2341 {
2342 /* Mark this image as a native image */
2343 LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
2344 }
2345
2346 /* Setup the rest of the entry */
2347 LdrEntry->DllBase = ModuleLoadBase;
2348 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
2349 NtHeader->OptionalHeader.AddressOfEntryPoint);
2350 LdrEntry->SizeOfImage = DriverSize;
2351 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
2352 LdrEntry->SectionPointer = Section;
2353
2354 /* Now write the DLL name */
2355 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
2356 LdrEntry->BaseDllName.Length = BaseName.Length;
2357 LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
2358
2359 /* Copy and null-terminate it */
2360 RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
2361 BaseName.Buffer,
2362 BaseName.Length);
2363 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
2364
2365 /* Now allocate the full name */
2366 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
2367 PrefixName.Length +
2368 sizeof(UNICODE_NULL),
2369 TAG_LDR_WSTR);
2370 if (!LdrEntry->FullDllName.Buffer)
2371 {
2372 /* Don't fail, just set it to zero */
2373 LdrEntry->FullDllName.Length = 0;
2374 LdrEntry->FullDllName.MaximumLength = 0;
2375 }
2376 else
2377 {
2378 /* Set it up */
2379 LdrEntry->FullDllName.Length = PrefixName.Length;
2380 LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
2381
2382 /* Copy and null-terminate */
2383 RtlCopyMemory(LdrEntry->FullDllName.Buffer,
2384 PrefixName.Buffer,
2385 PrefixName.Length);
2386 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
2387 }
2388
2389 /* Add the entry */
2390 MiProcessLoaderEntry(LdrEntry, TRUE);
2391
2392 /* Resolve imports */
2393 MissingApiName = Buffer;
2394 Status = MiResolveImageReferences(ModuleLoadBase,
2395 &BaseDirectory,
2396 NULL,
2397 &MissingApiName,
2398 &MissingDriverName,
2399 &LoadedImports);
2400 if (!NT_SUCCESS(Status))
2401 {
2402 /* Fail */
2403 MiProcessLoaderEntry(LdrEntry, FALSE);
2404
2405 /* Check if we need to free the name */
2406 if (LdrEntry->FullDllName.Buffer)
2407 {
2408 /* Free it */
2409 ExFreePool(LdrEntry->FullDllName.Buffer);
2410 }
2411
2412 /* Free the entry itself */
2413 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
2414 LdrEntry = NULL;
2415 goto Quickie;
2416 }
2417
2418 /* Update the loader entry */
2419 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
2420 LDRP_ENTRY_PROCESSED |
2421 LDRP_MM_LOADED);
2422 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2423 LdrEntry->LoadedImports = LoadedImports;
2424
2425 /* FIXME: Call driver verifier's loader function */
2426
2427 /* Write-protect the system image */
2428 MiWriteProtectSystemImage(LdrEntry->DllBase);
2429
2430 /* Check if notifications are enabled */
2431 if (PsImageNotifyEnabled)
2432 {
2433 /* Fill out the notification data */
2434 ImageInfo.Properties = 0;
2435 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
2436 ImageInfo.SystemModeImage = TRUE;
2437 ImageInfo.ImageSize = LdrEntry->SizeOfImage;
2438 ImageInfo.ImageBase = LdrEntry->DllBase;
2439 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
2440
2441 /* Send the notification */
2442 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
2443 }
2444
2445 #if defined(KDBG) || defined(_WINKD_)
2446 /* MiCacheImageSymbols doesn't detect rossym */
2447 if (TRUE)
2448 #else
2449 /* Check if there's symbols */
2450 if (MiCacheImageSymbols(LdrEntry->DllBase))
2451 #endif
2452 {
2453 /* Check if the system root is present */
2454 if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
2455 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
2456 {
2457 /* Add the system root */
2458 UnicodeTemp = PrefixName;
2459 UnicodeTemp.Buffer += 11;
2460 UnicodeTemp.Length -= (11 * sizeof(WCHAR));
2461 sprintf_nt(Buffer,
2462 "%ws%wZ",
2463 &SharedUserData->NtSystemRoot[2],
2464 &UnicodeTemp);
2465 }
2466 else
2467 {
2468 /* Build the name */
2469 sprintf_nt(Buffer, "%wZ", &BaseName);
2470 }
2471
2472 /* Setup the ansi string */
2473 RtlInitString(&AnsiTemp, Buffer);
2474
2475 /* Notify the debugger */
2476 DbgLoadImageSymbols(&AnsiTemp,
2477 LdrEntry->DllBase,
2478 (ULONG_PTR)ZwCurrentProcess());
2479 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
2480 }
2481
2482 /* Page the driver */
2483 ASSERT(Section == NULL);
2484 MiEnablePagingOfDriver(LdrEntry);
2485
2486 /* Return pointers */
2487 *ModuleObject = LdrEntry;
2488 *ImageBaseAddress = LdrEntry->DllBase;
2489
2490 Quickie:
2491 /* Check if we have the lock acquired */
2492 if (LockOwned)
2493 {
2494 /* Release the lock */
2495 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
2496 KeLeaveCriticalRegion();
2497 LockOwned = FALSE;
2498 }
2499
2500 /* If we have a file handle, close it */
2501 if (FileHandle) ZwClose(FileHandle);
2502
2503 /* Check if we had a prefix */
2504 if (NamePrefix) ExFreePool(PrefixName.Buffer);
2505
2506 /* Free the name buffer and return status */
2507 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
2508 return Status;
2509 }
2510
2511 PLDR_DATA_TABLE_ENTRY
2512 NTAPI
2513 MiLookupDataTableEntry(IN PVOID Address)
2514 {
2515 PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL;
2516 PLIST_ENTRY NextEntry;
2517 PAGED_CODE();
2518
2519 /* Loop entries */
2520 NextEntry = PsLoadedModuleList.Flink;
2521 do
2522 {
2523 /* Get the loader entry */
2524 LdrEntry = CONTAINING_RECORD(NextEntry,
2525 LDR_DATA_TABLE_ENTRY,
2526 InLoadOrderLinks);
2527
2528 /* Check if the address matches */
2529 if ((Address >= LdrEntry->DllBase) &&
2530 (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase +
2531 LdrEntry->SizeOfImage)))
2532 {
2533 /* Found a match */
2534 FoundEntry = LdrEntry;
2535 break;
2536 }
2537
2538 /* Move on */
2539 NextEntry = NextEntry->Flink;
2540 } while(NextEntry != &PsLoadedModuleList);
2541
2542 /* Return the entry */
2543 return FoundEntry;
2544 }
2545
2546 /* PUBLIC FUNCTIONS ***********************************************************/
2547
2548 /*
2549 * @implemented
2550 */
2551 PVOID
2552 NTAPI
2553 MmPageEntireDriver(IN PVOID AddressWithinSection)
2554 {
2555 PMMPTE StartPte, EndPte;
2556 PLDR_DATA_TABLE_ENTRY LdrEntry;
2557 PAGED_CODE();
2558
2559 /* Get the loader entry */
2560 LdrEntry = MiLookupDataTableEntry(AddressWithinSection);
2561 if (!LdrEntry) return NULL;
2562
2563 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */
2564 if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer))
2565 {
2566 /* Don't do anything, just return the base address */
2567 return LdrEntry->DllBase;
2568 }
2569
2570 /* Wait for active DPCs to finish before we page out the driver */
2571 KeFlushQueuedDpcs();
2572
2573 /* Get the PTE range for the whole driver image */
2574 StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase);
2575 EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage);
2576
2577 /* Enable paging for the PTE range */
2578 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE);
2579 MiSetPagingOfDriver(StartPte, EndPte);
2580
2581 /* Return the base address */
2582 return LdrEntry->DllBase;
2583 }
2584
2585 /*
2586 * @unimplemented
2587 */
2588 VOID
2589 NTAPI
2590 MmResetDriverPaging(IN PVOID AddressWithinSection)
2591 {
2592 UNIMPLEMENTED;
2593 }
2594
2595 /*
2596 * @implemented
2597 */
2598 PVOID
2599 NTAPI
2600 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
2601 {
2602 PVOID ProcAddress = NULL;
2603 ANSI_STRING AnsiRoutineName;
2604 NTSTATUS Status;
2605 PLIST_ENTRY NextEntry;
2606 PLDR_DATA_TABLE_ENTRY LdrEntry;
2607 BOOLEAN Found = FALSE;
2608 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
2609 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
2610 ULONG Modules = 0;
2611
2612 /* Convert routine to ansi name */
2613 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
2614 SystemRoutineName,
2615 TRUE);
2616 if (!NT_SUCCESS(Status)) return NULL;
2617
2618 /* Lock the list */
2619 KeEnterCriticalRegion();
2620 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
2621
2622 /* Loop the loaded module list */
2623 NextEntry = PsLoadedModuleList.Flink;
2624 while (NextEntry != &PsLoadedModuleList)
2625 {
2626 /* Get the entry */
2627 LdrEntry = CONTAINING_RECORD(NextEntry,
2628 LDR_DATA_TABLE_ENTRY,
2629 InLoadOrderLinks);
2630
2631 /* Check if it's the kernel or HAL */
2632 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
2633 {
2634 /* Found it */
2635 Found = TRUE;
2636 Modules++;
2637 }
2638 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
2639 {
2640 /* Found it */
2641 Found = TRUE;
2642 Modules++;
2643 }
2644
2645 /* Check if we found a valid binary */
2646 if (Found)
2647 {
2648 /* Find the procedure name */
2649 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
2650 &AnsiRoutineName);
2651
2652 /* Break out if we found it or if we already tried both modules */
2653 if (ProcAddress) break;
2654 if (Modules == 2) break;
2655 }
2656
2657 /* Keep looping */
2658 NextEntry = NextEntry->Flink;
2659 }
2660
2661 /* Release the lock */
2662 ExReleaseResourceLite(&PsLoadedModuleResource);
2663 KeLeaveCriticalRegion();
2664
2665 /* Free the string and return */
2666 RtlFreeAnsiString(&AnsiRoutineName);
2667 return ProcAddress;
2668 }
2669