Implemented dll preloading and mapping.
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.65 2003/05/12 19:47:53 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/utils.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 */
10
11 /*
12 * TODO:
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
15 * - any more ??
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
22 #include <windows.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27
28
29 #ifdef DBG_NTDLL_LDR_UTILS
30 #define NDEBUG
31 #endif
32 #include <ntdll/ntdll.h>
33
34 /* GLOBALS *******************************************************************/
35
36 static HANDLE LdrpKnownDllsDirHandle = NULL;
37 static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
38
39
40 /* PROTOTYPES ****************************************************************/
41
42 static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_MODULE *Module);
43 static PVOID LdrFixupForward(PCHAR ForwardName);
44 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
45
46
47 /* FUNCTIONS *****************************************************************/
48
49
50 #ifdef DBG
51
52 VOID
53 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
54 {
55 NtSystemDebugControl(
56 DebugDbgLoadSymbols,
57 (PVOID)LdrModule,
58 0,
59 NULL,
60 0,
61 NULL);
62 }
63
64 #endif /* DBG */
65
66
67 VOID
68 LdrpInitLoader(VOID)
69 {
70 OBJECT_ATTRIBUTES ObjectAttributes;
71 UNICODE_STRING LinkTarget;
72 UNICODE_STRING Name;
73 HANDLE LinkHandle;
74 ULONG Length;
75 NTSTATUS Status;
76
77 DPRINT("LdrpInitLoader() called\n");
78
79 /* Get handle to the 'KnownDlls' directory */
80 RtlInitUnicodeString(&Name,
81 L"\\KnownDlls");
82 InitializeObjectAttributes(&ObjectAttributes,
83 &Name,
84 OBJ_CASE_INSENSITIVE,
85 NULL,
86 NULL);
87 Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
88 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
89 &ObjectAttributes);
90 if (!NT_SUCCESS(Status))
91 {
92 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
93 LdrpKnownDllsDirHandle = NULL;
94 return;
95 }
96
97 /* Allocate target name string */
98 LinkTarget.Length = 0;
99 LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
100 LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
101 0,
102 MAX_PATH * sizeof(WCHAR));
103 if (LinkTarget.Buffer == NULL)
104 {
105 NtClose(LdrpKnownDllsDirHandle);
106 LdrpKnownDllsDirHandle = NULL;
107 return;
108 }
109
110 RtlInitUnicodeString(&Name,
111 L"KnownDllPath");
112 InitializeObjectAttributes(&ObjectAttributes,
113 &Name,
114 OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
115 LdrpKnownDllsDirHandle,
116 NULL);
117 Status = NtOpenSymbolicLinkObject(&LinkHandle,
118 SYMBOLIC_LINK_ALL_ACCESS,
119 &ObjectAttributes);
120 if (!NT_SUCCESS(Status))
121 {
122 RtlFreeUnicodeString(&LinkTarget);
123 NtClose(LdrpKnownDllsDirHandle);
124 LdrpKnownDllsDirHandle = NULL;
125 return;
126 }
127
128 Status = NtQuerySymbolicLinkObject(LinkHandle,
129 &LinkTarget,
130 &Length);
131 NtClose(LinkHandle);
132 if (!NT_SUCCESS(Status))
133 {
134 RtlFreeUnicodeString(&LinkTarget);
135 NtClose(LdrpKnownDllsDirHandle);
136 LdrpKnownDllsDirHandle = NULL;
137 }
138
139 RtlCreateUnicodeString(&LdrpKnownDllPath,
140 LinkTarget.Buffer);
141
142 RtlFreeUnicodeString(&LinkTarget);
143
144 DPRINT("LdrpInitLoader() done\n");
145 }
146
147
148 /***************************************************************************
149 * NAME LOCAL
150 * LdrAdjustDllName
151 *
152 * DESCRIPTION
153 * Adjusts the name of a dll to a fully qualified name.
154 *
155 * ARGUMENTS
156 * FullDllName: Pointer to caller supplied storage for the fully
157 * qualified dll name.
158 * DllName: Pointer to the dll name.
159 * BaseName: TRUE: Only the file name is passed to FullDllName
160 * FALSE: The full path is preserved in FullDllName
161 *
162 * RETURN VALUE
163 * None
164 *
165 * REVISIONS
166 *
167 * NOTE
168 * A given path is not affected by the adjustment, but the file
169 * name only:
170 * ntdll --> ntdll.dll
171 * ntdll. --> ntdll
172 * ntdll.xyz --> ntdll.xyz
173 */
174
175 static VOID
176 LdrAdjustDllName (PUNICODE_STRING FullDllName,
177 PUNICODE_STRING DllName,
178 BOOLEAN BaseName)
179 {
180 WCHAR Buffer[MAX_PATH];
181 ULONG Length;
182 PWCHAR Extension;
183 PWCHAR Pointer;
184
185 Length = DllName->Length / sizeof(WCHAR);
186
187 if (BaseName == TRUE)
188 {
189 /* get the base dll name */
190 Pointer = DllName->Buffer + Length;
191 Extension = Pointer;
192
193 do
194 {
195 --Pointer;
196 }
197 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
198
199 Pointer++;
200 Length = Extension - Pointer;
201 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
202 Buffer[Length] = L'\0';
203 }
204 else
205 {
206 /* get the full dll name */
207 memmove (Buffer, DllName->Buffer, DllName->Length);
208 Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
209 }
210
211 /* Build the DLL's absolute name */
212 Extension = wcsrchr (Buffer, L'.');
213 if ((Extension != NULL) && (*Extension == L'.'))
214 {
215 /* with extension - remove dot if it's the last character */
216 if (Buffer[Length - 1] == L'.')
217 Length--;
218 Buffer[Length] = 0;
219 }
220 else
221 {
222 /* name without extension - assume that it is .dll */
223 memmove (Buffer + Length, L".dll", 10);
224 }
225
226 RtlCreateUnicodeString(FullDllName, Buffer);
227 }
228
229 PLDR_MODULE
230 LdrAddModuleEntry(PVOID ImageBase,
231 PIMAGE_NT_HEADERS NTHeaders,
232 PWSTR FullDosName)
233 {
234 PLDR_MODULE Module;
235 Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE));
236 assert(Module);
237 Module->BaseAddress = (PVOID)ImageBase;
238 Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
239 if (Module->EntryPoint != 0)
240 Module->EntryPoint += (ULONG)Module->BaseAddress;
241 Module->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
242 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
243 {
244 /* loading while app is running */
245 Module->LoadCount = 1;
246 } else {
247 /*
248 * loading while app is initializing
249 * dll must not be unloaded
250 */
251 Module->LoadCount = -1;
252 }
253
254 Module->TlsIndex = 0;
255 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
256 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
257
258 RtlCreateUnicodeString (&Module->FullDllName,
259 FullDosName);
260 RtlCreateUnicodeString (&Module->BaseDllName,
261 wcsrchr(FullDosName, L'\\') + 1);
262 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
263
264 /* FIXME: aquire loader lock */
265 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
266 &Module->InLoadOrderModuleList);
267 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
268 &Module->InInitializationOrderModuleList);
269 /* FIXME: release loader lock */
270
271 return(Module);
272 }
273
274
275 static NTSTATUS
276 LdrpMapKnownDll(IN PUNICODE_STRING DllName,
277 OUT PUNICODE_STRING FullDosName,
278 OUT PHANDLE SectionHandle)
279 {
280 OBJECT_ATTRIBUTES ObjectAttributes;
281 UNICODE_STRING ObjectDirName;
282 NTSTATUS Status;
283
284 DPRINT("LdrpMapKnownDll() called\n");
285
286 if (LdrpKnownDllsDirHandle == NULL)
287 {
288 DPRINT("Invalid 'KnownDlls' directory\n");
289 return STATUS_UNSUCCESSFUL;
290 }
291
292 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath);
293
294 InitializeObjectAttributes(&ObjectAttributes,
295 DllName,
296 OBJ_CASE_INSENSITIVE,
297 LdrpKnownDllsDirHandle,
298 NULL);
299 Status = NtOpenSection(SectionHandle,
300 SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
301 &ObjectAttributes);
302 if (!NT_SUCCESS(Status))
303 {
304 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName, Status);
305 return Status;
306 }
307
308 FullDosName->Length = LdrpKnownDllPath.Length + DllName->Length + sizeof(WCHAR);
309 FullDosName->MaximumLength = FullDosName->Length + sizeof(WCHAR);
310 FullDosName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
311 0,
312 FullDosName->MaximumLength);
313 if (FullDosName->Buffer == NULL)
314 {
315 FullDosName->Length = 0;
316 FullDosName->MaximumLength = 0;
317 return STATUS_SUCCESS;
318 }
319
320 wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer);
321 wcscat(FullDosName->Buffer, L"\\");
322 wcscat(FullDosName->Buffer, DllName->Buffer);
323
324 DPRINT("FullDosName '%wZ'\n", FullDosName);
325
326 DPRINT("LdrpMapKnownDll() done\n");
327
328 return STATUS_SUCCESS;
329 }
330
331
332 static NTSTATUS
333 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
334 IN PUNICODE_STRING DllName,
335 OUT PUNICODE_STRING FullDosName,
336 OUT PHANDLE SectionHandle)
337 {
338 WCHAR SearchPathBuffer[MAX_PATH];
339 WCHAR DosName[MAX_PATH];
340 UNICODE_STRING FullNtFileName;
341 OBJECT_ATTRIBUTES FileObjectAttributes;
342 HANDLE FileHandle;
343 char BlockBuffer [1024];
344 PIMAGE_DOS_HEADER DosHeader;
345 PIMAGE_NT_HEADERS NTHeaders;
346 PVOID ImageBase;
347 ULONG ImageSize;
348 NTSTATUS Status;
349
350 DPRINT("LdrpMapDllImageFile() called\n");
351
352 if (SearchPath == NULL)
353 {
354 SearchPath = SearchPathBuffer;
355 wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
356 wcscat (SearchPathBuffer, L"\\system32;");
357 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
358 wcscat (SearchPathBuffer, L";.");
359 }
360
361 DPRINT("SearchPath %S\n", SearchPath);
362
363 if (RtlDosSearchPath_U (SearchPath,
364 DllName->Buffer,
365 NULL,
366 MAX_PATH,
367 DosName,
368 NULL) == 0)
369 return STATUS_DLL_NOT_FOUND;
370
371 DPRINT("DosName %S\n", DosName);
372
373 if (!RtlDosPathNameToNtPathName_U (DosName,
374 &FullNtFileName,
375 NULL,
376 NULL))
377 return STATUS_DLL_NOT_FOUND;
378
379 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
380
381 InitializeObjectAttributes(&FileObjectAttributes,
382 &FullNtFileName,
383 0,
384 NULL,
385 NULL);
386
387 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
388
389 Status = ZwOpenFile(&FileHandle,
390 FILE_ALL_ACCESS,
391 &FileObjectAttributes,
392 NULL,
393 0,
394 0);
395 if (!NT_SUCCESS(Status))
396 {
397 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
398 &FullNtFileName, Status);
399 RtlFreeUnicodeString (&FullNtFileName);
400 return Status;
401 }
402 RtlFreeUnicodeString (&FullNtFileName);
403
404 Status = ZwReadFile(FileHandle,
405 0,
406 0,
407 0,
408 0,
409 BlockBuffer,
410 sizeof(BlockBuffer),
411 0,
412 0);
413 if (!NT_SUCCESS(Status))
414 {
415 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
416 ZwClose(FileHandle);
417 return Status;
418 }
419 /*
420 * Overlay DOS and NT headers structures to the
421 * buffer with DLL's header raw data.
422 */
423 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
424 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
425 /*
426 * Check it is a PE image file.
427 */
428 if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
429 || (DosHeader->e_lfanew == 0L)
430 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
431 {
432 DPRINT("NTDLL format invalid\n");
433 ZwClose(FileHandle);
434
435 return STATUS_UNSUCCESSFUL;
436 }
437
438 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
439 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
440
441 DPRINT("ImageBase 0x%08x\n", ImageBase);
442
443 /*
444 * Create a section for dll.
445 */
446 Status = ZwCreateSection(SectionHandle,
447 SECTION_ALL_ACCESS,
448 NULL,
449 NULL,
450 PAGE_READWRITE,
451 SEC_COMMIT | SEC_IMAGE,
452 FileHandle);
453 ZwClose(FileHandle);
454
455 if (!NT_SUCCESS(Status))
456 {
457 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
458 return Status;
459 }
460
461 RtlCreateUnicodeString(FullDosName,
462 DosName);
463
464 return Status;
465 }
466
467
468
469 /***************************************************************************
470 * NAME EXPORTED
471 * LdrLoadDll
472 *
473 * DESCRIPTION
474 *
475 * ARGUMENTS
476 *
477 * RETURN VALUE
478 *
479 * REVISIONS
480 *
481 * NOTE
482 *
483 */
484
485 NTSTATUS STDCALL
486 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
487 IN ULONG LoadFlags,
488 IN PUNICODE_STRING Name,
489 OUT PVOID *BaseAddress OPTIONAL)
490 {
491 UNICODE_STRING FullDosName;
492 UNICODE_STRING AdjustedName;
493 NTSTATUS Status;
494 PIMAGE_NT_HEADERS NTHeaders;
495 ULONG ViewSize;
496 PVOID ImageBase;
497 HANDLE SectionHandle;
498 PDLLMAIN_FUNC Entrypoint = NULL;
499 PLDR_MODULE Module;
500
501
502 if (Name == NULL)
503 {
504 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
505 return STATUS_SUCCESS;
506 }
507
508 *BaseAddress = NULL;
509
510 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
511 Name, BaseAddress);
512
513 /* adjust the full dll name */
514 LdrAdjustDllName (&AdjustedName,
515 Name,
516 FALSE);
517 DPRINT("AdjustedName: %wZ\n", &AdjustedName);
518
519 /*
520 * Test if dll is already loaded.
521 */
522 if (LdrFindEntryForName(&AdjustedName, &Module) == STATUS_SUCCESS)
523 {
524 DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
525 if (Module->LoadCount != -1)
526 Module->LoadCount++;
527 *BaseAddress = Module->BaseAddress;
528 return STATUS_SUCCESS;
529 }
530 DPRINT("Loading \"%wZ\"\n", Name);
531
532 /* Open or create dll image section */
533 Status = LdrpMapKnownDll(&AdjustedName,
534 &FullDosName,
535 &SectionHandle);
536 if (!NT_SUCCESS(Status))
537 {
538 Status = LdrpMapDllImageFile(SearchPath,
539 &AdjustedName,
540 &FullDosName,
541 &SectionHandle);
542 }
543
544 RtlFreeUnicodeString(&AdjustedName);
545
546 if (!NT_SUCCESS(Status))
547 {
548 DPRINT1("Failed to create or open dll section (Status %lx)\n", Status);
549 return Status;
550 }
551
552 /*
553 * Map the dll into the process.
554 */
555 ViewSize = 0;
556 ImageBase = 0;
557 Status = NtMapViewOfSection(SectionHandle,
558 NtCurrentProcess(),
559 &ImageBase,
560 0,
561 0,
562 NULL,
563 &ViewSize,
564 0,
565 MEM_COMMIT,
566 PAGE_READWRITE);
567 if (!NT_SUCCESS(Status))
568 {
569 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n", Status);
570 RtlFreeUnicodeString(&FullDosName);
571 NtClose(SectionHandle);
572 return(Status);
573 }
574
575 /* Get and check the NT headers */
576 NTHeaders = RtlImageNtHeader(ImageBase);
577 if (NTHeaders == NULL)
578 {
579 DPRINT1("RtlImageNtHeaders() failed\n");
580 RtlFreeUnicodeString(&FullDosName);
581 return STATUS_UNSUCCESSFUL;
582 }
583
584 /* relocate dll and fixup import table */
585 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
586 IMAGE_FILE_DLL)
587 {
588 Entrypoint =
589 (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle, &Module,
590 FullDosName.Buffer);
591 if (Entrypoint == NULL)
592 {
593 RtlFreeUnicodeString(&FullDosName);
594 return(STATUS_UNSUCCESSFUL);
595 }
596 }
597
598 RtlFreeUnicodeString(&FullDosName);
599
600 #ifdef DBG
601
602 LdrpLoadUserModuleSymbols(Module);
603
604 #endif /* DBG */
605
606 /* initialize dll */
607 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
608 IMAGE_FILE_DLL)
609 {
610 if (Module->EntryPoint != 0)
611 {
612 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
613
614 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
615 if (FALSE == Entrypoint(Module->BaseAddress,
616 DLL_PROCESS_ATTACH,
617 NULL))
618 {
619 /* Do this as a DPRINT1 for now, until clean up and fail implemented */
620 DPRINT1("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
621 &Module->BaseDllName);
622 /* FIXME: should clean up and fail */
623 }
624 else
625 {
626 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
627 &Module->BaseDllName);
628 }
629 }
630 else
631 {
632 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
633 &Module->BaseDllName);
634 }
635 }
636
637 *BaseAddress = Module->BaseAddress;
638 return STATUS_SUCCESS;
639 }
640
641
642 /***************************************************************************
643 * NAME EXPORTED
644 * LdrFindEntryForAddress
645 *
646 * DESCRIPTION
647 *
648 * ARGUMENTS
649 *
650 * RETURN VALUE
651 *
652 * REVISIONS
653 *
654 * NOTE
655 *
656 */
657 NTSTATUS STDCALL
658 LdrFindEntryForAddress(PVOID Address,
659 PLDR_MODULE *Module)
660 {
661 PLIST_ENTRY ModuleListHead;
662 PLIST_ENTRY Entry;
663 PLDR_MODULE ModulePtr;
664
665 DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address);
666
667 if (NtCurrentPeb()->Ldr == NULL)
668 return(STATUS_NO_MORE_ENTRIES);
669
670 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
671 Entry = ModuleListHead->Flink;
672 if (Entry == ModuleListHead)
673 return(STATUS_NO_MORE_ENTRIES);
674
675 while (Entry != ModuleListHead)
676 {
677 ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
678
679 DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->BaseAddress);
680
681 if ((Address >= ModulePtr->BaseAddress) &&
682 (Address <= (ModulePtr->BaseAddress + ModulePtr->SizeOfImage)))
683 {
684 *Module = ModulePtr;
685 return(STATUS_SUCCESS);
686 }
687
688 Entry = Entry->Flink;
689 }
690
691 DPRINT("Failed to find module entry.\n");
692
693 return(STATUS_NO_MORE_ENTRIES);
694 }
695
696
697 /***************************************************************************
698 * NAME LOCAL
699 * LdrFindEntryForName
700 *
701 * DESCRIPTION
702 *
703 * ARGUMENTS
704 *
705 * RETURN VALUE
706 *
707 * REVISIONS
708 *
709 * NOTE
710 *
711 */
712 static NTSTATUS
713 LdrFindEntryForName(PUNICODE_STRING Name,
714 PLDR_MODULE *Module)
715 {
716 PLIST_ENTRY ModuleListHead;
717 PLIST_ENTRY Entry;
718 PLDR_MODULE ModulePtr;
719 BOOLEAN ContainsPath;
720 unsigned i;
721
722 DPRINT("NTDLL.LdrFindEntryForName(Name %wZ)\n", Name);
723
724 if (NtCurrentPeb()->Ldr == NULL)
725 return(STATUS_NO_MORE_ENTRIES);
726
727 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
728 Entry = ModuleListHead->Flink;
729 if (Entry == ModuleListHead)
730 return(STATUS_NO_MORE_ENTRIES);
731
732 // NULL is the current process
733 if (Name == NULL)
734 {
735 *Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
736 return(STATUS_SUCCESS);
737 }
738
739 ContainsPath = (2 <= Name->Length && L':' == Name->Buffer[1]);
740 for (i = 0; ! ContainsPath && i < Name->Length; i++)
741 {
742 ContainsPath = L'\\' == Name->Buffer[i] ||
743 L'/' == Name->Buffer[i];
744 }
745 while (Entry != ModuleListHead)
746 {
747 ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
748
749 DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, Name);
750
751 if ((! ContainsPath &&
752 0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, Name, TRUE)) ||
753 (ContainsPath &&
754 0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, Name, TRUE)))
755 {
756 *Module = ModulePtr;
757 return(STATUS_SUCCESS);
758 }
759
760 Entry = Entry->Flink;
761 }
762
763 DPRINT("Failed to find dll %wZ\n", Name);
764
765 return(STATUS_NO_MORE_ENTRIES);
766 }
767
768 /**********************************************************************
769 * NAME LOCAL
770 * LdrFixupForward
771 *
772 * DESCRIPTION
773 *
774 * ARGUMENTS
775 *
776 * RETURN VALUE
777 *
778 * REVISIONS
779 *
780 * NOTE
781 *
782 */
783 static PVOID
784 LdrFixupForward(PCHAR ForwardName)
785 {
786 CHAR NameBuffer[128];
787 UNICODE_STRING DllName;
788 UNICODE_STRING FunctionName;
789 NTSTATUS Status;
790 PCHAR p;
791 PVOID BaseAddress;
792
793 strcpy(NameBuffer, ForwardName);
794 p = strchr(NameBuffer, '.');
795 if (p != NULL)
796 {
797 *p = 0;
798
799 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
800 RtlCreateUnicodeStringFromAsciiz (&DllName,
801 NameBuffer);
802
803 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
804 if (!NT_SUCCESS(Status))
805 {
806 Status = LdrLoadDll(NULL,
807 0,
808 &DllName,
809 &BaseAddress);
810 if (!NT_SUCCESS(Status))
811 {
812 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
813 RtlFreeUnicodeString (&DllName);
814 return NULL;
815 }
816 }
817
818 RtlFreeUnicodeString (&DllName);
819 DPRINT("BaseAddress: %p\n", BaseAddress);
820
821 return LdrGetExportByName(BaseAddress, p+1, -1);
822 }
823
824 return NULL;
825 }
826
827
828 /**********************************************************************
829 * NAME LOCAL
830 * LdrGetExportByOrdinal
831 *
832 * DESCRIPTION
833 *
834 * ARGUMENTS
835 *
836 * RETURN VALUE
837 *
838 * REVISIONS
839 *
840 * NOTE
841 *
842 */
843 static PVOID
844 LdrGetExportByOrdinal (
845 PVOID BaseAddress,
846 ULONG Ordinal
847 )
848 {
849 PIMAGE_EXPORT_DIRECTORY ExportDir;
850 PDWORD * ExFunctions;
851 USHORT * ExOrdinals;
852
853 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
854 RtlImageDirectoryEntryToData (BaseAddress,
855 TRUE,
856 IMAGE_DIRECTORY_ENTRY_EXPORT,
857 NULL);
858
859
860 ExOrdinals = (USHORT *)
861 RVA(
862 BaseAddress,
863 ExportDir->AddressOfNameOrdinals
864 );
865 ExFunctions = (PDWORD *)
866 RVA(
867 BaseAddress,
868 ExportDir->AddressOfFunctions
869 );
870 DbgPrint(
871 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
872 Ordinal,
873 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
874 );
875 return(RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] ));
876 }
877
878
879 /**********************************************************************
880 * NAME LOCAL
881 * LdrGetExportByName
882 *
883 * DESCRIPTION
884 *
885 * ARGUMENTS
886 *
887 * RETURN VALUE
888 *
889 * REVISIONS
890 *
891 * NOTE
892 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
893 * both with NumberOfNames entries.
894 *
895 */
896 static PVOID
897 LdrGetExportByName(PVOID BaseAddress,
898 PUCHAR SymbolName,
899 WORD Hint)
900 {
901 PIMAGE_EXPORT_DIRECTORY ExportDir;
902 PDWORD * ExFunctions;
903 PDWORD * ExNames;
904 USHORT * ExOrdinals;
905 ULONG i;
906 PVOID ExName;
907 ULONG Ordinal;
908 PVOID Function;
909 ULONG minn, maxn;
910 ULONG ExportDirSize;
911
912 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
913
914 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
915 RtlImageDirectoryEntryToData(BaseAddress,
916 TRUE,
917 IMAGE_DIRECTORY_ENTRY_EXPORT,
918 &ExportDirSize);
919 if (ExportDir == NULL)
920 {
921 DbgPrint("LdrGetExportByName(): no export directory!\n");
922 return NULL;
923 }
924
925
926 //The symbol names may be missing entirely
927 if (ExportDir->AddressOfNames == 0)
928 {
929 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
930 return NULL;
931 }
932
933 /*
934 * Get header pointers
935 */
936 ExNames = (PDWORD *)RVA(BaseAddress,
937 ExportDir->AddressOfNames);
938 ExOrdinals = (USHORT *)RVA(BaseAddress,
939 ExportDir->AddressOfNameOrdinals);
940 ExFunctions = (PDWORD *)RVA(BaseAddress,
941 ExportDir->AddressOfFunctions);
942
943 /*
944 * Check the hint first
945 */
946 if (Hint < ExportDir->NumberOfNames)
947 {
948 ExName = RVA(BaseAddress, ExNames[Hint]);
949 if (strcmp(ExName, SymbolName) == 0)
950 {
951 Ordinal = ExOrdinals[Hint];
952 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
953 if (((ULONG)Function >= (ULONG)ExportDir) &&
954 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
955 {
956 DPRINT("Forward: %s\n", (PCHAR)Function);
957 Function = LdrFixupForward((PCHAR)Function);
958 }
959 if (Function != NULL)
960 return Function;
961 }
962 }
963
964 /*
965 * Try a binary search first
966 */
967 minn = 0;
968 maxn = ExportDir->NumberOfNames;
969 while (minn <= maxn)
970 {
971 ULONG mid;
972 LONG res;
973
974 mid = (minn + maxn) / 2;
975
976 ExName = RVA(BaseAddress, ExNames[mid]);
977 res = strcmp(ExName, SymbolName);
978 if (res == 0)
979 {
980 Ordinal = ExOrdinals[mid];
981 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
982 if (((ULONG)Function >= (ULONG)ExportDir) &&
983 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
984 {
985 DPRINT("Forward: %s\n", (PCHAR)Function);
986 Function = LdrFixupForward((PCHAR)Function);
987 }
988 if (Function != NULL)
989 return Function;
990 }
991 else if (minn == maxn)
992 {
993 DPRINT("LdrGetExportByName(): binary search failed\n");
994 break;
995 }
996 else if (res > 0)
997 {
998 maxn = mid - 1;
999 }
1000 else
1001 {
1002 minn = mid + 1;
1003 }
1004 }
1005
1006 /*
1007 * Fall back on a linear search
1008 */
1009 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1010 for (i = 0; i < ExportDir->NumberOfNames; i++)
1011 {
1012 ExName = RVA(BaseAddress, ExNames[i]);
1013 if (strcmp(ExName,SymbolName) == 0)
1014 {
1015 Ordinal = ExOrdinals[i];
1016 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1017 DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
1018 if (((ULONG)Function >= (ULONG)ExportDir) &&
1019 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
1020 {
1021 DPRINT("Forward: %s\n", (PCHAR)Function);
1022 Function = LdrFixupForward((PCHAR)Function);
1023 }
1024 return Function;
1025 }
1026 }
1027 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
1028 return NULL;
1029 }
1030
1031
1032 /**********************************************************************
1033 * NAME LOCAL
1034 * LdrPerformRelocations
1035 *
1036 * DESCRIPTION
1037 * Relocate a DLL's memory image.
1038 *
1039 * ARGUMENTS
1040 *
1041 * RETURN VALUE
1042 *
1043 * REVISIONS
1044 *
1045 * NOTE
1046 *
1047 */
1048 static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders,
1049 PVOID ImageBase)
1050 {
1051 USHORT NumberOfEntries;
1052 PUSHORT pValue16;
1053 ULONG RelocationRVA;
1054 ULONG Delta32;
1055 ULONG Offset;
1056 PULONG pValue32;
1057 PRELOCATION_DIRECTORY RelocationDir;
1058 PRELOCATION_ENTRY RelocationBlock;
1059 int i;
1060 PIMAGE_DATA_DIRECTORY RelocationDDir;
1061 ULONG OldProtect;
1062 ULONG OldProtect2;
1063 NTSTATUS Status;
1064 PIMAGE_SECTION_HEADER Sections;
1065 ULONG MaxExtend;
1066 ULONG LastOffset;
1067
1068 Sections =
1069 (PIMAGE_SECTION_HEADER)((PVOID)NTHeaders + sizeof(IMAGE_NT_HEADERS));
1070 MaxExtend = 0;
1071 for (i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++)
1072 {
1073 if (!(Sections[i].Characteristics & IMAGE_SECTION_NOLOAD))
1074 {
1075 ULONG Extend;
1076 Extend =
1077 (ULONG)(Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize);
1078 MaxExtend = max(MaxExtend, Extend);
1079 }
1080 }
1081
1082 RelocationDDir =
1083 &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1084 RelocationRVA = RelocationDDir->VirtualAddress;
1085
1086 if (RelocationRVA)
1087 {
1088 RelocationDir =
1089 (PRELOCATION_DIRECTORY)((PCHAR)ImageBase + RelocationRVA);
1090
1091 while (RelocationDir->SizeOfBlock)
1092 {
1093 if (RelocationDir->VirtualAddress > MaxExtend)
1094 {
1095 RelocationRVA += RelocationDir->SizeOfBlock;
1096 RelocationDir =
1097 (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
1098 continue;
1099 }
1100
1101 Delta32 = (ULONG)(ImageBase - NTHeaders->OptionalHeader.ImageBase);
1102 RelocationBlock =
1103 (PRELOCATION_ENTRY) (RelocationRVA + ImageBase +
1104 sizeof (RELOCATION_DIRECTORY));
1105 NumberOfEntries =
1106 RelocationDir->SizeOfBlock - sizeof (RELOCATION_DIRECTORY);
1107 NumberOfEntries = NumberOfEntries / sizeof (RELOCATION_ENTRY);
1108
1109 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1110 ImageBase +
1111 RelocationDir->VirtualAddress,
1112 PAGE_SIZE,
1113 PAGE_READWRITE,
1114 &OldProtect);
1115 if (!NT_SUCCESS(Status))
1116 {
1117 DPRINT1("Failed to unprotect relocation target.\n");
1118 return(Status);
1119 }
1120
1121 if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
1122 {
1123 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1124 ImageBase +
1125 RelocationDir->VirtualAddress + PAGE_SIZE,
1126 PAGE_SIZE,
1127 PAGE_READWRITE,
1128 &OldProtect2);
1129 if (!NT_SUCCESS(Status))
1130 {
1131 DPRINT1("Failed to unprotect relocation target (2).\n");
1132 NtProtectVirtualMemory(NtCurrentProcess(),
1133 ImageBase +
1134 RelocationDir->VirtualAddress,
1135 PAGE_SIZE,
1136 OldProtect,
1137 &OldProtect);
1138 return(Status);
1139 }
1140 }
1141
1142 for (i = 0; i < NumberOfEntries; i++)
1143 {
1144 Offset = (RelocationBlock[i].TypeOffset & 0xfff);
1145 Offset += (ULONG)(RelocationDir->VirtualAddress + ImageBase);
1146
1147 /*
1148 * What kind of relocations should we perform
1149 * for the current entry?
1150 */
1151 switch (RelocationBlock[i].TypeOffset >> 12)
1152 {
1153 case TYPE_RELOC_ABSOLUTE:
1154 break;
1155
1156 case TYPE_RELOC_HIGH:
1157 pValue16 = (PUSHORT)Offset;
1158 *pValue16 += Delta32 >> 16;
1159 break;
1160
1161 case TYPE_RELOC_LOW:
1162 pValue16 = (PUSHORT)Offset;
1163 *pValue16 += Delta32 & 0xffff;
1164 break;
1165
1166 case TYPE_RELOC_HIGHLOW:
1167 pValue32 = (PULONG)Offset;
1168 *pValue32 += Delta32;
1169 break;
1170
1171 case TYPE_RELOC_HIGHADJ:
1172 /* FIXME: do the highadjust fixup */
1173 DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
1174 return(STATUS_UNSUCCESSFUL);
1175
1176 default:
1177 DPRINT("unexpected fixup type\n");
1178 return STATUS_UNSUCCESSFUL;
1179 }
1180 }
1181
1182 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1183 ImageBase +
1184 RelocationDir->VirtualAddress,
1185 PAGE_SIZE,
1186 OldProtect,
1187 &OldProtect);
1188 if (!NT_SUCCESS(Status))
1189 {
1190 DPRINT1("Failed to protect relocation target.\n");
1191 return(Status);
1192 }
1193
1194 if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
1195 {
1196 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1197 ImageBase +
1198 RelocationDir->VirtualAddress + PAGE_SIZE,
1199 PAGE_SIZE,
1200 OldProtect2,
1201 &OldProtect2);
1202 if (!NT_SUCCESS(Status))
1203 {
1204 DPRINT1("Failed to protect relocation target2.\n");
1205 return(Status);
1206 }
1207 }
1208
1209 RelocationRVA += RelocationDir->SizeOfBlock;
1210 RelocationDir =
1211 (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
1212 }
1213 }
1214 return STATUS_SUCCESS;
1215 }
1216
1217
1218 /**********************************************************************
1219 * NAME LOCAL
1220 * LdrFixupImports
1221 *
1222 * DESCRIPTION
1223 * Compute the entry point for every symbol the DLL imports
1224 * from other modules.
1225 *
1226 * ARGUMENTS
1227 *
1228 * RETURN VALUE
1229 *
1230 * REVISIONS
1231 *
1232 * NOTE
1233 *
1234 */
1235 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
1236 PVOID ImageBase)
1237 {
1238 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1239 ULONG Ordinal;
1240 PVOID BaseAddress;
1241 NTSTATUS Status;
1242 ULONG IATSize;
1243
1244 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
1245 ImageBase);
1246
1247 /*
1248 * Process each import module.
1249 */
1250 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
1251 ImageBase + NTHeaders->OptionalHeader
1252 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1253 .VirtualAddress);
1254 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
1255
1256 while (ImportModuleDirectory->dwRVAModuleName)
1257 {
1258 PVOID * ImportAddressList;
1259 PULONG FunctionNameList;
1260 UNICODE_STRING DllName;
1261 DWORD pName;
1262 WORD pHint;
1263 PVOID IATBase;
1264 ULONG OldProtect;
1265
1266 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
1267 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1268
1269 RtlCreateUnicodeStringFromAsciiz (&DllName,
1270 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1271
1272 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
1273 if (!NT_SUCCESS(Status))
1274 {
1275 Status = LdrLoadDll(NULL,
1276 0,
1277 &DllName,
1278 &BaseAddress);
1279 RtlFreeUnicodeString (&DllName);
1280 if (!NT_SUCCESS(Status))
1281 {
1282 DbgPrint("LdrFixupImports:failed to load %s\n"
1283 ,(PCHAR)(ImageBase
1284 + ImportModuleDirectory->dwRVAModuleName));
1285
1286 return Status;
1287 }
1288 }
1289
1290 /*
1291 * Get the import address list.
1292 */
1293 ImportAddressList = (PVOID *)(ImageBase
1294 + ImportModuleDirectory->dwRVAFunctionAddressList);
1295
1296 /*
1297 * Get the list of functions to import.
1298 */
1299 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1300 {
1301 FunctionNameList = (PULONG) (
1302 ImageBase
1303 + ImportModuleDirectory->dwRVAFunctionNameList
1304 );
1305 }
1306 else
1307 {
1308 FunctionNameList =
1309 (PULONG)(ImageBase
1310 + ImportModuleDirectory->dwRVAFunctionAddressList);
1311 }
1312
1313 /*
1314 * Get the size of IAT.
1315 */
1316 IATSize = 0;
1317 while (FunctionNameList[IATSize] != 0L)
1318 {
1319 IATSize++;
1320 }
1321
1322 /*
1323 * Unprotect the region we are about to write into.
1324 */
1325 IATBase = (PVOID)ImportAddressList;
1326 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1327 IATBase,
1328 IATSize * sizeof(PVOID*),
1329 PAGE_READWRITE,
1330 &OldProtect);
1331 if (!NT_SUCCESS(Status))
1332 {
1333 DbgPrint("LDR: Failed to unprotect IAT.\n");
1334 return(Status);
1335 }
1336
1337 /*
1338 * Walk through function list and fixup addresses.
1339 */
1340 while (*FunctionNameList != 0L)
1341 {
1342 if ((*FunctionNameList) & 0x80000000)
1343 {
1344 Ordinal = (*FunctionNameList) & 0x7fffffff;
1345 *ImportAddressList =
1346 LdrGetExportByOrdinal(BaseAddress,
1347 Ordinal);
1348 }
1349 else
1350 {
1351 pName = (DWORD) (ImageBase + *FunctionNameList + 2);
1352 pHint = *(PWORD)(ImageBase + *FunctionNameList);
1353
1354 *ImportAddressList =
1355 LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
1356 if ((*ImportAddressList) == NULL)
1357 {
1358 DbgPrint("Failed to import %s\n", pName);
1359 return STATUS_UNSUCCESSFUL;
1360 }
1361 }
1362 ImportAddressList++;
1363 FunctionNameList++;
1364 }
1365
1366 /*
1367 * Protect the region we are about to write into.
1368 */
1369 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1370 IATBase,
1371 IATSize * sizeof(PVOID*),
1372 OldProtect,
1373 &OldProtect);
1374 if (!NT_SUCCESS(Status))
1375 {
1376 DbgPrint("LDR: Failed to protect IAT.\n");
1377 return(Status);
1378 }
1379
1380 ImportModuleDirectory++;
1381 }
1382 return STATUS_SUCCESS;
1383 }
1384
1385
1386 /**********************************************************************
1387 * NAME
1388 * LdrPEStartup
1389 *
1390 * DESCRIPTION
1391 * 1. Map the DLL's sections into memory.
1392 * 2. Relocate, if needed the DLL.
1393 * 3. Fixup any imported symbol.
1394 * 4. Compute the DLL's entry point.
1395 *
1396 * ARGUMENTS
1397 * ImageBase
1398 * Address at which the DLL's image
1399 * is loaded.
1400 *
1401 * SectionHandle
1402 * Handle of the section that contains
1403 * the DLL's image.
1404 *
1405 * RETURN VALUE
1406 * NULL on error; otherwise the entry point
1407 * to call for initializing the DLL.
1408 *
1409 * REVISIONS
1410 *
1411 * NOTE
1412 *
1413 */
1414 PEPFUNC LdrPEStartup (PVOID ImageBase,
1415 HANDLE SectionHandle,
1416 PLDR_MODULE* Module,
1417 PWSTR FullDosName)
1418 {
1419 NTSTATUS Status;
1420 PEPFUNC EntryPoint = NULL;
1421 PIMAGE_DOS_HEADER DosHeader;
1422 PIMAGE_NT_HEADERS NTHeaders;
1423
1424 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1425 ImageBase, (ULONG)SectionHandle);
1426
1427 /*
1428 * Overlay DOS and WNT headers structures
1429 * to the DLL's image.
1430 */
1431 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1432 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
1433
1434 /*
1435 * If the base address is different from the
1436 * one the DLL is actually loaded, perform any
1437 * relocation.
1438 */
1439 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1440 {
1441 DbgPrint("LDR: Performing relocations\n");
1442 Status = LdrPerformRelocations(NTHeaders, ImageBase);
1443 if (!NT_SUCCESS(Status))
1444 {
1445 DbgPrint("LdrPerformRelocations() failed\n");
1446 return NULL;
1447 }
1448 }
1449
1450 if (Module != NULL)
1451 {
1452 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
1453 }
1454
1455 /*
1456 * If the DLL's imports symbols from other
1457 * modules, fixup the imported calls entry points.
1458 */
1459 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1460 .VirtualAddress != 0)
1461 {
1462 DPRINT("About to fixup imports\n");
1463 Status = LdrFixupImports(NTHeaders, ImageBase);
1464 if (!NT_SUCCESS(Status))
1465 {
1466 DbgPrint("LdrFixupImports() failed\n");
1467 return NULL;
1468 }
1469 DPRINT("Fixup done\n");
1470 }
1471
1472 /*
1473 * Compute the DLL's entry point's address.
1474 */
1475 DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
1476 DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
1477 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
1478 {
1479 EntryPoint = (PEPFUNC) (ImageBase
1480 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
1481 }
1482 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
1483 return EntryPoint;
1484 }
1485
1486
1487 NTSTATUS STDCALL
1488 LdrUnloadDll (IN PVOID BaseAddress)
1489 {
1490 PIMAGE_NT_HEADERS NtHeaders;
1491 PDLLMAIN_FUNC Entrypoint;
1492 PLIST_ENTRY ModuleListHead;
1493 PLIST_ENTRY Entry;
1494 PLDR_MODULE Module;
1495 NTSTATUS Status;
1496
1497 if (BaseAddress == NULL)
1498 return STATUS_SUCCESS;
1499
1500 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1501 Entry = ModuleListHead->Flink;
1502
1503 while (Entry != ModuleListHead)
1504 {
1505 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1506 if (Module->BaseAddress == BaseAddress)
1507 {
1508 if (Module->LoadCount == -1)
1509 {
1510 /* never unload this dll */
1511 return STATUS_SUCCESS;
1512 }
1513 else if (Module->LoadCount > 1)
1514 {
1515 Module->LoadCount--;
1516 return STATUS_SUCCESS;
1517 }
1518
1519 NtHeaders = RtlImageNtHeader (Module->BaseAddress);
1520 if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
1521 {
1522 if (Module->EntryPoint != 0)
1523 {
1524 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1525 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1526 Entrypoint(Module->BaseAddress,
1527 DLL_PROCESS_DETACH,
1528 NULL);
1529 }
1530 else
1531 {
1532 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1533 }
1534 }
1535 Status = ZwUnmapViewOfSection (NtCurrentProcess (),
1536 Module->BaseAddress);
1537 ZwClose (Module->SectionHandle);
1538
1539 /* remove the module entry from the list */
1540 RtlFreeUnicodeString (&Module->FullDllName);
1541 RtlFreeUnicodeString (&Module->BaseDllName);
1542 RemoveEntryList (Entry);
1543 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
1544
1545 return Status;
1546 }
1547
1548 Entry = Entry->Flink;
1549 }
1550
1551 DPRINT("NTDLL.LDR: Dll not found\n")
1552
1553 return STATUS_UNSUCCESSFUL;
1554 }
1555
1556
1557 NTSTATUS STDCALL
1558 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
1559 {
1560 PLIST_ENTRY ModuleListHead;
1561 PLIST_ENTRY Entry;
1562 PLDR_MODULE Module;
1563 NTSTATUS Status;
1564
1565 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress);
1566
1567 Status = STATUS_DLL_NOT_FOUND;
1568 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1569 Entry = ModuleListHead->Flink;
1570 while (Entry != ModuleListHead) {
1571 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1572
1573 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module->BaseDllName, Module->BaseAddress);
1574
1575 if (Module->BaseAddress == BaseAddress) {
1576 if (Module->TlsIndex == 0) {
1577 Module->Flags |= 0x00040000;
1578 Status = STATUS_SUCCESS;
1579 }
1580 return Status;
1581 }
1582 Entry = Entry->Flink;
1583 }
1584 return Status;
1585 }
1586
1587
1588 NTSTATUS STDCALL
1589 LdrGetDllHandle(IN ULONG Unknown1,
1590 IN ULONG Unknown2,
1591 IN PUNICODE_STRING DllName,
1592 OUT PVOID* BaseAddress)
1593 {
1594 UNICODE_STRING FullDllName;
1595 PLIST_ENTRY ModuleListHead;
1596 PLIST_ENTRY Entry;
1597 PLDR_MODULE Module;
1598
1599 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1600 Unknown1, Unknown2, DllName, BaseAddress);
1601
1602 /* NULL is the current executable */
1603 if (DllName == NULL) {
1604 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
1605 DPRINT("BaseAddress %x\n", *BaseAddress);
1606 return STATUS_SUCCESS;
1607 }
1608 LdrAdjustDllName(&FullDllName, DllName, TRUE);
1609
1610 DPRINT("FullDllName %wZ\n", &FullDllName);
1611
1612 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1613 Entry = ModuleListHead->Flink;
1614 while (Entry != ModuleListHead) {
1615 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1616
1617 DPRINT("EntryPoint %x\n", Module->EntryPoint);
1618 DPRINT("Comparing %wZ and %wZ\n", &Module->BaseDllName, &FullDllName);
1619
1620 if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE)) {
1621 RtlFreeUnicodeString(&FullDllName);
1622 *BaseAddress = Module->BaseAddress;
1623 DPRINT("BaseAddress %x\n", *BaseAddress);
1624 return STATUS_SUCCESS;
1625 }
1626 Entry = Entry->Flink;
1627 }
1628
1629 DPRINT("Failed to find dll %wZ\n", &FullDllName);
1630
1631 RtlFreeUnicodeString(&FullDllName);
1632 *BaseAddress = NULL;
1633 return STATUS_DLL_NOT_FOUND;
1634 }
1635
1636
1637 NTSTATUS STDCALL
1638 LdrGetProcedureAddress (IN PVOID BaseAddress,
1639 IN PANSI_STRING Name,
1640 IN ULONG Ordinal,
1641 OUT PVOID *ProcedureAddress)
1642 {
1643 PIMAGE_EXPORT_DIRECTORY ExportDir;
1644 PUSHORT OrdinalPtr;
1645 PULONG NamePtr;
1646 PULONG AddressPtr;
1647 ULONG i = 0;
1648
1649 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1650 BaseAddress, Name, Ordinal, ProcedureAddress);
1651
1652 /* Get the pointer to the export directory */
1653 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1654 RtlImageDirectoryEntryToData (BaseAddress,
1655 TRUE,
1656 IMAGE_DIRECTORY_ENTRY_EXPORT,
1657 &i);
1658
1659 DPRINT("ExportDir %x i %lu\n", ExportDir, i);
1660
1661 if (!ExportDir || !i || !ProcedureAddress)
1662 {
1663 return STATUS_INVALID_PARAMETER;
1664 }
1665
1666 AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
1667 if (Name && Name->Length)
1668 {
1669 /* by name */
1670 OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
1671 NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
1672 for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
1673 {
1674 if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
1675 {
1676 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
1677 return STATUS_SUCCESS;
1678 }
1679 }
1680 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
1681 }
1682 else
1683 {
1684 /* by ordinal */
1685 Ordinal &= 0x0000FFFF;
1686 if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
1687 {
1688 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
1689 return STATUS_SUCCESS;
1690 }
1691 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
1692 }
1693
1694 return STATUS_PROCEDURE_NOT_FOUND;
1695 }
1696
1697
1698 NTSTATUS STDCALL
1699 LdrShutdownProcess (VOID)
1700 {
1701 PLIST_ENTRY ModuleListHead;
1702 PLIST_ENTRY Entry;
1703 PLDR_MODULE Module;
1704
1705 DPRINT("LdrShutdownProcess() called\n");
1706
1707 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1708
1709 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1710 Entry = ModuleListHead->Blink;
1711
1712 while (Entry != ModuleListHead)
1713 {
1714 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1715
1716 DPRINT(" Unloading %wZ\n",
1717 &Module->BaseDllName);
1718 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1719 // they loaded dynamically, and when the last reference is gone, that lib will
1720 // be detached.
1721 if (Module->EntryPoint != 0 && Module->LoadCount == -1)
1722 {
1723 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1724
1725 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1726 Entrypoint (Module->BaseAddress,
1727 DLL_PROCESS_DETACH,
1728 NULL);
1729 }
1730
1731 Entry = Entry->Blink;
1732 }
1733
1734 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1735
1736 DPRINT("LdrShutdownProcess() done\n");
1737
1738 return STATUS_SUCCESS;
1739 }
1740
1741
1742 NTSTATUS STDCALL
1743 LdrShutdownThread (VOID)
1744 {
1745 PLIST_ENTRY ModuleListHead;
1746 PLIST_ENTRY Entry;
1747 PLDR_MODULE Module;
1748
1749 DPRINT("LdrShutdownThread() called\n");
1750
1751 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1752
1753 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1754 Entry = ModuleListHead->Blink;
1755
1756 while (Entry != ModuleListHead)
1757 {
1758 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1759
1760 DPRINT(" Unloading %wZ\n",
1761 &Module->BaseDllName);
1762
1763 if (Module->EntryPoint != 0)
1764 {
1765 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1766
1767 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1768 Entrypoint (Module->BaseAddress,
1769 DLL_THREAD_DETACH,
1770 NULL);
1771 }
1772
1773 Entry = Entry->Blink;
1774 }
1775
1776 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1777
1778 DPRINT("LdrShutdownThread() done\n");
1779
1780 return STATUS_SUCCESS;
1781 }
1782
1783
1784 /***************************************************************************
1785 * NAME EXPORTED
1786 * LdrQueryProcessModuleInformation
1787 *
1788 * DESCRIPTION
1789 *
1790 * ARGUMENTS
1791 *
1792 * RETURN VALUE
1793 *
1794 * REVISIONS
1795 *
1796 * NOTE
1797 */
1798 NTSTATUS STDCALL
1799 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
1800 IN ULONG Size OPTIONAL,
1801 OUT PULONG ReturnedSize)
1802 {
1803 PLIST_ENTRY ModuleListHead;
1804 PLIST_ENTRY Entry;
1805 PLDR_MODULE Module;
1806 PMODULE_ENTRY ModulePtr = NULL;
1807 NTSTATUS Status = STATUS_SUCCESS;
1808 ULONG UsedSize = sizeof(ULONG);
1809 ANSI_STRING AnsiString;
1810 PCHAR p;
1811
1812 DPRINT("LdrQueryProcessModuleInformation() called\n");
1813
1814 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1815
1816 if (ModuleInformation == NULL || Size == 0)
1817 {
1818 Status = STATUS_INFO_LENGTH_MISMATCH;
1819 }
1820 else
1821 {
1822 ModuleInformation->ModuleCount = 0;
1823 ModulePtr = &ModuleInformation->ModuleEntry[0];
1824 Status = STATUS_SUCCESS;
1825 }
1826
1827 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1828 Entry = ModuleListHead->Flink;
1829
1830 while (Entry != ModuleListHead)
1831 {
1832 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1833
1834 DPRINT(" Module %wZ\n",
1835 &Module->FullDllName);
1836
1837 if (UsedSize > Size)
1838 {
1839 Status = STATUS_INFO_LENGTH_MISMATCH;
1840 }
1841 else if (ModuleInformation != NULL)
1842 {
1843 ModulePtr->Unknown0 = 0; // FIXME: ??
1844 ModulePtr->Unknown1 = 0; // FIXME: ??
1845 ModulePtr->BaseAddress = Module->BaseAddress;
1846 ModulePtr->SizeOfImage = Module->SizeOfImage;
1847 ModulePtr->Flags = Module->Flags;
1848 ModulePtr->Unknown2 = 0; // FIXME: load order index ??
1849 ModulePtr->Unknown3 = 0; // FIXME: ??
1850 ModulePtr->LoadCount = Module->LoadCount;
1851
1852 AnsiString.Length = 0;
1853 AnsiString.MaximumLength = 256;
1854 AnsiString.Buffer = ModulePtr->ModuleName;
1855 RtlUnicodeStringToAnsiString(&AnsiString,
1856 &Module->FullDllName,
1857 FALSE);
1858 p = strrchr(ModulePtr->ModuleName, '\\');
1859 if (p != NULL)
1860 ModulePtr->PathLength = p - ModulePtr->ModuleName + 1;
1861 else
1862 ModulePtr->PathLength = 0;
1863
1864 ModulePtr++;
1865 ModuleInformation->ModuleCount++;
1866 }
1867 UsedSize += sizeof(MODULE_ENTRY);
1868
1869 Entry = Entry->Flink;
1870 }
1871
1872 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1873
1874 if (ReturnedSize != 0)
1875 *ReturnedSize = UsedSize;
1876
1877 DPRINT("LdrQueryProcessModuleInformation() done\n");
1878
1879 return(Status);
1880 }
1881
1882 /* EOF */