Fixed a wrong DPRINT.
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.59 2003/01/31 21:49:11 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/utils.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 */
10
11 /*
12 * TODO:
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
15 * - any more ??
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
22 #include <windows.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27
28
29 #ifdef DBG_NTDLL_LDR_UTILS
30 #define NDEBUG
31 #endif
32 #include <ntdll/ntdll.h>
33
34 /* PROTOTYPES ****************************************************************/
35
36 static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_MODULE *Module);
37 static PVOID LdrFixupForward(PCHAR ForwardName);
38 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
39
40
41 /* FUNCTIONS *****************************************************************/
42
43
44 #ifdef DBG
45
46 VOID
47 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
48 {
49 NtSystemDebugControl(
50 DebugDbgLoadSymbols,
51 (PVOID)LdrModule,
52 0,
53 NULL,
54 0,
55 NULL);
56 }
57
58 #endif /* DBG */
59
60
61 /***************************************************************************
62 * NAME LOCAL
63 * LdrAdjustDllName
64 *
65 * DESCRIPTION
66 * Adjusts the name of a dll to a fully qualified name.
67 *
68 * ARGUMENTS
69 * FullDllName: Pointer to caller supplied storage for the fully
70 * qualified dll name.
71 * DllName: Pointer to the dll name.
72 * BaseName: TRUE: Only the file name is passed to FullDllName
73 * FALSE: The full path is preserved in FullDllName
74 *
75 * RETURN VALUE
76 * None
77 *
78 * REVISIONS
79 *
80 * NOTE
81 * A given path is not affected by the adjustment, but the file
82 * name only:
83 * ntdll --> ntdll.dll
84 * ntdll. --> ntdll
85 * ntdll.xyz --> ntdll.xyz
86 */
87
88 static VOID
89 LdrAdjustDllName (PUNICODE_STRING FullDllName,
90 PUNICODE_STRING DllName,
91 BOOLEAN BaseName)
92 {
93 WCHAR Buffer[MAX_PATH];
94 ULONG Length;
95 PWCHAR Extension;
96 PWCHAR Pointer;
97
98 Length = DllName->Length / sizeof(WCHAR);
99
100 if (BaseName == TRUE)
101 {
102 /* get the base dll name */
103 Pointer = DllName->Buffer + Length;
104 Extension = Pointer;
105
106 do
107 {
108 --Pointer;
109 }
110 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
111
112 Pointer++;
113 Length = Extension - Pointer;
114 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
115 Buffer[Length] = L'\0';
116 }
117 else
118 {
119 /* get the full dll name */
120 memmove (Buffer, DllName->Buffer, DllName->Length);
121 Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
122 }
123
124 /* Build the DLL's absolute name */
125 Extension = wcsrchr (Buffer, L'.');
126 if ((Extension != NULL) && (*Extension == L'.'))
127 {
128 /* with extension - remove dot if it's the last character */
129 if (Buffer[Length - 1] == L'.')
130 Length--;
131 Buffer[Length] = 0;
132 }
133 else
134 {
135 /* name without extension - assume that it is .dll */
136 memmove (Buffer + Length, L".dll", 10);
137 }
138
139 RtlCreateUnicodeString(FullDllName, Buffer);
140 }
141
142 PLDR_MODULE
143 LdrAddModuleEntry(PVOID ImageBase, PIMAGE_NT_HEADERS NTHeaders,
144 PWSTR FullDosName)
145 {
146 PLDR_MODULE Module;
147 Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE));
148 assert(Module);
149 Module->BaseAddress = (PVOID)ImageBase;
150 Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
151 if (Module->EntryPoint != 0)
152 Module->EntryPoint += (ULONG)Module->BaseAddress;
153 Module->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
154 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
155 {
156 /* loading while app is running */
157 Module->LoadCount = 1;
158 } else {
159 /*
160 * loading while app is initializing
161 * dll must not be unloaded
162 */
163 Module->LoadCount = -1;
164 }
165
166 Module->TlsIndex = 0;
167 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
168 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
169
170 RtlCreateUnicodeString (&Module->FullDllName,
171 FullDosName);
172 RtlCreateUnicodeString (&Module->BaseDllName,
173 wcsrchr(FullDosName, L'\\') + 1);
174 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
175
176 /* FIXME: aquire loader lock */
177 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
178 &Module->InLoadOrderModuleList);
179 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
180 &Module->InInitializationOrderModuleList);
181 /* FIXME: release loader lock */
182
183 return(Module);
184 }
185
186 /***************************************************************************
187 * NAME EXPORTED
188 * LdrLoadDll
189 *
190 * DESCRIPTION
191 *
192 * ARGUMENTS
193 *
194 * RETURN VALUE
195 *
196 * REVISIONS
197 *
198 * NOTE
199 *
200 */
201
202 NTSTATUS STDCALL
203 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
204 IN ULONG LoadFlags,
205 IN PUNICODE_STRING Name,
206 OUT PVOID *BaseAddress OPTIONAL)
207 {
208 WCHAR SearchPathBuffer[MAX_PATH];
209 WCHAR FullDosName[MAX_PATH];
210 UNICODE_STRING AdjustedName;
211 UNICODE_STRING FullNtFileName;
212 OBJECT_ATTRIBUTES FileObjectAttributes;
213 char BlockBuffer [1024];
214 PIMAGE_DOS_HEADER DosHeader;
215 NTSTATUS Status;
216 PIMAGE_NT_HEADERS NTHeaders;
217 ULONG ImageSize;
218 ULONG InitialViewSize;
219 PVOID ImageBase;
220 HANDLE FileHandle;
221 HANDLE SectionHandle;
222 PDLLMAIN_FUNC Entrypoint = NULL;
223 PLDR_MODULE Module;
224
225 if (Name == NULL)
226 {
227 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
228 return STATUS_SUCCESS;
229 }
230
231 *BaseAddress = NULL;
232
233 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
234 Name, BaseAddress);
235
236 /* adjust the full dll name */
237 LdrAdjustDllName (&AdjustedName,
238 Name,
239 FALSE);
240 DPRINT("AdjustedName: %wZ\n", &AdjustedName);
241
242 /*
243 * Test if dll is already loaded.
244 */
245 if (LdrFindEntryForName(&AdjustedName, &Module) == STATUS_SUCCESS)
246 {
247 DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
248 if (Module->LoadCount != -1)
249 Module->LoadCount++;
250 *BaseAddress = Module->BaseAddress;
251 return STATUS_SUCCESS;
252 }
253 DPRINT("Loading \"%wZ\"\n", Name);
254
255 if (SearchPath == NULL)
256 {
257 SearchPath = SearchPathBuffer;
258 wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
259 wcscat (SearchPathBuffer, L"\\system32;");
260 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
261 wcscat (SearchPathBuffer, L";.");
262 }
263
264 DPRINT("SearchPath %S\n", SearchPath);
265
266 if (RtlDosSearchPath_U (SearchPath,
267 AdjustedName.Buffer,
268 NULL,
269 MAX_PATH,
270 FullDosName,
271 NULL) == 0)
272 return STATUS_DLL_NOT_FOUND;
273
274 DPRINT("FullDosName %S\n", FullDosName);
275
276 RtlFreeUnicodeString (&AdjustedName);
277
278 if (!RtlDosPathNameToNtPathName_U (FullDosName,
279 &FullNtFileName,
280 NULL,
281 NULL))
282 return STATUS_DLL_NOT_FOUND;
283
284 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
285
286 InitializeObjectAttributes(&FileObjectAttributes,
287 &FullNtFileName,
288 0,
289 NULL,
290 NULL);
291
292 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
293
294 Status = ZwOpenFile(&FileHandle,
295 FILE_ALL_ACCESS,
296 &FileObjectAttributes,
297 NULL,
298 0,
299 0);
300 if (!NT_SUCCESS(Status))
301 {
302 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
303 &FullNtFileName, Status);
304 RtlFreeUnicodeString (&FullNtFileName);
305 return Status;
306 }
307 RtlFreeUnicodeString (&FullNtFileName);
308
309 Status = ZwReadFile(FileHandle,
310 0,
311 0,
312 0,
313 0,
314 BlockBuffer,
315 sizeof(BlockBuffer),
316 0,
317 0);
318 if (!NT_SUCCESS(Status))
319 {
320 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
321 ZwClose(FileHandle);
322 return Status;
323 }
324 /*
325 * Overlay DOS and NT headers structures to the
326 * buffer with DLL's header raw data.
327 */
328 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
329 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
330 /*
331 * Check it is a PE image file.
332 */
333 if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
334 || (DosHeader->e_lfanew == 0L)
335 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
336 {
337 DPRINT("NTDLL format invalid\n");
338 ZwClose(FileHandle);
339
340 return STATUS_UNSUCCESSFUL;
341 }
342
343 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
344 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
345
346 DPRINT("ImageBase 0x%08x\n", ImageBase);
347
348 /*
349 * Create a section for dll.
350 */
351 Status = ZwCreateSection(&SectionHandle,
352 SECTION_ALL_ACCESS,
353 NULL,
354 NULL,
355 PAGE_READWRITE,
356 SEC_COMMIT | SEC_IMAGE,
357 FileHandle);
358 if (!NT_SUCCESS(Status))
359 {
360 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
361 ZwClose(FileHandle);
362 return Status;
363 }
364
365 /*
366 * Map the dll into the process.
367 */
368 InitialViewSize = 0;
369 ImageBase = 0;
370 Status = ZwMapViewOfSection(SectionHandle,
371 NtCurrentProcess(),
372 &ImageBase,
373 0,
374 InitialViewSize,
375 NULL,
376 &InitialViewSize,
377 0,
378 MEM_COMMIT,
379 PAGE_READWRITE);
380 if (!NT_SUCCESS(Status))
381 {
382 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n", Status);
383 ZwClose(FileHandle);
384 return(Status);
385 }
386 ZwClose(FileHandle);
387
388 /* relocate dll and fixup import table */
389 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
390 IMAGE_FILE_DLL)
391 {
392 Entrypoint =
393 (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle, &Module,
394 FullDosName);
395 if (Entrypoint == NULL)
396 {
397 return(STATUS_UNSUCCESSFUL);
398 }
399 }
400
401 #ifdef DBG
402
403 LdrpLoadUserModuleSymbols(Module);
404
405 #endif /* DBG */
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 PIMAGE_DATA_DIRECTORY RelocationDDir;
840 ULONG OldProtect;
841 NTSTATUS Status;
842 PIMAGE_SECTION_HEADER Sections;
843 ULONG MaxExtend;
844 ULONG LastOffset;
845
846 Sections =
847 (PIMAGE_SECTION_HEADER)((PVOID)NTHeaders + sizeof(IMAGE_NT_HEADERS));
848 MaxExtend = 0;
849 for (i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++)
850 {
851 if (!(Sections[i].Characteristics & IMAGE_SECTION_NOLOAD))
852 {
853 ULONG Extend;
854 Extend =
855 (ULONG)(Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize);
856 MaxExtend = max(MaxExtend, Extend);
857 }
858 }
859
860 RelocationDDir =
861 &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
862 RelocationRVA = RelocationDDir->VirtualAddress;
863
864 if (RelocationRVA)
865 {
866 RelocationDir =
867 (PRELOCATION_DIRECTORY)((PCHAR)ImageBase + RelocationRVA);
868
869 while (RelocationDir->SizeOfBlock)
870 {
871 if (RelocationDir->VirtualAddress > MaxExtend)
872 {
873 RelocationRVA += RelocationDir->SizeOfBlock;
874 RelocationDir =
875 (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
876 continue;
877 }
878
879 Delta32 = (ULONG)(ImageBase - NTHeaders->OptionalHeader.ImageBase);
880 RelocationBlock =
881 (PRELOCATION_ENTRY) (RelocationRVA + ImageBase +
882 sizeof (RELOCATION_DIRECTORY));
883 NumberOfEntries =
884 RelocationDir->SizeOfBlock - sizeof (RELOCATION_DIRECTORY);
885 NumberOfEntries = NumberOfEntries / sizeof (RELOCATION_ENTRY);
886
887 Status = NtProtectVirtualMemory(NtCurrentProcess(),
888 ImageBase +
889 RelocationDir->VirtualAddress,
890 PAGE_SIZE,
891 PAGE_READWRITE,
892 &OldProtect);
893 if (!NT_SUCCESS(Status))
894 {
895 DPRINT1("Failed to unprotect relocation target.\n");
896 return(Status);
897 }
898
899 for (i = 0; i < NumberOfEntries; i++)
900 {
901 Offset = (RelocationBlock[i].TypeOffset & 0xfff);
902 Offset += (ULONG)(RelocationDir->VirtualAddress + ImageBase);
903
904 /*
905 * What kind of relocations should we perform
906 * for the current entry?
907 */
908 switch (RelocationBlock[i].TypeOffset >> 12)
909 {
910 case TYPE_RELOC_ABSOLUTE:
911 break;
912
913 case TYPE_RELOC_HIGH:
914 pValue16 = (PUSHORT)Offset;
915 *pValue16 += Delta32 >> 16;
916 break;
917
918 case TYPE_RELOC_LOW:
919 pValue16 = (PUSHORT)Offset;
920 *pValue16 += Delta32 & 0xffff;
921 break;
922
923 case TYPE_RELOC_HIGHLOW:
924 pValue32 = (PULONG)Offset;
925 *pValue32 += Delta32;
926 break;
927
928 case TYPE_RELOC_HIGHADJ:
929 /* FIXME: do the highadjust fixup */
930 DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
931 return(STATUS_UNSUCCESSFUL);
932
933 default:
934 DPRINT("unexpected fixup type\n");
935 return STATUS_UNSUCCESSFUL;
936 }
937 }
938
939 Status = NtProtectVirtualMemory(NtCurrentProcess(),
940 ImageBase +
941 RelocationDir->VirtualAddress,
942 PAGE_SIZE,
943 OldProtect,
944 &OldProtect);
945 if (!NT_SUCCESS(Status))
946 {
947 DPRINT1("Failed to protect relocation target.\n");
948 return(Status);
949 }
950
951 RelocationRVA += RelocationDir->SizeOfBlock;
952 RelocationDir =
953 (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
954 }
955 }
956 return STATUS_SUCCESS;
957 }
958
959
960 /**********************************************************************
961 * NAME LOCAL
962 * LdrFixupImports
963 *
964 * DESCRIPTION
965 * Compute the entry point for every symbol the DLL imports
966 * from other modules.
967 *
968 * ARGUMENTS
969 *
970 * RETURN VALUE
971 *
972 * REVISIONS
973 *
974 * NOTE
975 *
976 */
977 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
978 PVOID ImageBase)
979 {
980 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
981 ULONG Ordinal;
982 PVOID BaseAddress;
983 NTSTATUS Status;
984 ULONG IATSize;
985
986 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
987 ImageBase);
988
989 /*
990 * Process each import module.
991 */
992 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
993 ImageBase + NTHeaders->OptionalHeader
994 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
995 .VirtualAddress);
996 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
997
998 while (ImportModuleDirectory->dwRVAModuleName)
999 {
1000 PVOID * ImportAddressList;
1001 PULONG FunctionNameList;
1002 UNICODE_STRING DllName;
1003 DWORD pName;
1004 WORD pHint;
1005 PVOID IATBase;
1006 ULONG OldProtect;
1007
1008 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
1009 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1010
1011 RtlCreateUnicodeStringFromAsciiz (&DllName,
1012 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1013
1014 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
1015 if (!NT_SUCCESS(Status))
1016 {
1017 Status = LdrLoadDll(NULL,
1018 0,
1019 &DllName,
1020 &BaseAddress);
1021 RtlFreeUnicodeString (&DllName);
1022 if (!NT_SUCCESS(Status))
1023 {
1024 DbgPrint("LdrFixupImports:failed to load %s\n"
1025 ,(PCHAR)(ImageBase
1026 + ImportModuleDirectory->dwRVAModuleName));
1027
1028 return Status;
1029 }
1030 }
1031
1032 /*
1033 * Get the import address list.
1034 */
1035 ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
1036 + ImportModuleDirectory->dwRVAFunctionAddressList);
1037
1038 /*
1039 * Get the list of functions to import.
1040 */
1041 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1042 {
1043 FunctionNameList = (PULONG) (
1044 ImageBase
1045 + ImportModuleDirectory->dwRVAFunctionNameList
1046 );
1047 }
1048 else
1049 {
1050 FunctionNameList =
1051 (PULONG)(ImageBase
1052 + ImportModuleDirectory->dwRVAFunctionAddressList);
1053 }
1054
1055 /*
1056 * Get the size of IAT.
1057 */
1058 IATSize = 0;
1059 while (FunctionNameList[IATSize] != 0L)
1060 {
1061 IATSize++;
1062 }
1063
1064 /*
1065 * Unprotect the region we are about to write into.
1066 */
1067 IATBase = (PVOID)ImportAddressList;
1068 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1069 IATBase,
1070 IATSize * sizeof(PVOID*),
1071 PAGE_READWRITE,
1072 &OldProtect);
1073 if (!NT_SUCCESS(Status))
1074 {
1075 DbgPrint("LDR: Failed to unprotect IAT.\n");
1076 return(Status);
1077 }
1078
1079 /*
1080 * Walk through function list and fixup addresses.
1081 */
1082 while (*FunctionNameList != 0L)
1083 {
1084 if ((*FunctionNameList) & 0x80000000)
1085 {
1086 Ordinal = (*FunctionNameList) & 0x7fffffff;
1087 *ImportAddressList =
1088 LdrGetExportByOrdinal(BaseAddress,
1089 Ordinal);
1090 }
1091 else
1092 {
1093 pName = (DWORD) (ImageBase + *FunctionNameList + 2);
1094 pHint = *(PWORD)(ImageBase + *FunctionNameList);
1095
1096 *ImportAddressList =
1097 LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
1098 if ((*ImportAddressList) == NULL)
1099 {
1100 DbgPrint("Failed to import %s\n", pName);
1101 return STATUS_UNSUCCESSFUL;
1102 }
1103 }
1104 ImportAddressList++;
1105 FunctionNameList++;
1106 }
1107
1108 /*
1109 * Protect the region we are about to write into.
1110 */
1111 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1112 IATBase,
1113 IATSize * sizeof(PVOID*),
1114 OldProtect,
1115 &OldProtect);
1116 if (!NT_SUCCESS(Status))
1117 {
1118 DbgPrint("LDR: Failed to protect IAT.\n");
1119 return(Status);
1120 }
1121
1122 ImportModuleDirectory++;
1123 }
1124 return STATUS_SUCCESS;
1125 }
1126
1127
1128 /**********************************************************************
1129 * NAME
1130 * LdrPEStartup
1131 *
1132 * DESCRIPTION
1133 * 1. Map the DLL's sections into memory.
1134 * 2. Relocate, if needed the DLL.
1135 * 3. Fixup any imported symbol.
1136 * 4. Compute the DLL's entry point.
1137 *
1138 * ARGUMENTS
1139 * ImageBase
1140 * Address at which the DLL's image
1141 * is loaded.
1142 *
1143 * SectionHandle
1144 * Handle of the section that contains
1145 * the DLL's image.
1146 *
1147 * RETURN VALUE
1148 * NULL on error; otherwise the entry point
1149 * to call for initializing the DLL.
1150 *
1151 * REVISIONS
1152 *
1153 * NOTE
1154 *
1155 */
1156 PEPFUNC LdrPEStartup (PVOID ImageBase,
1157 HANDLE SectionHandle,
1158 PLDR_MODULE* Module,
1159 PWSTR FullDosName)
1160 {
1161 NTSTATUS Status;
1162 PEPFUNC EntryPoint = NULL;
1163 PIMAGE_DOS_HEADER DosHeader;
1164 PIMAGE_NT_HEADERS NTHeaders;
1165
1166 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1167 ImageBase, (ULONG)SectionHandle);
1168
1169 /*
1170 * Overlay DOS and WNT headers structures
1171 * to the DLL's image.
1172 */
1173 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1174 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
1175
1176 /*
1177 * If the base address is different from the
1178 * one the DLL is actually loaded, perform any
1179 * relocation.
1180 */
1181 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1182 {
1183 DbgPrint("LDR: Performing relocations\n");
1184 Status = LdrPerformRelocations(NTHeaders, ImageBase);
1185 if (!NT_SUCCESS(Status))
1186 {
1187 DbgPrint("LdrPerformRelocations() failed\n");
1188 return NULL;
1189 }
1190 }
1191
1192 if (Module != NULL)
1193 {
1194 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
1195 }
1196
1197 /*
1198 * If the DLL's imports symbols from other
1199 * modules, fixup the imported calls entry points.
1200 */
1201 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1202 .VirtualAddress != 0)
1203 {
1204 DPRINT("About to fixup imports\n");
1205 Status = LdrFixupImports(NTHeaders, ImageBase);
1206 if (!NT_SUCCESS(Status))
1207 {
1208 DbgPrint("LdrFixupImports() failed\n");
1209 return NULL;
1210 }
1211 DPRINT("Fixup done\n");
1212 }
1213
1214 /*
1215 * Compute the DLL's entry point's address.
1216 */
1217 DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
1218 DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
1219 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
1220 {
1221 EntryPoint = (PEPFUNC) (ImageBase
1222 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
1223 }
1224 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
1225 return EntryPoint;
1226 }
1227
1228
1229 NTSTATUS STDCALL
1230 LdrUnloadDll (IN PVOID BaseAddress)
1231 {
1232 PIMAGE_NT_HEADERS NtHeaders;
1233 PDLLMAIN_FUNC Entrypoint;
1234 PLIST_ENTRY ModuleListHead;
1235 PLIST_ENTRY Entry;
1236 PLDR_MODULE Module;
1237 NTSTATUS Status;
1238
1239 if (BaseAddress == NULL)
1240 return STATUS_SUCCESS;
1241
1242 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1243 Entry = ModuleListHead->Flink;
1244
1245 while (Entry != ModuleListHead)
1246 {
1247 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1248 if (Module->BaseAddress == BaseAddress)
1249 {
1250 if (Module->LoadCount == -1)
1251 {
1252 /* never unload this dll */
1253 return STATUS_SUCCESS;
1254 }
1255 else if (Module->LoadCount > 1)
1256 {
1257 Module->LoadCount--;
1258 return STATUS_SUCCESS;
1259 }
1260
1261 NtHeaders = RtlImageNtHeader (Module->BaseAddress);
1262 if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
1263 {
1264 if (Module->EntryPoint != 0)
1265 {
1266 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1267 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1268 Entrypoint(Module->BaseAddress,
1269 DLL_PROCESS_DETACH,
1270 NULL);
1271 }
1272 else
1273 {
1274 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1275 }
1276 }
1277 Status = ZwUnmapViewOfSection (NtCurrentProcess (),
1278 Module->BaseAddress);
1279 ZwClose (Module->SectionHandle);
1280
1281 /* remove the module entry from the list */
1282 RtlFreeUnicodeString (&Module->FullDllName);
1283 RtlFreeUnicodeString (&Module->BaseDllName);
1284 RemoveEntryList (Entry);
1285 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
1286
1287 return Status;
1288 }
1289
1290 Entry = Entry->Flink;
1291 }
1292
1293 DPRINT("NTDLL.LDR: Dll not found\n")
1294
1295 return STATUS_UNSUCCESSFUL;
1296 }
1297
1298 #if 0 /*MOVED_TO_FILE_RES_C*/
1299
1300 NTSTATUS STDCALL
1301 LdrFindResource_U(PVOID BaseAddress,
1302 PLDR_RESOURCE_INFO ResourceInfo,
1303 ULONG Level,
1304 PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
1305 {
1306 PIMAGE_RESOURCE_DIRECTORY ResDir;
1307 PIMAGE_RESOURCE_DIRECTORY ResBase;
1308 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1309 NTSTATUS Status = STATUS_SUCCESS;
1310 ULONG EntryCount;
1311 PWCHAR ws;
1312 ULONG i;
1313 ULONG Id;
1314
1315 DPRINT ("LdrFindResource_U()\n");
1316
1317 /* Get the pointer to the resource directory */
1318 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1319 RtlImageDirectoryEntryToData (BaseAddress,
1320 TRUE,
1321 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1322 &i);
1323 if (ResDir == NULL)
1324 {
1325 return STATUS_RESOURCE_DATA_NOT_FOUND;
1326 }
1327
1328 DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
1329
1330 ResBase = ResDir;
1331
1332 /* Let's go into resource tree */
1333 for (i = 0; i < Level; i++)
1334 {
1335 DPRINT("ResDir: %x\n", (ULONG)ResDir);
1336 Id = ((PULONG)ResourceInfo)[i];
1337 EntryCount = ResDir->NumberOfNamedEntries;
1338 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
1339 DPRINT("ResEntry %x\n", (ULONG)ResEntry);
1340 if (Id & 0xFFFF0000)
1341 {
1342 /* Resource name is a unicode string */
1343 for (; EntryCount--; ResEntry++)
1344 {
1345 /* Scan entries for equal name */
1346 if (ResEntry->Name & 0x80000000)
1347 {
1348 ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1349 if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
1350 wcslen((PWCHAR)Id) == (int)*ws )
1351 {
1352 goto found;
1353 }
1354 }
1355 }
1356 }
1357 else
1358 {
1359 /* We use ID number instead of string */
1360 ResEntry += EntryCount;
1361 EntryCount = ResDir->NumberOfIdEntries;
1362 for (; EntryCount--; ResEntry++)
1363 {
1364 /* Scan entries for equal name */
1365 if (ResEntry->Name == Id)
1366 {
1367 DPRINT("ID entry found %x\n", Id);
1368 goto found;
1369 }
1370 }
1371 }
1372 DPRINT("Error %lu\n", i);
1373
1374 switch (i)
1375 {
1376 case 0:
1377 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1378
1379 case 1:
1380 return STATUS_RESOURCE_NAME_NOT_FOUND;
1381
1382 case 2:
1383 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1384 {
1385 /* Use the first available language */
1386 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1387 break;
1388 }
1389 return STATUS_RESOURCE_LANG_NOT_FOUND;
1390
1391 case 3:
1392 return STATUS_RESOURCE_DATA_NOT_FOUND;
1393
1394 default:
1395 return STATUS_INVALID_PARAMETER;
1396 }
1397 found:;
1398 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
1399 (ResEntry->OffsetToData & 0x7FFFFFFF));
1400 }
1401 DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
1402
1403 if (ResourceDataEntry)
1404 {
1405 *ResourceDataEntry = (PVOID)ResDir;
1406 }
1407
1408 return Status;
1409 }
1410
1411
1412 NTSTATUS STDCALL
1413 LdrAccessResource(IN PVOID BaseAddress,
1414 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
1415 OUT PVOID *Resource OPTIONAL,
1416 OUT PULONG Size OPTIONAL)
1417 {
1418 PIMAGE_SECTION_HEADER Section;
1419 PIMAGE_NT_HEADERS NtHeader;
1420 ULONG SectionRva;
1421 ULONG SectionVa;
1422 ULONG DataSize;
1423 ULONG Offset = 0;
1424 ULONG Data;
1425
1426 Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
1427 TRUE,
1428 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1429 &DataSize);
1430 if (Data == 0)
1431 return STATUS_RESOURCE_DATA_NOT_FOUND;
1432
1433 if ((ULONG)BaseAddress & 1)
1434 {
1435 /* loaded as ordinary file */
1436 NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
1437 Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
1438 Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
1439 if (Section == NULL)
1440 {
1441 return STATUS_RESOURCE_DATA_NOT_FOUND;
1442 }
1443
1444 if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
1445 {
1446 SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
1447 SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
1448 Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
1449 }
1450 }
1451
1452 if (Resource)
1453 {
1454 *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
1455 }
1456
1457 if (Size)
1458 {
1459 *Size = ResourceDataEntry->Size;
1460 }
1461
1462 return STATUS_SUCCESS;
1463 }
1464
1465 #endif /*MOVED_TO_FILE_RES_C*/
1466
1467 NTSTATUS STDCALL
1468 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
1469 {
1470 PLIST_ENTRY ModuleListHead;
1471 PLIST_ENTRY Entry;
1472 PLDR_MODULE Module;
1473 NTSTATUS Status;
1474
1475 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress);
1476
1477 Status = STATUS_DLL_NOT_FOUND;
1478 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1479 Entry = ModuleListHead->Flink;
1480 while (Entry != ModuleListHead) {
1481 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1482
1483 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module->BaseDllName, Module->BaseAddress);
1484
1485 if (Module->BaseAddress == BaseAddress) {
1486 if (Module->TlsIndex == 0) {
1487 Module->Flags |= 0x00040000;
1488 Status = STATUS_SUCCESS;
1489 }
1490 return Status;
1491 }
1492 Entry = Entry->Flink;
1493 }
1494 return Status;
1495 }
1496
1497 #if 0 /*MOVED_TO_FILE_RES_C*/
1498
1499 NTSTATUS STDCALL
1500 LdrFindResourceDirectory_U (IN PVOID BaseAddress,
1501 WCHAR **name,
1502 DWORD level,
1503 OUT PVOID *addr)
1504 {
1505 PIMAGE_RESOURCE_DIRECTORY ResDir;
1506 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1507 ULONG EntryCount;
1508 ULONG i;
1509 NTSTATUS Status = STATUS_SUCCESS;
1510 WCHAR *ws;
1511
1512 /* Get the pointer to the resource directory */
1513 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1514 RtlImageDirectoryEntryToData (BaseAddress,
1515 TRUE,
1516 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1517 &i);
1518 if (ResDir == NULL)
1519 {
1520 return STATUS_RESOURCE_DATA_NOT_FOUND;
1521 }
1522
1523 /* Let's go into resource tree */
1524 for (i = 0; i < level; i++, name++)
1525 {
1526 EntryCount = ResDir->NumberOfNamedEntries;
1527 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
1528 if ((ULONG)(*name) & 0xFFFF0000)
1529 {
1530 /* Resource name is a unicode string */
1531 for (; EntryCount--; ResEntry++)
1532 {
1533 /* Scan entries for equal name */
1534 if (ResEntry->Name & 0x80000000)
1535 {
1536 ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1537 if (!wcsncmp( *name, ws + 1, *ws ) && wcslen( *name ) == (int)*ws )
1538 {
1539 goto found;
1540 }
1541 }
1542 }
1543 }
1544 else
1545 {
1546 /* We use ID number instead of string */
1547 ResEntry += EntryCount;
1548 EntryCount = ResDir->NumberOfIdEntries;
1549 for (; EntryCount--; ResEntry++)
1550 {
1551 /* Scan entries for equal name */
1552 if (ResEntry->Name == (ULONG)(*name))
1553 goto found;
1554 }
1555 }
1556
1557 switch (i)
1558 {
1559 case 0:
1560 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1561
1562 case 1:
1563 return STATUS_RESOURCE_NAME_NOT_FOUND;
1564
1565 case 2:
1566 Status = STATUS_RESOURCE_LANG_NOT_FOUND;
1567 /* Just use first language entry */
1568 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1569 {
1570 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1571 break;
1572 }
1573 return Status;
1574
1575 case 3:
1576 return STATUS_RESOURCE_DATA_NOT_FOUND;
1577
1578 default:
1579 return STATUS_INVALID_PARAMETER;
1580 }
1581 found:;
1582 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
1583 }
1584
1585 if (addr)
1586 {
1587 *addr = (PVOID)ResDir;
1588 }
1589
1590 return Status;
1591 }
1592
1593 #endif /*MOVED_TO_FILE_RES_C*/
1594
1595 NTSTATUS
1596 STDCALL
1597 LdrGetDllHandle(IN ULONG Unknown1,
1598 IN ULONG Unknown2,
1599 IN PUNICODE_STRING DllName,
1600 OUT PVOID* BaseAddress)
1601 {
1602 UNICODE_STRING FullDllName;
1603 PLIST_ENTRY ModuleListHead;
1604 PLIST_ENTRY Entry;
1605 PLDR_MODULE Module;
1606
1607 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1608 Unknown1, Unknown2, DllName, BaseAddress);
1609
1610 /* NULL is the current executable */
1611 if (DllName == NULL) {
1612 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
1613 DPRINT("BaseAddress %x\n", *BaseAddress);
1614 return STATUS_SUCCESS;
1615 }
1616 LdrAdjustDllName(&FullDllName, DllName, TRUE);
1617
1618 DPRINT("FullDllName %wZ\n", &FullDllName);
1619
1620 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1621 Entry = ModuleListHead->Flink;
1622 while (Entry != ModuleListHead) {
1623 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1624
1625 DPRINT("EntryPoint %x\n", Module->EntryPoint);
1626 DPRINT("Comparing %wZ and %wZ\n", &Module->BaseDllName, &FullDllName);
1627
1628 if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE)) {
1629 RtlFreeUnicodeString(&FullDllName);
1630 *BaseAddress = Module->BaseAddress;
1631 DPRINT("BaseAddress %x\n", *BaseAddress);
1632 return STATUS_SUCCESS;
1633 }
1634 Entry = Entry->Flink;
1635 }
1636
1637 DPRINT("Failed to find dll %wZ\n", &FullDllName);
1638
1639 RtlFreeUnicodeString(&FullDllName);
1640 *BaseAddress = NULL;
1641 return STATUS_DLL_NOT_FOUND;
1642 }
1643
1644
1645 NTSTATUS STDCALL
1646 LdrGetProcedureAddress (IN PVOID BaseAddress,
1647 IN PANSI_STRING Name,
1648 IN ULONG Ordinal,
1649 OUT PVOID *ProcedureAddress)
1650 {
1651 PIMAGE_EXPORT_DIRECTORY ExportDir;
1652 PUSHORT OrdinalPtr;
1653 PULONG NamePtr;
1654 PULONG AddressPtr;
1655 ULONG i = 0;
1656
1657 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1658 BaseAddress, Name, Ordinal, ProcedureAddress);
1659
1660 /* Get the pointer to the export directory */
1661 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1662 RtlImageDirectoryEntryToData (BaseAddress,
1663 TRUE,
1664 IMAGE_DIRECTORY_ENTRY_EXPORT,
1665 &i);
1666
1667 DPRINT("ExportDir %x i %lu\n", ExportDir, i);
1668
1669 if (!ExportDir || !i || !ProcedureAddress)
1670 {
1671 return STATUS_INVALID_PARAMETER;
1672 }
1673
1674 AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
1675 if (Name && Name->Length)
1676 {
1677 /* by name */
1678 OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
1679 NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
1680 for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
1681 {
1682 if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
1683 {
1684 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
1685 return STATUS_SUCCESS;
1686 }
1687 }
1688 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
1689 }
1690 else
1691 {
1692 /* by ordinal */
1693 Ordinal &= 0x0000FFFF;
1694 if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
1695 {
1696 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
1697 return STATUS_SUCCESS;
1698 }
1699 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
1700 }
1701
1702 return STATUS_PROCEDURE_NOT_FOUND;
1703 }
1704
1705
1706 NTSTATUS STDCALL
1707 LdrShutdownProcess (VOID)
1708 {
1709 PLIST_ENTRY ModuleListHead;
1710 PLIST_ENTRY Entry;
1711 PLDR_MODULE Module;
1712
1713 DPRINT("LdrShutdownProcess() called\n");
1714
1715 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1716
1717 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1718 Entry = ModuleListHead->Blink;
1719
1720 while (Entry != ModuleListHead)
1721 {
1722 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1723
1724 DPRINT(" Unloading %wZ\n",
1725 &Module->BaseDllName);
1726 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1727 // they loaded dynamically, and when the last reference is gone, that lib will
1728 // be detached.
1729 if (Module->EntryPoint != 0 && Module->LoadCount == -1)
1730 {
1731 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1732
1733 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1734 Entrypoint (Module->BaseAddress,
1735 DLL_PROCESS_DETACH,
1736 NULL);
1737 }
1738
1739 Entry = Entry->Blink;
1740 }
1741
1742 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1743
1744 DPRINT("LdrShutdownProcess() done\n");
1745
1746 return STATUS_SUCCESS;
1747 }
1748
1749
1750 NTSTATUS STDCALL
1751 LdrShutdownThread (VOID)
1752 {
1753 PLIST_ENTRY ModuleListHead;
1754 PLIST_ENTRY Entry;
1755 PLDR_MODULE Module;
1756
1757 DPRINT("LdrShutdownThread() called\n");
1758
1759 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1760
1761 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1762 Entry = ModuleListHead->Blink;
1763
1764 while (Entry != ModuleListHead)
1765 {
1766 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1767
1768 DPRINT(" Unloading %wZ\n",
1769 &Module->BaseDllName);
1770
1771 if (Module->EntryPoint != 0)
1772 {
1773 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1774
1775 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1776 Entrypoint (Module->BaseAddress,
1777 DLL_THREAD_DETACH,
1778 NULL);
1779 }
1780
1781 Entry = Entry->Blink;
1782 }
1783
1784 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1785
1786 DPRINT("LdrShutdownThread() done\n");
1787
1788 return STATUS_SUCCESS;
1789 }
1790
1791
1792 /***************************************************************************
1793 * NAME EXPORTED
1794 * LdrQueryProcessModuleInformation
1795 *
1796 * DESCRIPTION
1797 *
1798 * ARGUMENTS
1799 *
1800 * RETURN VALUE
1801 *
1802 * REVISIONS
1803 *
1804 * NOTE
1805 */
1806 NTSTATUS STDCALL
1807 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
1808 IN ULONG Size OPTIONAL,
1809 OUT PULONG ReturnedSize)
1810
1811 {
1812 PLIST_ENTRY ModuleListHead;
1813 PLIST_ENTRY Entry;
1814 PLDR_MODULE Module;
1815 PMODULE_ENTRY ModulePtr = NULL;
1816 NTSTATUS Status = STATUS_SUCCESS;
1817 ULONG UsedSize = sizeof(ULONG);
1818 ANSI_STRING AnsiString;
1819 PCHAR p;
1820
1821 DPRINT("LdrQueryProcessModuleInformation() called\n");
1822
1823 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1824
1825 if (ModuleInformation == NULL || Size == 0)
1826 {
1827 Status = STATUS_INFO_LENGTH_MISMATCH;
1828 }
1829 else
1830 {
1831 ModuleInformation->ModuleCount = 0;
1832 ModulePtr = &ModuleInformation->ModuleEntry[0];
1833 Status = STATUS_SUCCESS;
1834 }
1835
1836 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1837 Entry = ModuleListHead->Flink;
1838
1839 while (Entry != ModuleListHead)
1840 {
1841 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1842
1843 DPRINT(" Module %wZ\n",
1844 &Module->FullDllName);
1845
1846 if (UsedSize > Size)
1847 {
1848 Status = STATUS_INFO_LENGTH_MISMATCH;
1849 }
1850 else if (ModuleInformation != NULL)
1851 {
1852 ModulePtr->Unknown0 = 0; // FIXME: ??
1853 ModulePtr->Unknown1 = 0; // FIXME: ??
1854 ModulePtr->BaseAddress = Module->BaseAddress;
1855 ModulePtr->SizeOfImage = Module->SizeOfImage;
1856 ModulePtr->Flags = Module->Flags;
1857 ModulePtr->Unknown2 = 0; // FIXME: load order index ??
1858 ModulePtr->Unknown3 = 0; // FIXME: ??
1859 ModulePtr->LoadCount = Module->LoadCount;
1860
1861 AnsiString.Length = 0;
1862 AnsiString.MaximumLength = 256;
1863 AnsiString.Buffer = ModulePtr->ModuleName;
1864 RtlUnicodeStringToAnsiString(&AnsiString,
1865 &Module->FullDllName,
1866 FALSE);
1867 p = strrchr(ModulePtr->ModuleName, '\\');
1868 if (p != NULL)
1869 ModulePtr->PathLength = p - ModulePtr->ModuleName + 1;
1870 else
1871 ModulePtr->PathLength = 0;
1872
1873 ModulePtr++;
1874 ModuleInformation->ModuleCount++;
1875 }
1876 UsedSize += sizeof(MODULE_ENTRY);
1877
1878 Entry = Entry->Flink;
1879 }
1880
1881 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1882
1883 if (ReturnedSize != 0)
1884 *ReturnedSize = UsedSize;
1885
1886 DPRINT("LdrQueryProcessModuleInformation() done\n");
1887
1888 return(Status);
1889 }
1890
1891 /* EOF */