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