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