Merge trunk head (r43756)
[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 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,
765 BaseAddress,
766 (ULONG_PTR)ZwCurrentProcess());
767 RtlFreeAnsiString(&TempName);
768 }
769 }
770
771 /* FIXME: Free the driver */
772 //MmFreeSection(LdrEntry->DllBase);
773
774 /* Check if we're linked in */
775 if (LdrEntry->InLoadOrderLinks.Flink)
776 {
777 /* Remove us */
778 MiProcessLoaderEntry(LdrEntry, FALSE);
779 HadEntry = TRUE;
780 }
781
782 /* Dereference and clear the imports */
783 MiDereferenceImports(LdrEntry->LoadedImports);
784 MiClearImports(LdrEntry);
785
786 /* Check if the entry needs to go away */
787 if (HadEntry)
788 {
789 /* Check if it had a name */
790 if (LdrEntry->FullDllName.Buffer)
791 {
792 /* Free it */
793 ExFreePool(LdrEntry->FullDllName.Buffer);
794 }
795
796 /* Check if we had a section */
797 if (LdrEntry->SectionPointer)
798 {
799 /* Dereference it */
800 ObDereferenceObject(LdrEntry->SectionPointer);
801 }
802
803 /* Free the entry */
804 ExFreePool(LdrEntry);
805 }
806
807 /* Release the system lock and return */
808 Done:
809 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
810 KeLeaveCriticalRegion();
811 return STATUS_SUCCESS;
812 }
813
814 NTSTATUS
815 NTAPI
816 MiResolveImageReferences(IN PVOID ImageBase,
817 IN PUNICODE_STRING ImageFileDirectory,
818 IN PUNICODE_STRING NamePrefix OPTIONAL,
819 OUT PCHAR *MissingApi,
820 OUT PWCHAR *MissingDriver,
821 OUT PLOAD_IMPORTS *LoadImports)
822 {
823 PCHAR MissingApiBuffer = *MissingApi, ImportName;
824 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
825 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
826 PLOAD_IMPORTS LoadedImports, NewImports;
827 ULONG GdiLink, NormalLink, i;
828 BOOLEAN ReferenceNeeded, Loaded;
829 ANSI_STRING TempString;
830 UNICODE_STRING NameString, DllName;
831 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;
832 PVOID ImportBase, DllBase;
833 PLIST_ENTRY NextEntry;
834 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
835 NTSTATUS Status;
836 PIMAGE_THUNK_DATA OrigThunk, FirstThunk;
837 PAGED_CODE();
838 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
839 __FUNCTION__, ImageBase, ImageFileDirectory);
840
841 /* Assume no imports */
842 *LoadImports = (PVOID)-2;
843
844 /* Get the import descriptor */
845 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,
846 TRUE,
847 IMAGE_DIRECTORY_ENTRY_IMPORT,
848 &ImportSize);
849 if (!ImportDescriptor) return STATUS_SUCCESS;
850
851 /* Loop all imports to count them */
852 for (CurrentImport = ImportDescriptor;
853 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);
854 CurrentImport++)
855 {
856 /* One more */
857 ImportCount++;
858 }
859
860 /* Make sure we have non-zero imports */
861 if (ImportCount)
862 {
863 /* Calculate and allocate the list we'll need */
864 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
865 LoadedImports = ExAllocatePoolWithTag(PagedPool,
866 LoadedImportsSize,
867 TAG_LDR_WSTR);
868 if (LoadedImports)
869 {
870 /* Zero it */
871 RtlZeroMemory(LoadedImports, LoadedImportsSize);
872 }
873 }
874 else
875 {
876 /* No table */
877 LoadedImports = NULL;
878 }
879
880 /* Reset the import count and loop descriptors again */
881 ImportCount = GdiLink = NormalLink = 0;
882 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))
883 {
884 /* Get the name */
885 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);
886
887 /* Check if this is a GDI driver */
888 GdiLink = GdiLink |
889 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));
890
891 /* We can also allow dxapi */
892 NormalLink = NormalLink |
893 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&
894 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));
895
896 /* Check if this is a valid GDI driver */
897 if ((GdiLink) && (NormalLink))
898 {
899 /* It's not, it's importing stuff it shouldn't be! */
900 MiDereferenceImports(LoadedImports);
901 if (LoadedImports) ExFreePool(LoadedImports);
902 return STATUS_PROCEDURE_NOT_FOUND;
903 }
904
905 /* Check if this is a "core" import, which doesn't get referenced */
906 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||
907 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||
908 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))
909 {
910 /* Don't reference this */
911 ReferenceNeeded = FALSE;
912 }
913 else
914 {
915 /* Reference these modules */
916 ReferenceNeeded = TRUE;
917 }
918
919 /* Now setup a unicode string for the import */
920 RtlInitAnsiString(&TempString, ImportName);
921 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);
922 if (!NT_SUCCESS(Status))
923 {
924 /* Failed */
925 MiDereferenceImports(LoadedImports);
926 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
927 return Status;
928 }
929
930 /* We don't support name prefixes yet */
931 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");
932
933 /* Remember that we haven't loaded the import at this point */
934 CheckDllState:
935 Loaded = FALSE;
936 ImportBase = NULL;
937
938 /* Loop the driver list */
939 NextEntry = PsLoadedModuleList.Flink;
940 while (NextEntry != &PsLoadedModuleList)
941 {
942 /* Get the loader entry and compare the name */
943 LdrEntry = CONTAINING_RECORD(NextEntry,
944 LDR_DATA_TABLE_ENTRY,
945 InLoadOrderLinks);
946 if (RtlEqualUnicodeString(&NameString,
947 &LdrEntry->BaseDllName,
948 TRUE))
949 {
950 /* Get the base address */
951 ImportBase = LdrEntry->DllBase;
952
953 /* Check if we haven't loaded yet, and we need references */
954 if (!(Loaded) && (ReferenceNeeded))
955 {
956 /* Make sure we're not already loading */
957 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
958 {
959 /* Increase the load count */
960 LdrEntry->LoadCount++;
961 }
962 }
963
964 /* Done, break out */
965 break;
966 }
967
968 /* Go to the next entry */
969 NextEntry = NextEntry->Flink;
970 }
971
972 /* Check if we haven't loaded the import yet */
973 if (!ImportBase)
974 {
975 /* Setup the import DLL name */
976 DllName.MaximumLength = NameString.Length +
977 ImageFileDirectory->Length +
978 sizeof(UNICODE_NULL);
979 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
980 DllName.MaximumLength,
981 TAG_LDR_WSTR);
982 if (DllName.Buffer)
983 {
984 /* Setup the base length and copy it */
985 DllName.Length = ImageFileDirectory->Length;
986 RtlCopyMemory(DllName.Buffer,
987 ImageFileDirectory->Buffer,
988 ImageFileDirectory->Length);
989
990 /* Now add the import name and null-terminate it */
991 RtlAppendStringToString((PSTRING)&DllName,
992 (PSTRING)&NameString);
993 DllName.Buffer[(DllName.MaximumLength - 1) / 2] = UNICODE_NULL;
994
995 /* Load the image */
996 Status = MmLoadSystemImage(&DllName,
997 NamePrefix,
998 NULL,
999 0,
1000 (PVOID)&DllEntry,
1001 &DllBase);
1002 if (NT_SUCCESS(Status))
1003 {
1004 /* We can free the DLL Name */
1005 ExFreePool(DllName.Buffer);
1006 }
1007 else
1008 {
1009 /* Fill out the information for the error */
1010 *MissingDriver = DllName.Buffer;
1011 *(PULONG)MissingDriver |= 1;
1012 *MissingApi = NULL;
1013 }
1014 }
1015 else
1016 {
1017 /* We're out of resources */
1018 Status = STATUS_INSUFFICIENT_RESOURCES;
1019 }
1020
1021 /* Check if we're OK until now */
1022 if (NT_SUCCESS(Status))
1023 {
1024 /* We're now loaded */
1025 Loaded = TRUE;
1026
1027 /* Sanity check */
1028 ASSERT(DllBase = DllEntry->DllBase);
1029
1030 /* Call the initialization routines */
1031 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
1032 if (!NT_SUCCESS(Status))
1033 {
1034 /* We failed, unload the image */
1035 MmUnloadSystemImage(DllEntry);
1036 while (TRUE);
1037 Loaded = FALSE;
1038 }
1039 }
1040
1041 /* Check if we failed by here */
1042 if (!NT_SUCCESS(Status))
1043 {
1044 /* Cleanup and return */
1045 RtlFreeUnicodeString(&NameString);
1046 MiDereferenceImports(LoadedImports);
1047 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1048 return Status;
1049 }
1050
1051 /* Loop again to make sure that everything is OK */
1052 goto CheckDllState;
1053 }
1054
1055 /* Check if we're support to reference this import */
1056 if ((ReferenceNeeded) && (LoadedImports))
1057 {
1058 /* Make sure we're not already loading */
1059 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))
1060 {
1061 /* Add the entry */
1062 LoadedImports->Entry[LoadedImports->Count] = LdrEntry;
1063 LoadedImports->Count++;
1064 }
1065 }
1066
1067 /* Free the import name */
1068 RtlFreeUnicodeString(&NameString);
1069
1070 /* Set the missing driver name and get the export directory */
1071 *MissingDriver = LdrEntry->BaseDllName.Buffer;
1072 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,
1073 TRUE,
1074 IMAGE_DIRECTORY_ENTRY_EXPORT,
1075 &ExportSize);
1076 if (!ExportDirectory)
1077 {
1078 /* Cleanup and return */
1079 MiDereferenceImports(LoadedImports);
1080 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1081 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
1082 }
1083
1084 /* Make sure we have an IAT */
1085 if (ImportDescriptor->OriginalFirstThunk)
1086 {
1087 /* Get the first thunks */
1088 OrigThunk = (PVOID)((ULONG_PTR)ImageBase +
1089 ImportDescriptor->OriginalFirstThunk);
1090 FirstThunk = (PVOID)((ULONG_PTR)ImageBase +
1091 ImportDescriptor->FirstThunk);
1092
1093 /* Loop the IAT */
1094 while (OrigThunk->u1.AddressOfData)
1095 {
1096 /* Snap thunk */
1097 Status = MiSnapThunk(ImportBase,
1098 ImageBase,
1099 OrigThunk++,
1100 FirstThunk++,
1101 ExportDirectory,
1102 ExportSize,
1103 FALSE,
1104 MissingApi);
1105 if (!NT_SUCCESS(Status))
1106 {
1107 /* Cleanup and return */
1108 MiDereferenceImports(LoadedImports);
1109 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1110 return Status;
1111 }
1112
1113 /* Reset the buffer */
1114 *MissingApi = MissingApiBuffer;
1115 }
1116 }
1117
1118 /* Go to the next import */
1119 ImportDescriptor++;
1120 }
1121
1122 /* Check if we have an import list */
1123 if (LoadedImports)
1124 {
1125 /* Reset the count again, and loop entries*/
1126 ImportCount = 0;
1127 for (i = 0; i < LoadedImports->Count; i++)
1128 {
1129 if (LoadedImports->Entry[i])
1130 {
1131 /* Got an entry, OR it with 1 in case it's the single entry */
1132 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);
1133 ImportCount++;
1134 }
1135 }
1136
1137 /* Check if we had no imports */
1138 if (!ImportCount)
1139 {
1140 /* Free the list and set it to no imports */
1141 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1142 LoadedImports = (PVOID)-2;
1143 }
1144 else if (ImportCount == 1)
1145 {
1146 /* Just one entry, we can free the table and only use our entry */
1147 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1148 LoadedImports = (PLOAD_IMPORTS)ImportEntry;
1149 }
1150 else if (ImportCount != LoadedImports->Count)
1151 {
1152 /* Allocate a new list */
1153 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);
1154 NewImports = ExAllocatePoolWithTag(PagedPool,
1155 LoadedImportsSize,
1156 TAG_LDR_WSTR);
1157 if (NewImports)
1158 {
1159 /* Set count */
1160 NewImports->Count = 0;
1161
1162 /* Loop all the imports */
1163 for (i = 0; i < LoadedImports->Count; i++)
1164 {
1165 /* Make sure it's valid */
1166 if (LoadedImports->Entry[i])
1167 {
1168 /* Copy it */
1169 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i];
1170 NewImports->Count++;
1171 }
1172 }
1173
1174 /* Free the old copy */
1175 ExFreePoolWithTag(LoadedImports, TAG_LDR_WSTR);
1176 LoadedImports = NewImports;
1177 }
1178 }
1179
1180 /* Return the list */
1181 *LoadImports = LoadedImports;
1182 }
1183
1184 /* Return success */
1185 return STATUS_SUCCESS;
1186 }
1187
1188 VOID
1189 NTAPI
1190 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1191 {
1192 PLIST_ENTRY NextEntry;
1193 ULONG i = 0;
1194 PIMAGE_NT_HEADERS NtHeader;
1195 PLDR_DATA_TABLE_ENTRY LdrEntry;
1196 PIMAGE_FILE_HEADER FileHeader;
1197 BOOLEAN ValidRelocs;
1198 PIMAGE_DATA_DIRECTORY DataDirectory;
1199 PVOID DllBase, NewImageAddress;
1200 NTSTATUS Status;
1201
1202 /* Loop driver list */
1203 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;
1204 NextEntry != &LoaderBlock->LoadOrderListHead;
1205 NextEntry = NextEntry->Flink)
1206 {
1207 /* Get the loader entry and NT header */
1208 LdrEntry = CONTAINING_RECORD(NextEntry,
1209 LDR_DATA_TABLE_ENTRY,
1210 InLoadOrderLinks);
1211 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
1212
1213 /* Debug info */
1214 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",
1215 LdrEntry->DllBase,
1216 (ULONG_PTR)LdrEntry->DllBase+ LdrEntry->SizeOfImage,
1217 &LdrEntry->FullDllName);
1218
1219 /* Skip kernel and HAL */
1220 /* ROS HACK: Skip BOOTVID/KDCOM too */
1221 i++;
1222 if (i <= 4) continue;
1223
1224 /* Skip non-drivers */
1225 if (!NtHeader) continue;
1226
1227 /* Get the file header and make sure we can relocate */
1228 FileHeader = &NtHeader->FileHeader;
1229 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;
1230 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <
1231 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;
1232
1233 /* Everything made sense until now, check the relocation section too */
1234 DataDirectory = &NtHeader->OptionalHeader.
1235 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1236 if (!DataDirectory->VirtualAddress)
1237 {
1238 /* We don't really have relocations */
1239 ValidRelocs = FALSE;
1240 }
1241 else
1242 {
1243 /* Make sure the size is valid */
1244 if ((DataDirectory->VirtualAddress + DataDirectory->Size) >
1245 LdrEntry->SizeOfImage)
1246 {
1247 /* They're not, skip */
1248 continue;
1249 }
1250
1251 /* We have relocations */
1252 ValidRelocs = TRUE;
1253 }
1254
1255 /* Remember the original address */
1256 DllBase = LdrEntry->DllBase;
1257
1258 /* Allocate a virtual section for the module */
1259 NewImageAddress = MmAllocateSection(LdrEntry->SizeOfImage, NULL);
1260 if (!NewImageAddress)
1261 {
1262 /* Shouldn't happen */
1263 DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
1264 while (TRUE);
1265 }
1266
1267 /* Sanity check */
1268 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);
1269 ASSERT(ExpInitializationPhase == 0);
1270
1271 /* Now copy the entire driver over */
1272 RtlCopyMemory(NewImageAddress, DllBase, LdrEntry->SizeOfImage);
1273
1274 /* Sanity check */
1275 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);
1276
1277 /* Set the image base to the address where the loader put it */
1278 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1279 NtHeader = RtlImageNtHeader(NewImageAddress);
1280 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;
1281
1282 /* Check if we had relocations */
1283 if (ValidRelocs)
1284 {
1285 /* Relocate the image */
1286 Status = LdrRelocateImageWithBias(NewImageAddress,
1287 0,
1288 "SYSLDR",
1289 STATUS_SUCCESS,
1290 STATUS_CONFLICTING_ADDRESSES,
1291 STATUS_INVALID_IMAGE_FORMAT);
1292 if (!NT_SUCCESS(Status))
1293 {
1294 /* This shouldn't happen */
1295 DPRINT1("Relocations failed!\n");
1296 while (TRUE);
1297 }
1298 }
1299
1300 /* Update the loader entry */
1301 LdrEntry->DllBase = NewImageAddress;
1302
1303 /* Update the thunks */
1304 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);
1305 MiUpdateThunks(LoaderBlock,
1306 DllBase,
1307 NewImageAddress,
1308 LdrEntry->SizeOfImage);
1309
1310 /* Update the loader entry */
1311 LdrEntry->Flags |= 0x01000000;
1312 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +
1313 NtHeader->OptionalHeader.AddressOfEntryPoint);
1314 LdrEntry->SizeOfImage = LdrEntry->SizeOfImage;
1315
1316 /* Free the old copy */
1317 MiFreeBootDriverMemory(DllBase, LdrEntry->SizeOfImage);
1318 }
1319 }
1320
1321 BOOLEAN
1322 NTAPI
1323 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
1324 {
1325 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;
1326 PLIST_ENTRY ListHead, NextEntry;
1327 ULONG EntrySize;
1328
1329 /* Setup the loaded module list and lock */
1330 KeInitializeSpinLock(&PsLoadedModuleSpinLock);
1331 InitializeListHead(&PsLoadedModuleList);
1332
1333 /* Get loop variables and the kernel entry */
1334 ListHead = &LoaderBlock->LoadOrderListHead;
1335 NextEntry = ListHead->Flink;
1336 LdrEntry = CONTAINING_RECORD(NextEntry,
1337 LDR_DATA_TABLE_ENTRY,
1338 InLoadOrderLinks);
1339 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
1340
1341 /* Loop the loader block */
1342 while (NextEntry != ListHead)
1343 {
1344 /* Get the loader entry */
1345 LdrEntry = CONTAINING_RECORD(NextEntry,
1346 LDR_DATA_TABLE_ENTRY,
1347 InLoadOrderLinks);
1348
1349 /* FIXME: ROS HACK. Make sure this is a driver */
1350 if (!RtlImageNtHeader(LdrEntry->DllBase))
1351 {
1352 /* Skip this entry */
1353 NextEntry= NextEntry->Flink;
1354 continue;
1355 }
1356
1357 /* Calculate the size we'll need and allocate a copy */
1358 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1359 LdrEntry->BaseDllName.MaximumLength +
1360 sizeof(UNICODE_NULL);
1361 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);
1362 if (!NewEntry) return FALSE;
1363
1364 /* Copy the entry over */
1365 *NewEntry = *LdrEntry;
1366
1367 /* Allocate the name */
1368 NewEntry->FullDllName.Buffer =
1369 ExAllocatePoolWithTag(PagedPool,
1370 LdrEntry->FullDllName.MaximumLength +
1371 sizeof(UNICODE_NULL),
1372 TAG_LDR_WSTR);
1373 if (!NewEntry->FullDllName.Buffer) return FALSE;
1374
1375 /* Set the base name */
1376 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);
1377
1378 /* Copy the full and base name */
1379 RtlCopyMemory(NewEntry->FullDllName.Buffer,
1380 LdrEntry->FullDllName.Buffer,
1381 LdrEntry->FullDllName.MaximumLength);
1382 RtlCopyMemory(NewEntry->BaseDllName.Buffer,
1383 LdrEntry->BaseDllName.Buffer,
1384 LdrEntry->BaseDllName.MaximumLength);
1385
1386 /* Null-terminate the base name */
1387 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /
1388 sizeof(WCHAR)] = UNICODE_NULL;
1389
1390 /* Insert the entry into the list */
1391 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);
1392 NextEntry = NextEntry->Flink;
1393 }
1394
1395 /* Build the import lists for the boot drivers */
1396 //MiBuildImportsForBootDrivers();
1397
1398 /* We're done */
1399 return TRUE;
1400 }
1401
1402 BOOLEAN
1403 NTAPI
1404 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)
1405 {
1406 PIMAGE_NT_HEADERS NtHeader;
1407 PAGED_CODE();
1408
1409 /* Get NT Headers */
1410 NtHeader = RtlImageNtHeader(BaseAddress);
1411 if (NtHeader)
1412 {
1413 /* Check if this image is only safe for UP while we have 2+ CPUs */
1414 if ((KeNumberProcessors > 1) &&
1415 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))
1416 {
1417 /* Fail */
1418 return FALSE;
1419 }
1420 }
1421
1422 /* Otherwise, it's safe */
1423 return TRUE;
1424 }
1425
1426 NTSTATUS
1427 NTAPI
1428 MmCheckSystemImage(IN HANDLE ImageHandle,
1429 IN BOOLEAN PurgeSection)
1430 {
1431 NTSTATUS Status;
1432 HANDLE SectionHandle;
1433 PVOID ViewBase = NULL;
1434 SIZE_T ViewSize = 0;
1435 IO_STATUS_BLOCK IoStatusBlock;
1436 FILE_STANDARD_INFORMATION FileStandardInfo;
1437 KAPC_STATE ApcState;
1438 PAGED_CODE();
1439
1440 /* Create a section for the DLL */
1441 Status = ZwCreateSection(&SectionHandle,
1442 SECTION_MAP_EXECUTE,
1443 NULL,
1444 NULL,
1445 PAGE_EXECUTE,
1446 SEC_COMMIT,
1447 ImageHandle);
1448 if (!NT_SUCCESS(Status)) return Status;
1449
1450 /* Make sure we're in the system process */
1451 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
1452
1453 /* Map it */
1454 Status = ZwMapViewOfSection(SectionHandle,
1455 NtCurrentProcess(),
1456 &ViewBase,
1457 0,
1458 0,
1459 NULL,
1460 &ViewSize,
1461 ViewShare,
1462 0,
1463 PAGE_EXECUTE);
1464 if (!NT_SUCCESS(Status))
1465 {
1466 /* We failed, close the handle and return */
1467 KeUnstackDetachProcess(&ApcState);
1468 ZwClose(SectionHandle);
1469 return Status;
1470 }
1471
1472 /* Now query image information */
1473 Status = ZwQueryInformationFile(ImageHandle,
1474 &IoStatusBlock,
1475 &FileStandardInfo,
1476 sizeof(FileStandardInfo),
1477 FileStandardInformation);
1478 if ( NT_SUCCESS(Status) )
1479 {
1480 /* First, verify the checksum */
1481 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,
1482 FileStandardInfo.
1483 EndOfFile.LowPart,
1484 FileStandardInfo.
1485 EndOfFile.LowPart))
1486 {
1487 /* Set checksum failure */
1488 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
1489 }
1490
1491 /* Check that it's a valid SMP image if we have more then one CPU */
1492 if (!MmVerifyImageIsOkForMpUse(ViewBase))
1493 {
1494 /* Otherwise it's not the right image */
1495 Status = STATUS_IMAGE_MP_UP_MISMATCH;
1496 }
1497 }
1498
1499 /* Unmap the section, close the handle, and return status */
1500 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1501 KeUnstackDetachProcess(&ApcState);
1502 ZwClose(SectionHandle);
1503 return Status;
1504 }
1505
1506 NTSTATUS
1507 NTAPI
1508 MmLoadSystemImage(IN PUNICODE_STRING FileName,
1509 IN PUNICODE_STRING NamePrefix OPTIONAL,
1510 IN PUNICODE_STRING LoadedName OPTIONAL,
1511 IN ULONG Flags,
1512 OUT PVOID *ModuleObject,
1513 OUT PVOID *ImageBaseAddress)
1514 {
1515 PVOID ModuleLoadBase = NULL;
1516 NTSTATUS Status;
1517 HANDLE FileHandle = NULL;
1518 OBJECT_ATTRIBUTES ObjectAttributes;
1519 IO_STATUS_BLOCK IoStatusBlock;
1520 PIMAGE_NT_HEADERS NtHeader;
1521 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp;
1522 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
1523 ULONG EntrySize, DriverSize;
1524 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
1525 PCHAR MissingApiName, Buffer;
1526 PWCHAR MissingDriverName;
1527 HANDLE SectionHandle;
1528 ACCESS_MASK DesiredAccess;
1529 PVOID Section = NULL;
1530 BOOLEAN LockOwned = FALSE;
1531 PLIST_ENTRY NextEntry;
1532 IMAGE_INFO ImageInfo;
1533 STRING AnsiTemp;
1534 PAGED_CODE();
1535
1536 /* Detect session-load */
1537 if (Flags)
1538 {
1539 /* Sanity checks */
1540 ASSERT(NamePrefix == NULL);
1541 ASSERT(LoadedName == NULL);
1542
1543 /* Make sure the process is in session too */
1544 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;
1545 }
1546
1547 if (ModuleObject) *ModuleObject = NULL;
1548 if (ImageBaseAddress) *ImageBaseAddress = NULL;
1549
1550 /* Allocate a buffer we'll use for names */
1551 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
1552 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1553
1554 /* Check for a separator */
1555 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
1556 {
1557 PWCHAR p;
1558 ULONG BaseLength;
1559
1560 /* Loop the path until we get to the base name */
1561 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
1562 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
1563
1564 /* Get the length */
1565 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
1566 BaseLength *= sizeof(WCHAR);
1567
1568 /* Setup the string */
1569 BaseName.Length = (USHORT)BaseLength;
1570 BaseName.Buffer = p;
1571 }
1572 else
1573 {
1574 /* Otherwise, we already have a base name */
1575 BaseName.Length = FileName->Length;
1576 BaseName.Buffer = FileName->Buffer;
1577 }
1578
1579 /* Setup the maximum length */
1580 BaseName.MaximumLength = BaseName.Length;
1581
1582 /* Now compute the base directory */
1583 BaseDirectory = *FileName;
1584 BaseDirectory.Length -= BaseName.Length;
1585 BaseDirectory.MaximumLength = BaseDirectory.Length;
1586
1587 /* And the prefix, which for now is just the name itself */
1588 PrefixName = *FileName;
1589
1590 /* Check if we have a prefix */
1591 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");
1592
1593 /* Check if we already have a name, use it instead */
1594 if (LoadedName) BaseName = *LoadedName;
1595
1596 /* Acquire the load lock */
1597 LoaderScan:
1598 ASSERT(LockOwned == FALSE);
1599 LockOwned = TRUE;
1600 KeEnterCriticalRegion();
1601 KeWaitForSingleObject(&MmSystemLoadLock,
1602 WrVirtualMemory,
1603 KernelMode,
1604 FALSE,
1605 NULL);
1606
1607 /* Scan the module list */
1608 NextEntry = PsLoadedModuleList.Flink;
1609 while (NextEntry != &PsLoadedModuleList)
1610 {
1611 /* Get the entry and compare the names */
1612 LdrEntry = CONTAINING_RECORD(NextEntry,
1613 LDR_DATA_TABLE_ENTRY,
1614 InLoadOrderLinks);
1615 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))
1616 {
1617 /* Found it, break out */
1618 break;
1619 }
1620
1621 /* Keep scanning */
1622 NextEntry = NextEntry->Flink;
1623 }
1624
1625 /* Check if we found the image */
1626 if (NextEntry != &PsLoadedModuleList)
1627 {
1628 /* Check if we had already mapped a section */
1629 if (Section)
1630 {
1631 /* Dereference and clear */
1632 ObDereferenceObject(Section);
1633 Section = NULL;
1634 }
1635
1636 /* Check if this was supposed to be a session load */
1637 if (!Flags)
1638 {
1639 /* It wasn't, so just return the data */
1640 if (ModuleObject) *ModuleObject = LdrEntry;
1641 if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;
1642 Status = STATUS_IMAGE_ALREADY_LOADED;
1643 }
1644 else
1645 {
1646 /* We don't support session loading yet */
1647 DPRINT1("Unsupported Session-Load!\n");
1648 while (TRUE);
1649 }
1650
1651 /* Do cleanup */
1652 goto Quickie;
1653 }
1654 else if (!Section)
1655 {
1656 /* It wasn't loaded, and we didn't have a previous attempt */
1657 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
1658 KeLeaveCriticalRegion();
1659 LockOwned = FALSE;
1660
1661 /* Check if KD is enabled */
1662 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))
1663 {
1664 /* FIXME: Attempt to get image from KD */
1665 }
1666
1667 /* We don't have a valid entry */
1668 LdrEntry = NULL;
1669
1670 /* Setup image attributes */
1671 InitializeObjectAttributes(&ObjectAttributes,
1672 FileName,
1673 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1674 NULL,
1675 NULL);
1676
1677 /* Open the image */
1678 Status = ZwOpenFile(&FileHandle,
1679 FILE_EXECUTE,
1680 &ObjectAttributes,
1681 &IoStatusBlock,
1682 FILE_SHARE_READ | FILE_SHARE_DELETE,
1683 0);
1684 if (!NT_SUCCESS(Status)) goto Quickie;
1685
1686 /* Validate it */
1687 Status = MmCheckSystemImage(FileHandle, FALSE);
1688 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||
1689 (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||
1690 (Status == STATUS_INVALID_IMAGE_FORMAT))
1691 {
1692 /* Fail loading */
1693 goto Quickie;
1694 }
1695
1696 /* Check if this is a session-load */
1697 if (Flags)
1698 {
1699 /* Then we only need read and execute */
1700 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;
1701 }
1702 else
1703 {
1704 /* Otherwise, we can allow write access */
1705 DesiredAccess = SECTION_ALL_ACCESS;
1706 }
1707
1708 /* Initialize the attributes for the section */
1709 InitializeObjectAttributes(&ObjectAttributes,
1710 NULL,
1711 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1712 NULL,
1713 NULL);
1714
1715 /* Create the section */
1716 Status = ZwCreateSection(&SectionHandle,
1717 DesiredAccess,
1718 &ObjectAttributes,
1719 NULL,
1720 PAGE_EXECUTE,
1721 SEC_IMAGE,
1722 FileHandle);
1723 if (!NT_SUCCESS(Status)) goto Quickie;
1724
1725 /* Now get the section pointer */
1726 Status = ObReferenceObjectByHandle(SectionHandle,
1727 SECTION_MAP_EXECUTE,
1728 MmSectionObjectType,
1729 KernelMode,
1730 &Section,
1731 NULL);
1732 ZwClose(SectionHandle);
1733 if (!NT_SUCCESS(Status)) goto Quickie;
1734
1735 /* Check if this was supposed to be a session-load */
1736 if (Flags)
1737 {
1738 /* We don't support session loading yet */
1739 DPRINT1("Unsupported Session-Load!\n");
1740 while (TRUE);
1741 }
1742
1743 /* Check the loader list again, we should end up in the path below */
1744 goto LoaderScan;
1745 }
1746 else
1747 {
1748 /* We don't have a valid entry */
1749 LdrEntry = NULL;
1750 }
1751
1752 /* Load the image */
1753 Status = MiLoadImageSection(&Section,
1754 &ModuleLoadBase,
1755 FileName,
1756 FALSE,
1757 NULL);
1758 ASSERT(Status != STATUS_ALREADY_COMMITTED);
1759
1760 /* Get the size of the driver */
1761 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
1762
1763 /* Make sure we're not being loaded into session space */
1764 if (!Flags)
1765 {
1766 /* Check for success */
1767 if (NT_SUCCESS(Status))
1768 {
1769 /* FIXME: Support large pages for drivers */
1770 }
1771
1772 /* Dereference the section */
1773 ObDereferenceObject(Section);
1774 Section = NULL;
1775 }
1776
1777 /* Get the NT Header */
1778 NtHeader = RtlImageNtHeader(ModuleLoadBase);
1779
1780 /* Relocate the driver */
1781 Status = LdrRelocateImageWithBias(ModuleLoadBase,
1782 0,
1783 "SYSLDR",
1784 STATUS_SUCCESS,
1785 STATUS_CONFLICTING_ADDRESSES,
1786 STATUS_INVALID_IMAGE_FORMAT);
1787 if (!NT_SUCCESS(Status)) goto Quickie;
1788
1789 /* Calculate the size we'll need for the entry and allocate it */
1790 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
1791 BaseName.Length +
1792 sizeof(UNICODE_NULL);
1793
1794 /* Allocate the entry */
1795 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);
1796 if (!LdrEntry)
1797 {
1798 /* Fail */
1799 Status = STATUS_INSUFFICIENT_RESOURCES;
1800 goto Quickie;
1801 }
1802
1803 /* Setup the entry */
1804 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;
1805 LdrEntry->LoadCount = 1;
1806 LdrEntry->LoadedImports = LoadedImports;
1807 LdrEntry->PatchInformation = NULL;
1808
1809 /* Check the version */
1810 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
1811 (NtHeader->OptionalHeader.MajorImageVersion >= 5))
1812 {
1813 /* Mark this image as a native image */
1814 LdrEntry->Flags |= 0x80000000;
1815 }
1816
1817 /* Setup the rest of the entry */
1818 LdrEntry->DllBase = ModuleLoadBase;
1819 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +
1820 NtHeader->OptionalHeader.AddressOfEntryPoint);
1821 LdrEntry->SizeOfImage = DriverSize;
1822 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;
1823 LdrEntry->SectionPointer = Section;
1824
1825 /* Now write the DLL name */
1826 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);
1827 LdrEntry->BaseDllName.Length = BaseName.Length;
1828 LdrEntry->BaseDllName.MaximumLength = BaseName.Length;
1829
1830 /* Copy and null-terminate it */
1831 RtlCopyMemory(LdrEntry->BaseDllName.Buffer,
1832 BaseName.Buffer,
1833 BaseName.Length);
1834 LdrEntry->BaseDllName.Buffer[BaseName.Length / 2] = UNICODE_NULL;
1835
1836 /* Now allocate the full name */
1837 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,
1838 PrefixName.Length +
1839 sizeof(UNICODE_NULL),
1840 TAG_LDR_WSTR);
1841 if (!LdrEntry->FullDllName.Buffer)
1842 {
1843 /* Don't fail, just set it to zero */
1844 LdrEntry->FullDllName.Length = 0;
1845 LdrEntry->FullDllName.MaximumLength = 0;
1846 }
1847 else
1848 {
1849 /* Set it up */
1850 LdrEntry->FullDllName.Length = PrefixName.Length;
1851 LdrEntry->FullDllName.MaximumLength = PrefixName.Length;
1852
1853 /* Copy and null-terminate */
1854 RtlCopyMemory(LdrEntry->FullDllName.Buffer,
1855 PrefixName.Buffer,
1856 PrefixName.Length);
1857 LdrEntry->FullDllName.Buffer[PrefixName.Length / 2] = UNICODE_NULL;
1858 }
1859
1860 /* Add the entry */
1861 MiProcessLoaderEntry(LdrEntry, TRUE);
1862
1863 /* Resolve imports */
1864 MissingApiName = Buffer;
1865 Status = MiResolveImageReferences(ModuleLoadBase,
1866 &BaseDirectory,
1867 NULL,
1868 &MissingApiName,
1869 &MissingDriverName,
1870 &LoadedImports);
1871 if (!NT_SUCCESS(Status))
1872 {
1873 /* Fail */
1874 MiProcessLoaderEntry(LdrEntry, FALSE);
1875
1876 /* Check if we need to free the name */
1877 if (LdrEntry->FullDllName.Buffer)
1878 {
1879 /* Free it */
1880 ExFreePool(LdrEntry->FullDllName.Buffer);
1881 }
1882
1883 /* Free the entry itself */
1884 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT);
1885 LdrEntry = NULL;
1886 goto Quickie;
1887 }
1888
1889 /* Update the loader entry */
1890 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED |
1891 LDRP_ENTRY_PROCESSED |
1892 LDRP_MM_LOADED);
1893 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
1894 LdrEntry->LoadedImports = LoadedImports;
1895
1896 /* FIXME: Apply driver verifier */
1897
1898 /* FIXME: Write-protect the system image */
1899
1900 /* Check if notifications are enabled */
1901 if (PsImageNotifyEnabled)
1902 {
1903 /* Fill out the notification data */
1904 ImageInfo.Properties = 0;
1905 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
1906 ImageInfo.SystemModeImage = TRUE;
1907 ImageInfo.ImageSize = LdrEntry->SizeOfImage;
1908 ImageInfo.ImageBase = LdrEntry->DllBase;
1909 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0;
1910
1911 /* Send the notification */
1912 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo);
1913 }
1914
1915 /* Check if there's symbols */
1916 #ifdef KDBG
1917 /* If KDBG is defined, then we always have symbols */
1918 if (TRUE)
1919 #else
1920 if (MiCacheImageSymbols(LdrEntry->DllBase))
1921 #endif
1922 {
1923 /* Check if the system root is present */
1924 if ((PrefixName.Length > (11 * sizeof(WCHAR))) &&
1925 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11)))
1926 {
1927 /* Add the system root */
1928 UnicodeTemp = PrefixName;
1929 UnicodeTemp.Buffer += 11;
1930 UnicodeTemp.Length -= (11 * sizeof(WCHAR));
1931 sprintf_nt(Buffer,
1932 "%ws%wZ",
1933 &SharedUserData->NtSystemRoot[2],
1934 &UnicodeTemp);
1935 }
1936 else
1937 {
1938 /* Build the name */
1939 sprintf_nt(Buffer, "%wZ", &BaseName);
1940 }
1941
1942 /* Setup the ansi string */
1943 RtlInitString(&AnsiTemp, Buffer);
1944
1945 /* Notify the debugger */
1946 DbgLoadImageSymbols(&AnsiTemp,
1947 LdrEntry->DllBase,
1948 (ULONG_PTR)ZwCurrentProcess());
1949 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
1950 }
1951
1952 /* FIXME: Page the driver */
1953 ASSERT(Section == NULL);
1954
1955 /* Return pointers */
1956 if (ModuleObject) *ModuleObject = LdrEntry;
1957 if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;
1958
1959 Quickie:
1960 /* If we have a file handle, close it */
1961 if (FileHandle) ZwClose(FileHandle);
1962
1963 /* Check if we have the lock acquired */
1964 if (LockOwned)
1965 {
1966 /* Release the lock */
1967 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
1968 KeLeaveCriticalRegion();
1969 LockOwned = FALSE;
1970 }
1971
1972 /* Check if we had a prefix */
1973 if (NamePrefix) ExFreePool(PrefixName.Buffer);
1974
1975 /* Free the name buffer and return status */
1976 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
1977 return Status;
1978 }
1979
1980 /*
1981 * @implemented
1982 */
1983 PVOID
1984 NTAPI
1985 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)
1986 {
1987 PVOID ProcAddress = NULL;
1988 ANSI_STRING AnsiRoutineName;
1989 NTSTATUS Status;
1990 PLIST_ENTRY NextEntry;
1991 extern LIST_ENTRY PsLoadedModuleList;
1992 PLDR_DATA_TABLE_ENTRY LdrEntry;
1993 BOOLEAN Found = FALSE;
1994 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
1995 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
1996 ULONG Modules = 0;
1997
1998 /* Convert routine to ansi name */
1999 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,
2000 SystemRoutineName,
2001 TRUE);
2002 if (!NT_SUCCESS(Status)) return NULL;
2003
2004 /* Lock the list */
2005 KeEnterCriticalRegion();
2006
2007 /* Loop the loaded module list */
2008 NextEntry = PsLoadedModuleList.Flink;
2009 while (NextEntry != &PsLoadedModuleList)
2010 {
2011 /* Get the entry */
2012 LdrEntry = CONTAINING_RECORD(NextEntry,
2013 LDR_DATA_TABLE_ENTRY,
2014 InLoadOrderLinks);
2015
2016 /* Check if it's the kernel or HAL */
2017 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
2018 {
2019 /* Found it */
2020 Found = TRUE;
2021 Modules++;
2022 }
2023 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
2024 {
2025 /* Found it */
2026 Found = TRUE;
2027 Modules++;
2028 }
2029
2030 /* Check if we found a valid binary */
2031 if (Found)
2032 {
2033 /* Find the procedure name */
2034 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,
2035 &AnsiRoutineName);
2036
2037 /* Break out if we found it or if we already tried both modules */
2038 if (ProcAddress) break;
2039 if (Modules == 2) break;
2040 }
2041
2042 /* Keep looping */
2043 NextEntry = NextEntry->Flink;
2044 }
2045
2046 /* Release the lock */
2047 KeLeaveCriticalRegion();
2048
2049 /* Free the string and return */
2050 RtlFreeAnsiString(&AnsiRoutineName);
2051 return ProcAddress;
2052 }
2053