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