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