[CSRSS]
[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 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GCC's incompetence strikes again */
16 __inline
17 VOID
18 sprintf_nt(IN PCHAR Buffer,
19 IN PCHAR Format,
20 IN ...)
21 {
22 va_list ap;
23 va_start(ap, Format);
24 vsprintf(Buffer, Format, ap);
25 va_end(ap);
26 }
27
28 /* GLOBALS *******************************************************************/
29
30 LIST_ENTRY PsLoadedModuleList;
31 LIST_ENTRY MmLoadedUserImageList;
32 KSPIN_LOCK PsLoadedModuleSpinLock;
33 ERESOURCE PsLoadedModuleResource;
34 ULONG_PTR PsNtosImageBase;
35 KMUTANT MmSystemLoadLock;
36
37 PVOID MmUnloadedDrivers;
38 PVOID MmLastUnloadedDrivers;
39 PVOID MmTriageActionTaken;
40 PVOID KernelVerifier;
41
42 /* FUNCTIONS *****************************************************************/
43
44 PVOID
45 NTAPI
46 MiCacheImageSymbols(IN PVOID BaseAddress)
47 {
48 ULONG DebugSize;
49 PVOID DebugDirectory = NULL;
50 PAGED_CODE();
51
52 /* Make sure it's safe to access the image */
53 _SEH2_TRY
54 {
55 /* Get the debug directory */
56 DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress,
57 TRUE,
58 IMAGE_DIRECTORY_ENTRY_DEBUG,
59 &DebugSize);
60 }
61 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
62 {
63 /* Nothing */
64 }
65 _SEH2_END;
66
67 /* Return the directory */
68 return DebugDirectory;
69 }
70
71 VOID
72 NTAPI
73 MiFreeBootDriverMemory(PVOID BaseAddress,
74 ULONG Length)
75 {
76 ULONG i;
77
78 /* Loop each page */
79 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
80 {
81 /* Free the page */
82 MmDeleteVirtualMapping(NULL,
83 (PVOID)((ULONG_PTR)BaseAddress + i * PAGE_SIZE),
84 TRUE,
85 NULL,
86 NULL);
87 }
88 }
89
90 NTSTATUS
91 NTAPI
92 MiLoadImageSection(IN OUT PVOID *SectionPtr,
93 OUT PVOID *ImageBase,
94 IN PUNICODE_STRING FileName,
95 IN BOOLEAN SessionLoad,
96 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
97 {
98 PROS_SECTION_OBJECT Section = *SectionPtr;
99 NTSTATUS Status;
100 PEPROCESS Process;
101 PVOID Base = NULL;
102 SIZE_T ViewSize = 0;
103 KAPC_STATE ApcState;
104 LARGE_INTEGER SectionOffset = {{0, 0}};
105 BOOLEAN LoadSymbols = FALSE;
106 ULONG DriverSize;
107 PVOID DriverBase;
108 PAGED_CODE();
109
110 /* Detect session load */
111 if (SessionLoad)
112 {
113 /* Fail */
114 DPRINT1("Session loading not yet supported!\n");
115 while (TRUE);
116 }
117
118 /* Not session load, shouldn't have an entry */
119 ASSERT(LdrEntry == NULL);
120
121 /* Attach to the system process */
122 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
123
124 /* Check if we need to load symbols */
125 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)
126 {
127 /* Yes we do */
128 LoadSymbols = TRUE;
129 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
130 }
131
132 /* Map the driver */
133 Process = PsGetCurrentProcess();
134 Status = MmMapViewOfSection(Section,
135 Process,
136 &Base,
137 0,
138 0,
139 &SectionOffset,
140 &ViewSize,
141 ViewUnmap,
142 0,
143 PAGE_EXECUTE);
144
145 /* Re-enable the flag */
146 if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
147
148 /* Check if we failed with distinguished status code */
149 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
150 {
151 /* Change it to something more generic */
152 Status = STATUS_INVALID_IMAGE_FORMAT;
153 }
154
155 /* Now check if we failed */
156 if (!NT_SUCCESS(Status))
157 {
158 /* Detach and return */
159 KeUnstackDetachProcess(&ApcState);
160 return Status;
161 }
162
163 /* Get the driver size */
164 DriverSize = Section->ImageSection->ImageSize;
165
166 /* Allocate a virtual section for the module */
167 DriverBase = MmAllocateSection(DriverSize, NULL);
168 *ImageBase = DriverBase;
169
170 /* Copy the image */
171 RtlCopyMemory(DriverBase, Base, DriverSize);
172
173 /* Now unmap the view */
174 Status = MmUnmapViewOfSection(Process, Base);
175 ASSERT(NT_SUCCESS(Status));
176
177 /* Detach and return status */
178 KeUnstackDetachProcess(&ApcState);
179 return Status;
180 }
181
182 NTSTATUS
183 NTAPI
184 MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
185 {
186 SIZE_T i;
187
188 /* Check if there's no imports or if we're a boot driver */
189 if ((ImportList == (PVOID)-1) ||
190 (ImportList == (PVOID)-2) ||
191 (ImportList->Count == 0))
192 {
193 /* Then there's nothing to do */
194 return STATUS_SUCCESS;
195 }
196
197 /* Otherwise, FIXME */
198 DPRINT1("%u imports not dereferenced!\n", ImportList->Count);
199 for (i = 0; i < ImportList->Count; i++)
200 {
201 DPRINT1("%wZ <%wZ>\n", &ImportList->Entry[i]->FullDllName, &ImportList->Entry[i]->BaseDllName);
202 }
203 return STATUS_UNSUCCESSFUL;
204 }
205
206 VOID
207 NTAPI
208 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
209 {
210 PAGED_CODE();
211
212 /* Check if there's no imports or we're a boot driver or only one entry */
213 if ((LdrEntry->LoadedImports == (PVOID)-1) ||
214 (LdrEntry->LoadedImports == (PVOID)-2) ||
215 ((ULONG_PTR)LdrEntry->LoadedImports & 1))
216 {
217 /* Nothing to do */
218 return;
219 }
220
221 /* Otherwise, free the import list */
222 ExFreePool(LdrEntry->LoadedImports);
223 }
224
225 PVOID
226 NTAPI
227 MiFindExportedRoutineByName(IN PVOID DllBase,
228 IN PANSI_STRING ExportName)
229 {
230 PULONG NameTable;
231 PUSHORT OrdinalTable;
232 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
233 LONG Low = 0, Mid = 0, High, Ret;
234 USHORT Ordinal;
235 PVOID Function;
236 ULONG ExportSize;
237 PULONG ExportTable;
238 PAGED_CODE();
239
240 /* Get the export directory */
241 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
242 TRUE,
243 IMAGE_DIRECTORY_ENTRY_EXPORT,
244 &ExportSize);
245 if (!ExportDirectory) return NULL;
246
247 /* Setup name tables */
248 NameTable = (PULONG)((ULONG_PTR)DllBase +
249 ExportDirectory->AddressOfNames);
250 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
251 ExportDirectory->AddressOfNameOrdinals);
252
253 /* Do a binary search */
254 High = ExportDirectory->NumberOfNames - 1;
255 while (High >= Low)
256 {
257 /* Get new middle value */
258 Mid = (Low + High) >> 1;
259
260 /* Compare name */
261 Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
262 if (Ret < 0)
263 {
264 /* Update high */
265 High = Mid - 1;
266 }
267 else if (Ret > 0)
268 {
269 /* Update low */
270 Low = Mid + 1;
271 }
272 else
273 {
274 /* We got it */
275 break;
276 }
277 }
278
279 /* Check if we couldn't find it */
280 if (High < Low) return NULL;
281
282 /* Otherwise, this is the ordinal */
283 Ordinal = OrdinalTable[Mid];
284
285 /* Resolve the address and write it */
286 ExportTable = (PULONG)((ULONG_PTR)DllBase +
287 ExportDirectory->AddressOfFunctions);
288 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
289
290 /* We found it! */
291 ASSERT(!(Function > (PVOID)ExportDirectory) &&
292 (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
293 return Function;
294 }
295
296 PVOID
297 NTAPI
298 MiLocateExportName(IN PVOID DllBase,
299 IN PCHAR ExportName)
300 {
301 PULONG NameTable;
302 PUSHORT OrdinalTable;
303 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
304 LONG Low = 0, Mid = 0, High, Ret;
305 USHORT Ordinal;
306 PVOID Function;
307 ULONG ExportSize;
308 PULONG ExportTable;
309 PAGED_CODE();
310
311 /* Get the export directory */
312 ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
313 TRUE,
314 IMAGE_DIRECTORY_ENTRY_EXPORT,
315 &ExportSize);
316 if (!ExportDirectory) return NULL;
317
318 /* Setup name tables */
319 NameTable = (PULONG)((ULONG_PTR)DllBase +
320 ExportDirectory->AddressOfNames);
321 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
322 ExportDirectory->AddressOfNameOrdinals);
323
324 /* Do a binary search */
325 High = ExportDirectory->NumberOfNames - 1;
326 while (High >= Low)
327 {
328 /* Get new middle value */
329 Mid = (Low + High) >> 1;
330
331 /* Compare name */
332 Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
333 if (Ret < 0)
334 {
335 /* Update high */
336 High = Mid - 1;
337 }
338 else if (Ret > 0)
339 {
340 /* Update low */
341 Low = Mid + 1;
342 }
343 else
344 {
345 /* We got it */
346 break;
347 }
348 }
349
350 /* Check if we couldn't find it */
351 if (High < Low) return NULL;
352
353 /* Otherwise, this is the ordinal */
354 Ordinal = OrdinalTable[Mid];
355
356 /* Resolve the address and write it */
357 ExportTable = (PULONG)((ULONG_PTR)DllBase +
358 ExportDirectory->AddressOfFunctions);
359 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
360
361 /* Check if the function is actually a forwarder */
362 if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
363 ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
364 {
365 /* It is, fail */
366 return NULL;
367 }
368
369 /* We found it */
370 return Function;
371 }
372
373 NTSTATUS
374 NTAPI
375 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
376 IN PLIST_ENTRY ListHead)
377 {
378 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
379 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
380 PMM_DLL_INITIALIZE DllInit;
381 UNICODE_STRING RegPath, ImportName;
382 NTSTATUS Status;
383
384 /* Try to see if the image exports a DllInitialize routine */
385 DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
386 "DllInitialize");
387 if (!DllInit) return STATUS_SUCCESS;
388
389 /* Do a temporary copy of BaseDllName called ImportName
390 * because we'll alter the length of the string
391 */
392 ImportName.Length = LdrEntry->BaseDllName.Length;
393 ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
394 ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
395
396 /* Obtain the path to this dll's service in the registry */
397 RegPath.MaximumLength = ServicesKeyName.Length +
398 ImportName.Length + sizeof(UNICODE_NULL);
399 RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
400 RegPath.MaximumLength,
401 TAG_LDR_WSTR);
402
403 /* Check if this allocation was unsuccessful */
404 if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
405
406 /* Build and append the service name itself */
407 RegPath.Length = ServicesKeyName.Length;
408 RtlCopyMemory(RegPath.Buffer,
409 ServicesKeyName.Buffer,
410 ServicesKeyName.Length);
411
412 /* Check if there is a dot in the filename */
413 if (wcschr(ImportName.Buffer, L'.'))
414 {
415 /* Remove the extension */
416 ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
417 ImportName.Buffer) * sizeof(WCHAR);
418 }
419
420 /* Append service name (the basename without extension) */
421 RtlAppendUnicodeStringToString(&RegPath, &ImportName);
422
423 /* Now call the DllInit func */
424 DPRINT("Calling DllInit(%wZ)\n", &RegPath);
425 Status = DllInit(&RegPath);
426
427 /* Clean up */
428 ExFreePool(RegPath.Buffer);
429
430 /* Return status value which DllInitialize returned */
431 return Status;
432 }
433
434 VOID
435 NTAPI
436 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
437 IN BOOLEAN Insert)
438 {
439 KIRQL OldIrql;
440
441 /* Acquire module list lock */
442 KeEnterCriticalRegion();
443 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE);
444
445 /* Acquire the spinlock too as we will insert or remove the entry */
446 OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
447
448 /* Insert or remove from the list */
449 Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
450 RemoveEntryList(&LdrEntry->InLoadOrderLinks);
451
452 /* Release locks */
453 KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
454 ExReleaseResourceLite(&PsLoadedModuleResource);
455 KeLeaveCriticalRegion();
456 }
457
458 VOID
459 NTAPI
460 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
461 IN PVOID OldBase,
462 IN PVOID NewBase,
463 IN ULONG Size)
464 {
465 ULONG_PTR OldBaseTop, Delta;
466 PLDR_DATA_TABLE_ENTRY LdrEntry;
467 PLIST_ENTRY NextEntry;
468 ULONG ImportSize;
469 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
470 PULONG ImageThunk;
471
472 /* Calculate the top and delta */
473 OldBaseTop = (ULONG_PTR)OldBase + Size - 1;
474 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;
475
476 /* Loop the loader block */
477 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
478 NextEntry != &LoaderBlock->LoadOrderListHead;
479 NextEntry = NextEntry->Flink)
480 {
481 /* Get the loader entry */
482 LdrEntry = CONTAINING_RECORD(NextEntry,
483 LDR_DATA_TABLE_ENTRY,
484 InLoadOrderLinks);
485
486 /* Get the import table */
487 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
488 TRUE,
489 IMAGE_DIRECTORY_ENTRY_IMPORT,
490 &ImportSize);
491 if (!ImportDescriptor) continue;
492
493 /* Make sure we have an IAT */
494 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);
495 while ((ImportDescriptor->Name) &&
496 (ImportDescriptor->OriginalFirstThunk))
497 {
498 /* Get the image thunk */
499 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
500 ImportDescriptor->FirstThunk);
501 while (*ImageThunk)
502 {
503 /* Check if it's within this module */
504 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))
505 {
506 /* Relocate it */
507 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",
508 ImageThunk, *ImageThunk, *ImageThunk + Delta);
509 *ImageThunk += Delta;
510 }
511
512 /* Go to the next thunk */
513 ImageThunk++;
514 }
515
516 /* Go to the next import */
517 ImportDescriptor++;
518 }
519 }
520 }
521
522 NTSTATUS
523 NTAPI
524 MiSnapThunk(IN PVOID DllBase,
525 IN PVOID ImageBase,
526 IN PIMAGE_THUNK_DATA Name,
527 IN PIMAGE_THUNK_DATA Address,
528 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
529 IN ULONG ExportSize,
530 IN BOOLEAN SnapForwarder,
531 OUT PCHAR *MissingApi)
532 {
533 BOOLEAN IsOrdinal;
534 USHORT Ordinal;
535 PULONG NameTable;
536 PUSHORT OrdinalTable;
537 PIMAGE_IMPORT_BY_NAME NameImport;
538 USHORT Hint;
539 ULONG Low = 0, Mid = 0, High;
540 LONG Ret;
541 NTSTATUS Status;
542 PCHAR MissingForwarder;
543 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];
544 PULONG ExportTable;
545 ANSI_STRING DllName;
546 UNICODE_STRING ForwarderName;
547 PLIST_ENTRY NextEntry;
548 PLDR_DATA_TABLE_ENTRY LdrEntry;
549 ULONG ForwardExportSize;
550 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;
551 PIMAGE_IMPORT_BY_NAME ForwardName;
552 ULONG ForwardLength;
553 IMAGE_THUNK_DATA ForwardThunk;
554 PAGED_CODE();
555
556 /* Check if this is an ordinal */
557 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);
558 if ((IsOrdinal) && !(SnapForwarder))
559 {
560 /* Get the ordinal number and set it as missing */
561 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -
562 ExportDirectory->Base);
563 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;
564 }
565 else
566 {
567 /* Get the VA if we don't have to snap */
568 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;
569 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;
570
571 /* Copy the procedure name */
572 strncpy(*MissingApi,
573 (PCHAR)&NameImport->Name[0],
574 MAXIMUM_FILENAME_LENGTH - 1);
575
576 /* Setup name tables */
577 DPRINT("Import name: %s\n", NameImport->Name);
578 NameTable = (PULONG)((ULONG_PTR)DllBase +
579 ExportDirectory->AddressOfNames);
580 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
581 ExportDirectory->AddressOfNameOrdinals);
582
583 /* Get the hint and check if it's valid */
584 Hint = NameImport->Hint;
585 if ((Hint < ExportDirectory->NumberOfNames) &&
586 !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))
587 {
588 /* We have a match, get the ordinal number from here */
589 Ordinal = OrdinalTable[Hint];
590 }
591 else
592 {
593 /* Do a binary search */
594 High = ExportDirectory->NumberOfNames - 1;
595 while (High >= Low)
596 {
597 /* Get new middle value */
598 Mid = (Low + High) >> 1;
599
600 /* Compare name */
601 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);
602 if (Ret < 0)
603 {
604 /* Update high */
605 High = Mid - 1;
606 }
607 else if (Ret > 0)
608 {
609 /* Update low */
610 Low = Mid + 1;
611 }
612 else
613 {
614 /* We got it */
615 break;
616 }
617 }
618
619 /* Check if we couldn't find it */
620 if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
621
622 /* Otherwise, this is the ordinal */
623 Ordinal = OrdinalTable[Mid];
624 }
625 }
626
627 /* Check if the ordinal is invalid */
628 if (Ordinal >= ExportDirectory->NumberOfFunctions)
629 {
630 /* Fail */
631 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;
632 }
633 else
634 {
635 /* In case the forwarder is missing */
636 MissingForwarder = NameBuffer;
637
638 /* Resolve the address and write it */
639 ExportTable = (PULONG)((ULONG_PTR)DllBase +
640 ExportDirectory->AddressOfFunctions);
641 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];
642
643 /* Assume success from now on */
644 Status = STATUS_SUCCESS;
645
646 /* Check if the function is actually a forwarder */
647 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&
648 (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
649 {
650 /* Now assume failure in case the forwarder doesn't exist */
651 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
652
653 /* Build the forwarder name */
654 DllName.Buffer = (PCHAR)Address->u1.Function;
655 DllName.Length = strchr(DllName.Buffer, '.') -
656 DllName.Buffer +
657 sizeof(ANSI_NULL);
658 DllName.MaximumLength = DllName.Length;
659
660 /* Convert it */
661 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,
662 &DllName,
663 TRUE)))
664 {
665 /* We failed, just return an error */
666 return Status;
667 }
668
669 /* Loop the module list */
670 NextEntry = PsLoadedModuleList.Flink;
671 while (NextEntry != &PsLoadedModuleList)
672 {
673 /* Get the loader entry */
674 LdrEntry = CONTAINING_RECORD(NextEntry,
675 LDR_DATA_TABLE_ENTRY,
676 InLoadOrderLinks);
677
678 /* Check if it matches */
679 if (RtlPrefixString((PSTRING)&ForwarderName,
680 (PSTRING)&LdrEntry->BaseDllName,
681 TRUE))
682 {
683 /* Get the forwarder export directory */
684 ForwardExportDirectory =
685 RtlImageDirectoryEntryToData(LdrEntry->DllBase,
686 TRUE,
687 IMAGE_DIRECTORY_ENTRY_EXPORT,
688 &ForwardExportSize);
689 if (!ForwardExportDirectory) break;
690
691 /* Allocate a name entry */
692 ForwardLength = strlen(DllName.Buffer + DllName.Length) +
693 sizeof(ANSI_NULL);
694 ForwardName = ExAllocatePoolWithTag(PagedPool,
695 sizeof(*ForwardName) +
696 ForwardLength,
697 TAG_LDR_WSTR);
698 if (!ForwardName) break;
699
700 /* Copy the data */
701 RtlCopyMemory(&ForwardName->Name[0],
702 DllName.Buffer + DllName.Length,
703 ForwardLength);
704 ForwardName->Hint = 0;
705
706 /* Set the new address */
707 ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName;
708
709 /* Snap the forwarder */
710 Status = MiSnapThunk(LdrEntry->DllBase,
711 ImageBase,
712 &ForwardThunk,
713 &ForwardThunk,
714 ForwardExportDirectory,
715 ForwardExportSize,
716 TRUE,
717 &MissingForwarder);
718
719 /* Free the forwarder name and set the thunk */
720 ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR);
721 Address->u1 = ForwardThunk.u1;
722 break;
723 }
724
725 /* Go to the next entry */
726 NextEntry = NextEntry->Flink;
727 }
728
729 /* Free the name */
730 RtlFreeUnicodeString(&ForwarderName);
731 }
732 }
733
734 /* Return status */
735 return Status;
736 }
737
738 NTSTATUS
739 NTAPI
740 MmUnloadSystemImage(IN PVOID ImageHandle)
741 {
742 PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
743 PVOID BaseAddress = LdrEntry->DllBase;
744 NTSTATUS Status;
745 STRING TempName;
746 BOOLEAN HadEntry = FALSE;
747
748 /* Acquire the loader lock */
749 KeEnterCriticalRegion();
750 KeWaitForSingleObject(&MmSystemLoadLock,
751 WrVirtualMemory,
752 KernelMode,
753 FALSE,
754 NULL);
755
756 /* Check if this driver was loaded at boot and didn't get imports parsed */
757 if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;
758
759 /* We should still be alive */
760 ASSERT(LdrEntry->LoadCount != 0);
761 LdrEntry->LoadCount--;
762
763 /* Check if we're still loaded */
764 if (LdrEntry->LoadCount) goto Done;
765
766 /* We should cleanup... are symbols loaded */
767 if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
768 {
769 /* Create the ANSI name */
770 Status = RtlUnicodeStringToAnsiString(&TempName,
771 &LdrEntry->BaseDllName,
772 TRUE);
773 if (NT_SUCCESS(Status))
774 {
775 /* Unload the symbols */
776 DbgUnLoadImageSymbols(&TempName,
777 BaseAddress,
778 (ULONG_PTR)ZwCurrentProcess());
779 RtlFreeAnsiString(&TempName);
780 }
781 }
782
783 /* FIXME: Free the driver */
784 //MmFreeSection(LdrEntry->DllBase);
785
786 /* Check if we're linked in */
787 if (LdrEntry->InLoadOrderLinks.Flink)
788 {
789 /* Remove us */
790 MiProcessLoaderEntry(LdrEntry, FALSE);
791 HadEntry = TRUE;
792 }
793
794 /* Dereference and clear the imports */
795 MiDereferenceImports(LdrEntry->LoadedImports);
796 MiClearImports(LdrEntry);
797
798 /* Check if the entry needs to go away */
799 if (HadEntry)
800 {
801 /* Check if it had a name */
802 if (LdrEntry->FullDllName.Buffer)
803 {
804 /* Free it */
805 ExFreePool(LdrEntry->FullDllName.Buffer);
806 }
807
808 /* Check if we had a section */
809 if (LdrEntry->SectionPointer)
810 {
811 /* Dereference it */
812 ObDereferenceObject(LdrEntry->SectionPointer);
813 }
814
815 /* Free the entry */
816 ExFreePool(LdrEntry);
817 }
818
819 /* Release the system lock and return */
820 Done:
821 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
822 KeLeaveCriticalRegion();
823 return STATUS_SUCCESS;
824 }
825
826 NTSTATUS
827 NTAPI
828 MiResolveImageReferences(IN PVOID ImageBase,
829 IN PUNICODE_STRING ImageFileDirectory,
830 IN PUNICODE_STRING NamePrefix OPTIONAL,
831 OUT PCHAR *MissingApi,
832 OUT PWCHAR *MissingDriver,
833 OUT PLOAD_IMPORTS *LoadImports)
834 {
835 PCHAR MissingApiBuffer = *MissingApi, ImportName;
836 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
837 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
838 PLOAD_IMPORTS LoadedImports, NewImports;
839 ULONG GdiLink, NormalLink, i;
840 BOOLEAN ReferenceNeeded, Loaded;
841 ANSI_STRING TempString;
842 UNICODE_STRING NameString, DllName;
843 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
844 PVOID ImportBase, DllBase;
845 PLIST_ENTRY NextEntry;
846 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
847 NTSTATUS Status;
848 PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
849 PAGED_CODE();
850 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
851 __FUNCTION__, ImageBase, ImageFileDirectory);
852
853 /* Assume no imports */
854 *LoadImports = (PVOID)-2;
855
856 /* Get the import descriptor */
857 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
858 TRUE,
859 IMAGE_DIRECTORY_ENTRY_IMPORT,
860 &ImportSize);
861 if (!ImportDescriptor) return STATUS_SUCCESS;
862
863 /* Loop all imports to count them */
864 for (CurrentImport = ImportDescriptor;
865 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
866 CurrentImport++)
867 {
868 /* One more */
869 ImportCount++;
870 }
871
872 /* Make sure we have non-zero imports */
873 if (ImportCount)
874 {
875 /* Calculate and allocate the list we'll need */
876 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
877 LoadedImports = ExAllocatePoolWithTag(PagedPool,
878 LoadedImportsSize,
879 TAG_LDR_WSTR);
880 if (LoadedImports)
881 {
882 /* Zero it */
883 RtlZeroMemory(LoadedImports, LoadedImportsSize);
884 }
885 }
886 else
887 {
888 /* No table */
889 LoadedImports = NULL;
890 }
891
892 /* Reset the import count and loop descriptors again */
893 ImportCount = GdiLink = NormalLink = 0;
894 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
895 {
896 /* Get the name */
897 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
898
899 /* Check if this is a GDI driver */
900 GdiLink = GdiLink |
901 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
902
903 /* We can also allow dxapi */
904 NormalLink = NormalLink |
905 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
906 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));
907
908 /* Check if this is a valid GDI driver */
909 if ((GdiLink) && (NormalLink))
910 {
911 /* It's not, it's importing stuff it shouldn't be! */
912 MiDereferenceImports(LoadedImports);
913 if (LoadedImports) ExFreePool(LoadedImports);
914 return STATUS_PROCEDURE_NOT_FOUND;
915 }
916
917 /* Check if this is a "core" import, which doesn't get referenced */
918 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
919 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
920 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
921 {
922 /* Don't reference this */
923 ReferenceNeeded = FALSE;
924 }
925 else
926 {
927 /* Reference these modules */
928 ReferenceNeeded = TRUE;
929 }
930
931 /* Now setup a unicode string for the import */
932 RtlInitAnsiString(&TempString, ImportName);
933 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
934 if (!NT_SUCCESS(Status))
935 {
936 /* Failed */
937 MiDereferenceImports(LoadedImports);
938 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
939 return Status;
940 }
941
942 /* We don't support name prefixes yet */
943 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
944
945 /* Remember that we haven't loaded the import at this point */
946 CheckDllState:
947 Loaded = FALSE;
948 ImportBase = NULL;
949
950 /* Loop the driver list */
951 NextEntry = PsLoadedModuleList.Flink;
952 while (NextEntry != &PsLoadedModuleList)
953 {
954 /* Get the loader entry and compare the name */
955 LdrEntry = CONTAINING_RECORD(NextEntry,
956 LDR_DATA_TABLE_ENTRY,
957 InLoadOrderLinks);
958 if (RtlEqualUnicodeString(&NameString,
959 &LdrEntry->BaseDllName,
960 TRUE))
961 {
962 /* Get the base address */
963 ImportBase = LdrEntry->DllBase;
964
965 /* Check if we haven't loaded yet, and we need references */
966 if (!(Loaded) && (ReferenceNeeded))
967 {
968 /* Make sure we're not already loading */
969 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
970 {
971 /* Increase the load count */
972 LdrEntry->LoadCount++;
973 }
974 }
975
976 /* Done, break out */
977 break;
978 }
979
980 /* Go to the next entry */
981 NextEntry = NextEntry->Flink;
982 }
983
984 /* Check if we haven't loaded the import yet */
985 if (!ImportBase)
986 {
987 /* Setup the import DLL name */
988 DllName.MaximumLength = NameString.Length +
989 ImageFileDirectory->Length +
990 sizeof(UNICODE_NULL);
991 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
992 DllName.MaximumLength,
993 TAG_LDR_WSTR);
994 if (DllName.Buffer)
995 {
996 /* Setup the base length and copy it */
997 DllName.Length = ImageFileDirectory->Length;
998 RtlCopyMemory(DllName.Buffer,
999 ImageFileDirectory->Buffer,
1000 ImageFileDirectory->Length);
1001
1002 /* Now add the import name and null-terminate it */
1003 RtlAppendStringToString((PSTRING)&DllName,
1004 (PSTRING)&NameString);
1005 DllName.Buffer[(DllName.MaximumLength - 1) / sizeof(WCHAR)] = UNICODE_NULL;
1006
1007 /* Load the image */
1008 Status = MmLoadSystemImage(&DllName,
1009 NamePrefix,
1010 NULL,
1011 0,
1012 (PVOID)&DllEntry,
1013 &DllBase);
1014 if (NT_SUCCESS(Status))
1015 {
1016 /* We can free the DLL Name */
1017 ExFreePool(DllName.Buffer);
1018 }
1019 else
1020 {
1021 /* Fill out the information for the error */
1022 *MissingDriver = DllName.Buffer;
1023 *(PULONG)MissingDriver |= 1;
1024 *MissingApi = NULL;
1025 }
1026 }
1027 else
1028 {
1029 /* We're out of resources */
1030 Status = STATUS_INSUFFICIENT_RESOURCES;
1031 }
1032
1033 /* Check if we're OK until now */
1034 if (NT_SUCCESS(Status))
1035 {
1036 /* We're now loaded */
1037 Loaded = TRUE;
1038
1039 /* Sanity check */
1040 ASSERT(DllBase = DllEntry->DllBase);
1041
1042 /* Call the initialization routines */
1043 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
1044 if (!NT_SUCCESS(Status))
1045 {
1046 /* We failed, unload the image */
1047 MmUnloadSystemImage(DllEntry);
1048 while (TRUE);
1049 Loaded = FALSE;
1050 }
1051 }
1052
1053 /* Check if we failed by here */
1054 if (!NT_SUCCESS(Status))
1055 {
1056 /* Cleanup and return */
1057 RtlFreeUnicodeString(&NameString);
1058 MiDereferenceImports(LoadedImports);
1059 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1060 return Status;
1061 }
1062
1063 /* Loop again to make sure that everything is OK */
1064 goto CheckDllState;
1065 }
1066
1067 /* Check if we're support to reference this import */
1068 if ((ReferenceNeeded) && (LoadedImports))
1069 {
1070 /* Make sure we're not already loading */
1071 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1072 {
1073 /* Add the entry */
1074 LoadedImports->Entry[LoadedImports->Count] = LdrEntry;
1075 LoadedImports->Count++;
1076 }
1077 }
1078
1079 /* Free the import name */
1080 RtlFreeUnicodeString(&NameString);
1081
1082 /* Set the missing driver name and get the export directory */
1083 *MissingDriver = LdrEntry->BaseDllName.Buffer;
1084 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
1085 TRUE,
1086 IMAGE_DIRECTORY_ENTRY_EXPORT,
1087 &ExportSize);
1088 if (!ExportDirectory)
1089 {
1090 /* Cleanup and return */
1091 MiDereferenceImports(LoadedImports);
1092 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1093 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
1094 }
1095
1096 /* Make sure we have an IAT */
1097 if (ImportDescriptor->OriginalFirstThunk)
1098 {
1099 /* Get the first thunks */
1100 OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
1101 ImportDescriptor->OriginalFirstThunk);
1102 FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
1103 ImportDescriptor->FirstThunk);
1104
1105 /* Loop the IAT */
1106 while (OrigThunk->u1.AddressOfData)
1107 {
1108 /* Snap thunk */
1109 Status = MiSnapThunk(ImportBase,
1110 ImageBase,
1111 OrigThunk++,
1112 FirstThunk++,
1113 ExportDirectory,
1114 ExportSize,
1115 FALSE,
1116 MissingApi);
1117 if (!NT_SUCCESS(Status))
1118 {
1119 /* Cleanup and return */
1120 MiDereferenceImports(LoadedImports);
1121 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1122 return Status;
1123 }
1124
1125 /* Reset the buffer */
1126 *MissingApi = MissingApiBuffer;
1127 }
1128 }
1129
1130 /* Go to the next import */
1131 ImportDescriptor++;
1132 }
1133
1134 /* Check if we have an import list */
1135 if (LoadedImports)
1136 {
1137 /* Reset the count again, and loop entries*/
1138 ImportCount = 0;
1139 for (i = 0; i < LoadedImports->Count; i++)
1140 {
1141 if (LoadedImports->Entry[i])
1142 {
1143 /* Got an entry, OR it with 1 in case it's the single entry */
1144 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);
1145 ImportCount++;
1146 }
1147 }
1148
1149 /* Check if we had no imports */
1150 if (!ImportCount)
1151 {
1152 /* Free the list and set it to no imports */
1153 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1154 LoadedImports = (PVOID)-2;
1155 }
1156 else if (ImportCount == 1)
1157 {
1158 /* Just one entry, we can free the table and only use our entry */
1159 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1160 LoadedImports = (PLOAD_IMPORTS)ImportEntry;
1161 }
1162 else if (ImportCount != LoadedImports->Count)
1163 {
1164 /* Allocate a new list */
1165 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1166 NewImports = ExAllocatePoolWithTag(PagedPool,
1167 LoadedImportsSize,
1168 TAG_LDR_WSTR);
1169 if (NewImports)
1170 {
1171 /* Set count */
1172 NewImports->Count = 0;
1173
1174 /* Loop all the imports */
1175 for (i = 0; i < LoadedImports->Count; i++)
1176 {
1177 /* Make sure it's valid */
1178 if (LoadedImports->Entry[i])
1179 {
1180 /* Copy it */
1181 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
1182 NewImports->Count++;
1183 }
1184 }
1185
1186 /* Free the old copy */
1187 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1188 LoadedImports = NewImports;
1189 }
1190 }
1191
1192 /* Return the list */
1193 *LoadImports = LoadedImports;
1194 }
1195
1196 /* Return success */
1197 return STATUS_SUCCESS;
1198 }
1199
1200 VOID
1201 NTAPI
1202 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1203 {
1204 PLIST_ENTRY NextEntry;
1205 ULONG i = 0;
1206 PIMAGE_NT_HEADERS NtHeader;
1207 PLDR_DATA_TABLE_ENTRY LdrEntry;
1208 PIMAGE_FILE_HEADER FileHeader;
1209 BOOLEAN ValidRelocs;
1210 PIMAGE_DATA_DIRECTORY DataDirectory;
1211 PVOID DllBase, NewImageAddress;
1212 NTSTATUS Status;
1213
1214 /* Loop driver list */
1215 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
1216 NextEntry != &LoaderBlock->LoadOrderListHead;
1217 NextEntry = NextEntry->Flink)
1218 {
1219 /* Get the loader entry and NT header */
1220 LdrEntry = CONTAINING_RECORD(NextEntry,
1221 LDR_DATA_TABLE_ENTRY,
1222 InLoadOrderLinks);
1223 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
1224
1225 /* Debug info */
1226 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1227 LdrEntry->DllBase,
1228 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage,
1229 &LdrEntry->FullDllName);
1230
1231 /* Skip kernel and HAL */
1232 /* ROS HACK: Skip BOOTVID/KDCOM too */
1233 i++;
1234 if (i <= 4) continue;
1235
1236 /* Skip non-drivers */
1237 if (!NtHeader) continue;
1238
1239 /* Get the file header and make sure we can relocate */
1240 FileHeader = &NtHeader->FileHeader;
1241 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
1242 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
1243 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
1244
1245 /* Everything made sense until now, check the relocation section too */
1246 DataDirectory = &NtHeader->OptionalHeader.
1247 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1248 if (!DataDirectory->VirtualAddress)
1249 {
1250 /* We don't really have relocations */
1251 ValidRelocs = FALSE;
1252 }
1253 else
1254 {
1255 /* Make sure the size is valid */
1256 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
1257 LdrEntry->SizeOfImage)
1258 {
1259 /* They're not, skip */
1260 continue;
1261 }
1262
1263 /* We have relocations */
1264 ValidRelocs = TRUE;
1265 }
1266
1267 /* Remember the original address */
1268 DllBase = LdrEntry->DllBase;
1269
1270 /* Allocate a virtual section for the module */
1271 NewImageAddress = MmAllocateSection(LdrEntry->SizeOfImage, NULL);
1272 if (!NewImageAddress)
1273 {
1274 /* Shouldn't happen */
1275 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1276 while (TRUE);
1277 }
1278
1279 /* Sanity check */
1280 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
1281 ASSERT(ExpInitializationPhase == 0);
1282
1283 /* Now copy the entire driver over */
1284 RtlCopyMemory(NewImageAddress, DllBase, LdrEntry->SizeOfImage);
1285
1286 /* Sanity check */
1287 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
1288
1289 /* Set the image base to the address where the loader put it */
1290 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1291 NtHeader = RtlImageNtHeader(NewImageAddress);
1292 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1293
1294 /* Check if we had relocations */
1295 if (ValidRelocs)
1296 {
1297 /* Relocate the image */
1298 Status = LdrRelocateImageWithBias(NewImageAddress,
1299 0,
1300 "SYSLDR",
1301 STATUS_SUCCESS,
1302 STATUS_CONFLICTING_ADDRESSES,
1303 STATUS_INVALID_IMAGE_FORMAT);
1304 if (!NT_SUCCESS(Status))
1305 {
1306 /* This shouldn't happen */
1307 DPRINT1("Relocations failed!\n");
1308 while (TRUE);
1309 }
1310 }
1311
1312 /* Update the loader entry */
1313 LdrEntry->DllBase = NewImageAddress;
1314
1315 /* Update the thunks */
1316 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
1317 MiUpdateThunks(LoaderBlock,
1318 DllBase,
1319 NewImageAddress,
1320 LdrEntry->SizeOfImage);
1321
1322 /* Update the loader entry */
1323 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED;
1324 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
1325 NtHeader->OptionalHeader.AddressOfEntryPoint);
1326 LdrEntry->SizeOfImage = LdrEntry->SizeOfImage;
1327
1328 /* Free the old copy */
1329 MiFreeBootDriverMemory(DllBase, LdrEntry->SizeOfImage);
1330 }
1331 }
1332
1333 BOOLEAN
1334 NTAPI
1335 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1336 {
1337 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
1338 PLIST_ENTRY ListHead, NextEntry;
1339 ULONG EntrySize;
1340
1341 /* Setup the loaded module list and locks */
1342 ExInitializeResourceLite(&PsLoadedModuleResource);
1343 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
1344 InitializeListHead(&PsLoadedModuleList);
1345
1346 /* Get loop variables and the kernel entry */
1347 ListHead = &LoaderBlock->LoadOrderListHead;
1348 NextEntry = ListHead->Flink;
1349 LdrEntry = CONTAINING_RECORD(NextEntry,
1350 LDR_DATA_TABLE_ENTRY,
1351 InLoadOrderLinks);
1352 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
1353
1354 /* Loop the loader block */
1355 while (NextEntry != ListHead)
1356 {
1357 /* Get the loader entry */
1358 LdrEntry = CONTAINING_RECORD(NextEntry,
1359 LDR_DATA_TABLE_ENTRY,
1360 InLoadOrderLinks);
1361
1362 /* FIXME: ROS HACK. Make sure this is a driver */
1363 if (!RtlImageNtHeader(LdrEntry->DllBase))
1364 {
1365 /* Skip this entry */
1366 NextEntry= NextEntry->Flink;
1367 continue;
1368 }
1369
1370 /* Calculate the size we'll need and allocate a copy */
1371 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1372 LdrEntry->BaseDllName.MaximumLength +
1373 sizeof(UNICODE_NULL);
1374 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
1375 if (!NewEntry) return FALSE;
1376
1377 /* Copy the entry over */
1378 *NewEntry = *LdrEntry;
1379
1380 /* Allocate the name */
1381 NewEntry->FullDllName.Buffer =
1382 ExAllocatePoolWithTag(PagedPool,
1383 LdrEntry->FullDllName.MaximumLength +
1384 sizeof(UNICODE_NULL),
1385 TAG_LDR_WSTR);
1386 if (!NewEntry->FullDllName.Buffer) return FALSE;
1387
1388 /* Set the base name */
1389 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
1390
1391 /* Copy the full and base name */
1392 RtlCopyMemory(NewEntry->FullDllName.Buffer,
1393 LdrEntry->FullDllName.Buffer,
1394 LdrEntry->FullDllName.MaximumLength);
1395 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
1396 LdrEntry->BaseDllName.Buffer,
1397 LdrEntry->BaseDllName.MaximumLength);
1398
1399 /* Null-terminate the base name */
1400 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
1401 sizeof(WCHAR)] = UNICODE_NULL;
1402
1403 /* Insert the entry into the list */
1404 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
1405 NextEntry = NextEntry->Flink;
1406 }
1407
1408 /* Build the import lists for the boot drivers */
1409 //MiBuildImportsForBootDrivers();
1410
1411 /* We're done */
1412 return TRUE;
1413 }
1414
1415 BOOLEAN
1416 NTAPI
1417 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
1418 {
1419 PIMAGE_NT_HEADERS NtHeader;
1420 PAGED_CODE();
1421
1422 /* Get NT Headers */
1423 NtHeader = RtlImageNtHeader(BaseAddress);
1424 if (NtHeader)
1425 {
1426 /* Check if this image is only safe for UP while we have 2+ CPUs */
1427 if ((KeNumberProcessors > 1) &&
1428 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
1429 {
1430 /* Fail */
1431 return FALSE;
1432 }
1433 }
1434
1435 /* Otherwise, it's safe */
1436 return TRUE;
1437 }
1438
1439 NTSTATUS
1440 NTAPI
1441 MmCheckSystemImage(IN HANDLE ImageHandle,
1442 IN BOOLEAN PurgeSection)
1443 {
1444 NTSTATUS Status;
1445 HANDLE SectionHandle;
1446 PVOID ViewBase = NULL;
1447 SIZE_T ViewSize = 0;
1448 IO_STATUS_BLOCK IoStatusBlock;
1449 FILE_STANDARD_INFORMATION FileStandardInfo;
1450 KAPC_STATE ApcState;
1451 PAGED_CODE();
1452
1453 /* Create a section for the DLL */
1454 Status = ZwCreateSection(&SectionHandle,
1455 SECTION_MAP_EXECUTE,
1456 NULL,
1457 NULL,
1458 PAGE_EXECUTE,
1459 SEC_COMMIT,
1460 ImageHandle);
1461 if (!NT_SUCCESS(Status)) return Status;
1462
1463 /* Make sure we're in the system process */
1464 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1465
1466 /* Map it */
1467 Status = ZwMapViewOfSection(SectionHandle,
1468 NtCurrentProcess(),
1469 &ViewBase,
1470 0,
1471 0,
1472 NULL,
1473 &ViewSize,
1474 ViewShare,
1475 0,
1476 PAGE_EXECUTE);
1477 if (!NT_SUCCESS(Status))
1478 {
1479 /* We failed, close the handle and return */
1480 KeUnstackDetachProcess(&ApcState);
1481 ZwClose(SectionHandle);
1482 return Status;
1483 }
1484
1485 /* Now query image information */
1486 Status = ZwQueryInformationFile(ImageHandle,
1487 &IoStatusBlock,
1488 &FileStandardInfo,
1489 sizeof(FileStandardInfo),
1490 FileStandardInformation);
1491 if ( NT_SUCCESS(Status) )
1492 {
1493 /* First, verify the checksum */
1494 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
1495 FileStandardInfo.
1496 EndOfFile.LowPart,
1497 FileStandardInfo.
1498 EndOfFile.LowPart))
1499 {
1500 /* Set checksum failure */
1501 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
1502 }
1503
1504 /* Check that it's a valid SMP image if we have more then one CPU */
1505 if (!MmVerifyImageIsOkForMpUse(ViewBase))
1506 {
1507 /* Otherwise it's not the right image */
1508 Status = STATUS_IMAGE_MP_UP_MISMATCH;
1509 }
1510 }
1511
1512 /* Unmap the section, close the handle, and return status */
1513 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1514 KeUnstackDetachProcess(&ApcState);
1515 ZwClose(SectionHandle);
1516 return Status;
1517 }
1518
1519 NTSTATUS
1520 NTAPI
1521 MmLoadSystemImage(IN PUNICODE_STRING FileName,
1522 IN PUNICODE_STRING NamePrefix OPTIONAL,
1523 IN PUNICODE_STRING LoadedName OPTIONAL,
1524 IN ULONG Flags,
1525 OUT PVOID *ModuleObject,
1526 OUT PVOID *ImageBaseAddress)
1527 {
1528 PVOID ModuleLoadBase = NULL;
1529 NTSTATUS Status;
1530 HANDLE FileHandle = NULL;
1531 OBJECT_ATTRIBUTES ObjectAttributes;
1532 IO_STATUS_BLOCK IoStatusBlock;
1533 PIMAGE_NT_HEADERS NtHeader;
1534 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
1535 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
1536 ULONG EntrySize, DriverSize;
1537 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
1538 PCHAR MissingApiName, Buffer;
1539 PWCHAR MissingDriverName;
1540 HANDLE SectionHandle;
1541 ACCESS_MASK DesiredAccess;
1542 PVOID Section = NULL;
1543 BOOLEAN LockOwned = FALSE;
1544 PLIST_ENTRY NextEntry;
1545 IMAGE_INFO ImageInfo;
1546 STRING AnsiTemp;
1547 PAGED_CODE();
1548
1549 /* Detect session-load */
1550 if (Flags)
1551 {
1552 /* Sanity checks */
1553 ASSERT(NamePrefix == NULL);
1554 ASSERT(LoadedName == NULL);
1555
1556 /* Make sure the process is in session too */
1557 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
1558 }
1559
1560 /* Allocate a buffer we'll use for names */
1561 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
1562 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1563
1564 /* Check for a separator */
1565 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
1566 {
1567 PWCHAR p;
1568 ULONG BaseLength;
1569
1570 /* Loop the path until we get to the base name */
1571 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
1572 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
1573
1574 /* Get the length */
1575 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
1576 BaseLength *= sizeof(WCHAR);
1577
1578 /* Setup the string */
1579 BaseName.Length = (USHORT)BaseLength;
1580 BaseName.Buffer = p;
1581 }
1582 else
1583 {
1584 /* Otherwise, we already have a base name */
1585 BaseName.Length = FileName->Length;
1586 BaseName.Buffer = FileName->Buffer;
1587 }
1588
1589 /* Setup the maximum length */
1590 BaseName.MaximumLength = BaseName.Length;
1591
1592 /* Now compute the base directory */
1593 BaseDirectory = *FileName;
1594 BaseDirectory.Length -= BaseName.Length;
1595 BaseDirectory.MaximumLength = BaseDirectory.Length;
1596
1597 /* And the prefix, which for now is just the name itself */
1598 PrefixName = *FileName;
1599
1600 /* Check if we have a prefix */
1601 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
1602
1603 /* Check if we already have a name, use it instead */
1604 if (LoadedName) BaseName = *LoadedName;
1605
1606 /* Acquire the load lock */
1607 LoaderScan:
1608 ASSERT(LockOwned == FALSE);
1609 LockOwned = TRUE;
1610 KeEnterCriticalRegion();
1611 KeWaitForSingleObject(&MmSystemLoadLock,
1612 WrVirtualMemory,
1613 KernelMode,
1614 FALSE,
1615 NULL);
1616
1617 /* Scan the module list */
1618 NextEntry = PsLoadedModuleList.Flink;
1619 while (NextEntry != &PsLoadedModuleList)
1620 {
1621 /* Get the entry and compare the names */
1622 LdrEntry = CONTAINING_RECORD(NextEntry,
1623 LDR_DATA_TABLE_ENTRY,
1624 InLoadOrderLinks);
1625 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
1626 {
1627 /* Found it, break out */
1628 break;
1629 }
1630
1631 /* Keep scanning */
1632 NextEntry = NextEntry->Flink;
1633 }
1634
1635 /* Check if we found the image */
1636 if (NextEntry != &PsLoadedModuleList)
1637 {
1638 /* Check if we had already mapped a section */
1639 if (Section)
1640 {
1641 /* Dereference and clear */
1642 ObDereferenceObject(Section);
1643 Section = NULL;
1644 }
1645
1646 /* Check if this was supposed to be a session load */
1647 if (!Flags)
1648 {
1649 /* It wasn't, so just return the data */
1650 *ModuleObject = LdrEntry;
1651 *ImageBaseAddress = LdrEntry->DllBase;
1652 Status = STATUS_IMAGE_ALREADY_LOADED;
1653 }
1654 else
1655 {
1656 /* We don't support session loading yet */
1657 DPRINT1("Unsupported Session-Load!\n");
1658 while (TRUE);
1659 }
1660
1661 /* Do cleanup */
1662 goto Quickie;
1663 }
1664 else if (!Section)
1665 {
1666 /* It wasn't loaded, and we didn't have a previous attempt */
1667 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
1668 KeLeaveCriticalRegion();
1669 LockOwned = FALSE;
1670
1671 /* Check if KD is enabled */
1672 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
1673 {
1674 /* FIXME: Attempt to get image from KD */
1675 }
1676
1677 /* We don't have a valid entry */
1678 LdrEntry = NULL;
1679
1680 /* Setup image attributes */
1681 InitializeObjectAttributes(&ObjectAttributes,
1682 FileName,
1683 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1684 NULL,
1685 NULL);
1686
1687 /* Open the image */
1688 Status = ZwOpenFile(&FileHandle,
1689 FILE_EXECUTE,
1690 &ObjectAttributes,
1691 &IoStatusBlock,
1692 FILE_SHARE_READ | FILE_SHARE_DELETE,
1693 0);
1694 if (!NT_SUCCESS(Status)) goto Quickie;
1695
1696 /* Validate it */
1697 Status = MmCheckSystemImage(FileHandle, FALSE);
1698 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
1699 (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
1700 (Status == STATUS_INVALID_IMAGE_FORMAT))
1701 {
1702 /* Fail loading */
1703 goto Quickie;
1704 }
1705
1706 /* Check if this is a session-load */
1707 if (Flags)
1708 {
1709 /* Then we only need read and execute */
1710 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
1711 }
1712 else
1713 {
1714 /* Otherwise, we can allow write access */
1715 DesiredAccess = SECTION_ALL_ACCESS;
1716 }
1717
1718 /* Initialize the attributes for the section */
1719 InitializeObjectAttributes(&ObjectAttributes,
1720 NULL,
1721 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1722 NULL,
1723 NULL);
1724
1725 /* Create the section */
1726 Status = ZwCreateSection(&SectionHandle,
1727 DesiredAccess,
1728 &ObjectAttributes,
1729 NULL,
1730 PAGE_EXECUTE,
1731 SEC_IMAGE,
1732 FileHandle);
1733 if (!NT_SUCCESS(Status)) goto Quickie;
1734
1735 /* Now get the section pointer */
1736 Status = ObReferenceObjectByHandle(SectionHandle,
1737 SECTION_MAP_EXECUTE,
1738 MmSectionObjectType,
1739 KernelMode,
1740 &Section,
1741 NULL);
1742 ZwClose(SectionHandle);
1743 if (!NT_SUCCESS(Status)) goto Quickie;
1744
1745 /* Check if this was supposed to be a session-load */
1746 if (Flags)
1747 {
1748 /* We don't support session loading yet */
1749 DPRINT1("Unsupported Session-Load!\n");
1750 while (TRUE);
1751 }
1752
1753 /* Check the loader list again, we should end up in the path below */
1754 goto LoaderScan;
1755 }
1756 else
1757 {
1758 /* We don't have a valid entry */
1759 LdrEntry = NULL;
1760 }
1761
1762 /* Load the image */
1763 Status = MiLoadImageSection(&Section,
1764 &ModuleLoadBase,
1765 FileName,
1766 FALSE,
1767 NULL);
1768 ASSERT(Status != STATUS_ALREADY_COMMITTED);
1769
1770 /* Get the size of the driver */
1771 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
1772
1773 /* Make sure we're not being loaded into session space */
1774 if (!Flags)
1775 {
1776 /* Check for success */
1777 if (NT_SUCCESS(Status))
1778 {
1779 /* FIXME: Support large pages for drivers */
1780 }
1781
1782 /* Dereference the section */
1783 ObDereferenceObject(Section);
1784 Section = NULL;
1785 }
1786
1787 /* Get the NT Header */
1788 NtHeader = RtlImageNtHeader(ModuleLoadBase);
1789
1790 /* Relocate the driver */
1791 Status = LdrRelocateImageWithBias(ModuleLoadBase,
1792 0,
1793 "SYSLDR",
1794 STATUS_SUCCESS,
1795 STATUS_CONFLICTING_ADDRESSES,
1796 STATUS_INVALID_IMAGE_FORMAT);
1797 if (!NT_SUCCESS(Status)) goto Quickie;
1798
1799 /* Calculate the size we'll need for the entry and allocate it */
1800 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1801 BaseName.Length +
1802 sizeof(UNICODE_NULL);
1803
1804 /* Allocate the entry */
1805 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
1806 if (!LdrEntry)
1807 {
1808 /* Fail */
1809 Status = STATUS_INSUFFICIENT_RESOURCES;
1810 goto Quickie;
1811 }
1812
1813 /* Setup the entry */
1814 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
1815 LdrEntry->LoadCount = 1;
1816 LdrEntry->LoadedImports = LoadedImports;
1817 LdrEntry->PatchInformation = NULL;
1818
1819 /* Check the version */
1820 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
1821 (NtHeader->OptionalHeader.MajorImageVersion >= 5))
1822 {
1823 /* Mark this image as a native image */
1824 LdrEntry->Flags |= LDRP_ENTRY_NATIVE;
1825 }
1826
1827 /* Setup the rest of the entry */
1828 LdrEntry->DllBase = ModuleLoadBase;
1829 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
1830 NtHeader->OptionalHeader.AddressOfEntryPoint);
1831 LdrEntry->SizeOfImage = DriverSize;
1832 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
1833 LdrEntry->SectionPointer = Section;
1834
1835 /* Now write the DLL name */
1836 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
1837 LdrEntry->BaseDllName.Length = BaseName.Length;
1838 LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
1839
1840 /* Copy and null-terminate it */
1841 RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
1842 BaseName.Buffer,
1843 BaseName.Length);
1844 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1845
1846 /* Now allocate the full name */
1847 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
1848 PrefixName.Length +
1849 sizeof(UNICODE_NULL),
1850 TAG_LDR_WSTR);
1851 if (!LdrEntry->FullDllName.Buffer)
1852 {
1853 /* Don't fail, just set it to zero */
1854 LdrEntry->FullDllName.Length = 0;
1855 LdrEntry->FullDllName.MaximumLength = 0;
1856 }
1857 else
1858 {
1859 /* Set it up */
1860 LdrEntry->FullDllName.Length = PrefixName.Length;
1861 LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
1862
1863 /* Copy and null-terminate */
1864 RtlCopyMemory(LdrEntry->FullDllName.Buffer,
1865 PrefixName.Buffer,
1866 PrefixName.Length);
1867 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1868 }
1869
1870 /* Add the entry */
1871 MiProcessLoaderEntry(LdrEntry, TRUE);
1872
1873 /* Resolve imports */
1874 MissingApiName = Buffer;
1875 Status = MiResolveImageReferences(ModuleLoadBase,
1876 &BaseDirectory,
1877 NULL,
1878 &MissingApiName,
1879 &MissingDriverName,
1880 &LoadedImports);
1881 if (!NT_SUCCESS(Status))
1882 {
1883 /* Fail */
1884 MiProcessLoaderEntry(LdrEntry, FALSE);
1885
1886 /* Check if we need to free the name */
1887 if (LdrEntry->FullDllName.Buffer)
1888 {
1889 /* Free it */
1890 ExFreePool(LdrEntry->FullDllName.Buffer);
1891 }
1892
1893 /* Free the entry itself */
1894 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
1895 LdrEntry = NULL;
1896 goto Quickie;
1897 }
1898
1899 /* Update the loader entry */
1900 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
1901 LDRP_ENTRY_PROCESSED |
1902 LDRP_MM_LOADED);
1903 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
1904 LdrEntry->LoadedImports = LoadedImports;
1905
1906 /* FIXME: Apply driver verifier */
1907
1908 /* FIXME: Write-protect the system image */
1909
1910 /* Check if notifications are enabled */
1911 if (PsImageNotifyEnabled)
1912 {
1913 /* Fill out the notification data */
1914 ImageInfo.Properties = 0;
1915 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
1916 ImageInfo.SystemModeImage = TRUE;
1917 ImageInfo.ImageSize = LdrEntry->SizeOfImage;
1918 ImageInfo.ImageBase = LdrEntry->DllBase;
1919 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
1920
1921 /* Send the notification */
1922 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
1923 }
1924
1925 #if defined(KDBG) || defined(_WINKD_)
1926 /* MiCacheImageSymbols doesn't detect rossym */
1927 if (TRUE)
1928 #else
1929 /* Check if there's symbols */
1930 if (MiCacheImageSymbols(LdrEntry->DllBase))
1931 #endif
1932 {
1933 /* Check if the system root is present */
1934 if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
1935 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
1936 {
1937 /* Add the system root */
1938 UnicodeTemp = PrefixName;
1939 UnicodeTemp.Buffer += 11;
1940 UnicodeTemp.Length -= (11 * sizeof(WCHAR));
1941 sprintf_nt(Buffer,
1942 "%ws%wZ",
1943 &SharedUserData->NtSystemRoot[2],
1944 &UnicodeTemp);
1945 }
1946 else
1947 {
1948 /* Build the name */
1949 sprintf_nt(Buffer, "%wZ", &BaseName);
1950 }
1951
1952 /* Setup the ansi string */
1953 RtlInitString(&AnsiTemp, Buffer);
1954
1955 /* Notify the debugger */
1956 DbgLoadImageSymbols(&AnsiTemp,
1957 LdrEntry->DllBase,
1958 (ULONG_PTR)ZwCurrentProcess());
1959 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
1960 }
1961
1962 /* FIXME: Page the driver */
1963 ASSERT(Section == NULL);
1964
1965 /* Return pointers */
1966 *ModuleObject = LdrEntry;
1967 *ImageBaseAddress = LdrEntry->DllBase;
1968
1969 Quickie:
1970 /* If we have a file handle, close it */
1971 if (FileHandle) ZwClose(FileHandle);
1972
1973 /* Check if we have the lock acquired */
1974 if (LockOwned)
1975 {
1976 /* Release the lock */
1977 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
1978 KeLeaveCriticalRegion();
1979 LockOwned = FALSE;
1980 }
1981
1982 /* Check if we had a prefix */
1983 if (NamePrefix) ExFreePool(PrefixName.Buffer);
1984
1985 /* Free the name buffer and return status */
1986 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
1987 return Status;
1988 }
1989
1990 /*
1991 * @implemented
1992 */
1993 PVOID
1994 NTAPI
1995 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
1996 {
1997 PVOID ProcAddress = NULL;
1998 ANSI_STRING AnsiRoutineName;
1999 NTSTATUS Status;
2000 PLIST_ENTRY NextEntry;
2001 PLDR_DATA_TABLE_ENTRY LdrEntry;
2002 BOOLEAN Found = FALSE;
2003 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
2004 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
2005 ULONG Modules = 0;
2006
2007 /* Convert routine to ansi name */
2008 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
2009 SystemRoutineName,
2010 TRUE);
2011 if (!NT_SUCCESS(Status)) return NULL;
2012
2013 /* Lock the list */
2014 KeEnterCriticalRegion();
2015 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);
2016
2017 /* Loop the loaded module list */
2018 NextEntry = PsLoadedModuleList.Flink;
2019 while (NextEntry != &PsLoadedModuleList)
2020 {
2021 /* Get the entry */
2022 LdrEntry = CONTAINING_RECORD(NextEntry,
2023 LDR_DATA_TABLE_ENTRY,
2024 InLoadOrderLinks);
2025
2026 /* Check if it's the kernel or HAL */
2027 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
2028 {
2029 /* Found it */
2030 Found = TRUE;
2031 Modules++;
2032 }
2033 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
2034 {
2035 /* Found it */
2036 Found = TRUE;
2037 Modules++;
2038 }
2039
2040 /* Check if we found a valid binary */
2041 if (Found)
2042 {
2043 /* Find the procedure name */
2044 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
2045 &AnsiRoutineName);
2046
2047 /* Break out if we found it or if we already tried both modules */
2048 if (ProcAddress) break;
2049 if (Modules == 2) break;
2050 }
2051
2052 /* Keep looping */
2053 NextEntry = NextEntry->Flink;
2054 }
2055
2056 /* Release the lock */
2057 ExReleaseResourceLite(&PsLoadedModuleResource);
2058 KeLeaveCriticalRegion();
2059
2060 /* Free the string and return */
2061 RtlFreeAnsiString(&AnsiRoutineName);
2062 return ProcAddress;
2063 }
2064