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