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