Fixed problem with handles not being released
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.21 1999/12/20 02:14:37 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <reactos/config.h>
14 #define WIN32_NO_STATUS
15 #define WIN32_NO_PEHDR
16 #include <windows.h>
17 #include <ddk/ntddk.h>
18 #include <pe.h>
19 #include <string.h>
20 #include <internal/string.h>
21 #include <wchar.h>
22 #include <ntdll/ldr.h>
23
24 #ifdef DBG_NTDLL_LDR_UTILS
25 #define NDEBUG
26 #endif
27 #include <ntdll/ntdll.h>
28
29 /* FUNCTIONS *****************************************************************/
30
31
32 /* Type for a DLL's entry point */
33 typedef
34 WINBOOL
35 STDCALL
36 (* PDLLMAIN_FUNC) (
37 HANDLE hInst,
38 ULONG ul_reason_for_call,
39 LPVOID lpReserved
40 );
41
42 static
43 NTSTATUS
44 LdrFindDll (PDLL* Dll,PCHAR Name);
45
46 /**********************************************************************
47 * NAME
48 * LdrLoadDll
49 *
50 * DESCRIPTION
51 *
52 * ARGUMENTS
53 *
54 * RETURN VALUE
55 *
56 * REVISIONS
57 *
58 * NOTE
59 *
60 */
61
62 NTSTATUS LdrLoadDll (PDLL* Dll,
63 PCHAR Name)
64 {
65 char fqname [255] = "\\??\\C:\\reactos\\system32\\";
66 ANSI_STRING AnsiString;
67 UNICODE_STRING UnicodeString;
68 OBJECT_ATTRIBUTES FileObjectAttributes;
69 char BlockBuffer [1024];
70 PIMAGE_DOS_HEADER DosHeader;
71 NTSTATUS Status;
72 PIMAGE_NT_HEADERS NTHeaders;
73 PEPFUNC DllStartupAddr;
74 ULONG ImageSize;
75 ULONG InitialViewSize;
76 PVOID ImageBase;
77 HANDLE FileHandle;
78 HANDLE SectionHandle;
79 PDLLMAIN_FUNC Entrypoint;
80
81 if ( Dll == NULL )
82 return -1;
83
84 if ( Name == NULL ) {
85 *Dll = &LdrDllListHead;
86 return STATUS_SUCCESS;
87 }
88
89 DPRINT("LdrLoadDll(Base %x, Name \"%s\")\n", Dll, Name);
90
91 /*
92 * Build the DLL's absolute name
93 */
94
95 if ( strncmp(Name,"\\??\\",3) != 0 ) {
96
97 strcat(fqname, Name);
98 }
99 else
100 strncpy(fqname, Name, 256);
101
102 DPRINT("fqname \"%s\"\n", fqname);
103 /*
104 * Open the DLL's image file.
105 */
106
107 if (LdrFindDll(Dll, Name) == STATUS_SUCCESS)
108 return STATUS_SUCCESS;
109
110
111 RtlInitAnsiString(
112 & AnsiString,
113 fqname
114 );
115 RtlAnsiStringToUnicodeString(
116 & UnicodeString,
117 & AnsiString,
118 TRUE
119 );
120
121 InitializeObjectAttributes(
122 & FileObjectAttributes,
123 & UnicodeString,
124 0,
125 NULL,
126 NULL
127 );
128
129 DPRINT("Opening dll \"%s\"\n", fqname);
130
131 Status = ZwOpenFile(
132 & FileHandle,
133 FILE_ALL_ACCESS,
134 & FileObjectAttributes,
135 NULL,
136 0,
137 0
138 );
139 if (!NT_SUCCESS(Status))
140 {
141 dprintf("Dll open of %s failed: Status = 0x%08x\n",
142 fqname, Status);
143 return Status;
144 }
145 Status = ZwReadFile(
146 FileHandle,
147 0,
148 0,
149 0,
150 0,
151 BlockBuffer,
152 sizeof BlockBuffer,
153 0,
154 0
155 );
156 if (!NT_SUCCESS(Status))
157 {
158 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
159 ZwClose(FileHandle);
160 return Status;
161 }
162 /*
163 * Overlay DOS and NT headers structures to the
164 * buffer with DLL's header raw data.
165 */
166 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
167 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
168 /*
169 * Check it is a PE image file.
170 */
171 if ( (DosHeader->e_magic != IMAGE_DOS_MAGIC)
172 || (DosHeader->e_lfanew == 0L)
173 // || (*(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
174 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC)
175 )
176 {
177 DPRINT("NTDLL format invalid\n");
178 ZwClose(FileHandle);
179
180 return STATUS_UNSUCCESSFUL;
181 }
182
183 // NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
184 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
185 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
186
187 DPRINT("ImageBase 0x%08x\n", ImageBase);
188
189 DllStartupAddr =
190 (PEPFUNC) (
191 ImageBase
192 + NTHeaders->OptionalHeader.AddressOfEntryPoint
193 );
194 /*
195 * Create a section for NTDLL.
196 */
197 Status = ZwCreateSection(
198 & SectionHandle,
199 SECTION_ALL_ACCESS,
200 NULL,
201 NULL,
202 PAGE_READWRITE,
203 MEM_COMMIT,
204 FileHandle
205 );
206 if (!NT_SUCCESS(Status))
207 {
208 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
209 ZwClose(FileHandle);
210 return Status;
211 }
212 /*
213 * Map the NTDLL into the process.
214 */
215 InitialViewSize =
216 DosHeader->e_lfanew
217 + sizeof (IMAGE_NT_HEADERS)
218 + sizeof (IMAGE_SECTION_HEADER) * NTHeaders->FileHeader.NumberOfSections;
219 Status = ZwMapViewOfSection(
220 SectionHandle,
221 NtCurrentProcess(),
222 (PVOID*)&ImageBase,
223 0,
224 InitialViewSize,
225 NULL,
226 &InitialViewSize,
227 0,
228 MEM_COMMIT,
229 PAGE_READWRITE
230 );
231 if (!NT_SUCCESS(Status))
232 {
233 dprintf("NTDLL.LDR: map view of section failed (Status %x)\n",
234 Status);
235 ZwClose(FileHandle);
236 return(Status);
237 }
238 ZwClose(FileHandle);
239
240 (*Dll) = RtlAllocateHeap(
241 RtlGetProcessHeap(),
242 0,
243 sizeof (DLL)
244 );
245 (*Dll)->Headers = NTHeaders;
246 (*Dll)->BaseAddress = (PVOID)ImageBase;
247 (*Dll)->Next = LdrDllListHead.Next;
248 (*Dll)->Prev = & LdrDllListHead;
249 (*Dll)->ReferenceCount = 1;
250 LdrDllListHead.Next->Prev = (*Dll);
251 LdrDllListHead.Next = (*Dll);
252
253
254 if (((*Dll)->Headers->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
255 IMAGE_FILE_DLL)
256 {
257
258 Entrypoint =
259 (PDLLMAIN_FUNC) LdrPEStartup(
260 ImageBase,
261 SectionHandle
262 );
263 if (Entrypoint != NULL)
264 {
265 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
266 if (FALSE == Entrypoint(
267 Dll,
268 DLL_PROCESS_ATTACH,
269 NULL
270 ))
271 {
272 DPRINT("NTDLL.LDR: DLL \"%s\" failed to initialize\n", fqname);
273 /* FIXME: should clean up and fail */
274 }
275 else
276 {
277 DPRINT("NTDLL.LDR: DLL \"%s\" initialized successfully\n", fqname);
278 }
279 }
280 else
281 {
282 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%s\"\n", fqname);
283 }
284 }
285 return STATUS_SUCCESS;
286 }
287
288
289 /**********************************************************************
290 * NAME LOCAL
291 * LdrFindDll
292 *
293 * DESCRIPTION
294 *
295 * ARGUMENTS
296 *
297 * RETURN VALUE
298 *
299 * REVISIONS
300 *
301 * NOTE
302 *
303 */
304 static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name)
305 {
306 PIMAGE_EXPORT_DIRECTORY ExportDir;
307 DLL * current;
308 PIMAGE_OPTIONAL_HEADER OptionalHeader;
309
310
311 DPRINT("NTDLL.LdrFindDll(Name %s)\n", Name);
312
313 current = & LdrDllListHead;
314
315 // NULL is the current process
316
317 if ( Name == NULL )
318 {
319 *Dll = current;
320 return STATUS_SUCCESS;
321 }
322
323 do
324 {
325 OptionalHeader = & current->Headers->OptionalHeader;
326 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
327 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
328 .VirtualAddress;
329 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
330 ((ULONG)ExportDir + (ULONG)current->BaseAddress);
331
332 DPRINT("Scanning %x %x %x\n",ExportDir->Name,
333 current->BaseAddress,
334 (ExportDir->Name + current->BaseAddress));
335 DPRINT("Scanning %s %s\n",
336 ExportDir->Name + current->BaseAddress, Name);
337
338 if (_stricmp(ExportDir->Name + current->BaseAddress, Name) == 0)
339 {
340 *Dll = current;
341 current->ReferenceCount++;
342 return STATUS_SUCCESS;
343 }
344
345 current = current->Next;
346
347 } while (current != & LdrDllListHead);
348
349 DPRINT("Failed to find dll %s\n",Name);
350
351 return -1;
352 }
353
354
355 /**********************************************************************
356 * NAME
357 * LdrMapSections
358 *
359 * DESCRIPTION
360 *
361 * ARGUMENTS
362 *
363 * RETURN VALUE
364 *
365 * REVISIONS
366 *
367 * NOTE
368 *
369 */
370 NTSTATUS LdrMapSections(HANDLE ProcessHandle,
371 PVOID ImageBase,
372 HANDLE SectionHandle,
373 PIMAGE_NT_HEADERS NTHeaders)
374 {
375 ULONG i;
376 NTSTATUS Status;
377
378
379 for (i = 0; (i < NTHeaders->FileHeader.NumberOfSections); i++)
380 {
381 PIMAGE_SECTION_HEADER Sections;
382 LARGE_INTEGER Offset;
383 ULONG Base;
384 ULONG Size;
385
386 Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(ImageBase);
387 Base = (ULONG) (Sections[i].VirtualAddress + ImageBase);
388 Offset.u.LowPart = Sections[i].PointerToRawData;
389 Offset.u.HighPart = 0;
390
391 Size = max(Sections[i].Misc.VirtualSize, Sections[i].SizeOfRawData);
392
393 DPRINT("Mapping section %d offset %x base %x size %x\n",
394 i, Offset.u.LowPart, Base, Sections[i].Misc.VirtualSize);
395 DPRINT("Size %x\n", Sections[i].SizeOfRawData);
396
397 Status = ZwMapViewOfSection(SectionHandle,
398 ProcessHandle,
399 (PVOID*)&Base,
400 0,
401 Size,
402 &Offset,
403 (PULONG)&Size,
404 0,
405 MEM_COMMIT,
406 PAGE_READWRITE);
407 if (!NT_SUCCESS(Status))
408 {
409 DPRINT("Failed to map section");
410 return(Status);
411 }
412 }
413 return STATUS_SUCCESS;
414 }
415
416
417 /**********************************************************************
418 * NAME LOCAL
419 * LdrGetExportByOrdinal
420 *
421 * DESCRIPTION
422 *
423 * ARGUMENTS
424 *
425 * RETURN VALUE
426 *
427 * REVISIONS
428 *
429 * NOTE
430 *
431 */
432
433 PVOID
434 LdrGetExportByOrdinal (
435 PDLL Module,
436 ULONG Ordinal
437 )
438 {
439 PIMAGE_EXPORT_DIRECTORY ExportDir;
440 PDWORD * ExFunctions;
441 USHORT * ExOrdinals;
442
443 ExportDir = (
444 Module->BaseAddress
445 + (Module->Headers->OptionalHeader
446 .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
447 .VirtualAddress
448 )
449 );
450
451 ExOrdinals = (USHORT *)
452 RVA(
453 Module->BaseAddress,
454 ExportDir->AddressOfNameOrdinals
455 );
456 ExFunctions = (PDWORD *)
457 RVA(
458 Module->BaseAddress,
459 ExportDir->AddressOfFunctions
460 );
461 dprintf(
462 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
463 Ordinal,
464 ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
465 );
466 return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
467 }
468
469
470 /**********************************************************************
471 * NAME LOCAL
472 * LdrGetExportByName
473 *
474 * DESCRIPTION
475 *
476 * ARGUMENTS
477 *
478 * RETURN VALUE
479 *
480 * REVISIONS
481 *
482 * NOTE
483 *
484 */
485
486 PVOID
487 LdrGetExportByName (
488 PDLL Module,
489 PUCHAR SymbolName
490 )
491 {
492 PIMAGE_EXPORT_DIRECTORY ExportDir;
493 PDWORD * ExFunctions;
494 PDWORD * ExNames;
495 USHORT * ExOrdinals;
496 ULONG i;
497 PVOID ExName;
498 ULONG Ordinal;
499
500 // DPRINT(
501 // "LdrFindExport(Module %x, SymbolName %s)\n",
502 // Module,
503 // SymbolName
504 // );
505
506 ExportDir = (
507 Module->BaseAddress
508 + (Module->Headers->OptionalHeader
509 .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
510 .VirtualAddress
511 )
512 );
513 /*
514 * Get header pointers
515 */
516 ExNames = (PDWORD *)
517 RVA(
518 Module->BaseAddress,
519 ExportDir->AddressOfNames
520 );
521 ExOrdinals = (USHORT *)
522 RVA(
523 Module->BaseAddress,
524 ExportDir->AddressOfNameOrdinals
525 );
526 ExFunctions = (PDWORD *)
527 RVA(
528 Module->BaseAddress,
529 ExportDir->AddressOfFunctions
530 );
531 for ( i = 0;
532 ( i < ExportDir->NumberOfFunctions);
533 i++
534 )
535 {
536 ExName = RVA(
537 Module->BaseAddress,
538 ExNames[i]
539 );
540 // DPRINT(
541 // "Comparing '%s' '%s'\n",
542 // ExName,
543 // SymbolName
544 // );
545 if (strcmp(ExName,SymbolName) == 0)
546 {
547 Ordinal = ExOrdinals[i];
548 return(RVA(Module->BaseAddress, ExFunctions[Ordinal]));
549 }
550 }
551
552 dprintf("LdrGetExportByName() = failed to find %s\n",SymbolName);
553
554 return NULL;
555 }
556
557
558 /**********************************************************************
559 * NAME LOCAL
560 * LdrPerformRelocations
561 *
562 * DESCRIPTION
563 * Relocate a DLL's memory image.
564 *
565 * ARGUMENTS
566 *
567 * RETURN VALUE
568 *
569 * REVISIONS
570 *
571 * NOTE
572 *
573 */
574 static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders,
575 PVOID ImageBase)
576 {
577 USHORT NumberOfEntries;
578 PUSHORT pValue16;
579 ULONG RelocationRVA;
580 ULONG Delta32;
581 ULONG Offset;
582 PULONG pValue32;
583 PRELOCATION_DIRECTORY RelocationDir;
584 PRELOCATION_ENTRY RelocationBlock;
585 int i;
586
587
588 RelocationRVA = NTHeaders->OptionalHeader
589 .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
590 .VirtualAddress;
591
592 if (RelocationRVA)
593 {
594 RelocationDir = (PRELOCATION_DIRECTORY)
595 ((PCHAR)ImageBase + RelocationRVA);
596
597 while (RelocationDir->SizeOfBlock)
598 {
599 Delta32 = (ULONG)(ImageBase -
600 NTHeaders->OptionalHeader.ImageBase);
601 RelocationBlock = (PRELOCATION_ENTRY) (
602 RelocationRVA
603 + ImageBase
604 + sizeof (RELOCATION_DIRECTORY)
605 );
606 NumberOfEntries = (
607 RelocationDir->SizeOfBlock
608 - sizeof (RELOCATION_DIRECTORY)
609 )
610 / sizeof (RELOCATION_ENTRY);
611
612 for ( i = 0;
613 (i < NumberOfEntries);
614 i++
615 )
616 {
617 Offset = (
618 RelocationBlock[i].TypeOffset
619 & 0xfff
620 )
621 + RelocationDir->VirtualAddress;
622 /*
623 * What kind of relocations should we perform
624 * for the current entry?
625 */
626 switch (RelocationBlock[i].TypeOffset >> 12)
627 {
628 case TYPE_RELOC_ABSOLUTE:
629 break;
630
631 case TYPE_RELOC_HIGH:
632 pValue16 = (PUSHORT) (ImageBase + Offset);
633 *pValue16 += Delta32 >> 16;
634 break;
635
636 case TYPE_RELOC_LOW:
637 pValue16 = (PUSHORT)(ImageBase + Offset);
638 *pValue16 += Delta32 & 0xffff;
639 break;
640
641 case TYPE_RELOC_HIGHLOW:
642 pValue32 = (PULONG) (ImageBase + Offset);
643 *pValue32 += Delta32;
644 break;
645
646 case TYPE_RELOC_HIGHADJ:
647 /* FIXME: do the highadjust fixup */
648 DPRINT(
649 "TYPE_RELOC_HIGHADJ fixup not implemented"
650 ", sorry\n"
651 );
652 return(STATUS_UNSUCCESSFUL);
653
654 default:
655 DPRINT("unexpected fixup type\n");
656 return STATUS_UNSUCCESSFUL;
657 }
658 }
659 RelocationRVA += RelocationDir->SizeOfBlock;
660 RelocationDir = (PRELOCATION_DIRECTORY) (
661 ImageBase
662 + RelocationRVA
663 );
664 }
665 }
666 return STATUS_SUCCESS;
667 }
668
669
670 /**********************************************************************
671 * NAME LOCAL
672 * LdrFixupImports
673 *
674 * DESCRIPTION
675 * Compute the entry point for every symbol the DLL imports
676 * from other modules.
677 *
678 * ARGUMENTS
679 *
680 * RETURN VALUE
681 *
682 * REVISIONS
683 *
684 * NOTE
685 *
686 */
687 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
688 PVOID ImageBase)
689 {
690 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
691 ULONG Ordinal;
692 PDLL Module;
693 NTSTATUS Status;
694
695 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
696 ImageBase);
697
698 /*
699 * Process each import module.
700 */
701 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
702 ImageBase + NTHeaders->OptionalHeader
703 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
704 .VirtualAddress);
705 DPRINT1("ImportModuleDirectory %x\n", ImportModuleDirectory);
706 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
707
708 while (ImportModuleDirectory->dwRVAModuleName)
709 {
710 PVOID * ImportAddressList;
711 PULONG FunctionNameList;
712 DWORD pName;
713 PWORD pHint;
714
715 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
716 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
717
718 Status = LdrLoadDll(&Module,
719 (PCHAR)(ImageBase
720 +ImportModuleDirectory->dwRVAModuleName));
721 if (!NT_SUCCESS(Status))
722 {
723 return Status;
724 }
725 /*
726 * Get the import address list.
727 */
728 ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
729 + ImportModuleDirectory->dwRVAFunctionAddressList);
730
731 /*
732 * Get the list of functions to import.
733 */
734 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
735 {
736 FunctionNameList = (PULONG) (
737 ImageBase
738 + ImportModuleDirectory->dwRVAFunctionNameList
739 );
740 }
741 else
742 {
743 FunctionNameList = (PULONG) (
744 ImageBase
745 + ImportModuleDirectory->dwRVAFunctionAddressList
746 );
747 }
748 /*
749 * Walk through function list and fixup addresses.
750 */
751 while (*FunctionNameList != 0L)
752 {
753 if ((*FunctionNameList) & 0x80000000)
754 {
755 Ordinal = (*FunctionNameList) & 0x7fffffff;
756 *ImportAddressList =
757 LdrGetExportByOrdinal(
758 Module,
759 Ordinal
760 );
761 }
762 else
763 {
764 pName = (DWORD) (
765 ImageBase
766 + *FunctionNameList
767 + 2
768 );
769 pHint = (PWORD) (
770 ImageBase
771 + *FunctionNameList
772 );
773
774 *ImportAddressList =
775 LdrGetExportByName(
776 Module,
777 (PUCHAR) pName
778 );
779 if ((*ImportAddressList) == NULL)
780 {
781 dprintf("Failed to import %s\n", pName);
782 return STATUS_UNSUCCESSFUL;
783 }
784 }
785 ImportAddressList++;
786 FunctionNameList++;
787 }
788 ImportModuleDirectory++;
789 }
790 return STATUS_SUCCESS;
791 }
792
793
794 /**********************************************************************
795 * NAME
796 * LdrPEStartup
797 *
798 * DESCRIPTION
799 * 1. Map the DLL's sections into memory.
800 * 2. Relocate, if needed the DLL.
801 * 3. Fixup any imported symbol.
802 * 4. Compute the DLL's entry point.
803 *
804 * ARGUMENTS
805 * ImageBase
806 * Address at which the DLL's image
807 * is loaded.
808 *
809 * SectionHandle
810 * Handle of the section that contains
811 * the DLL's image.
812 *
813 * RETURN VALUE
814 * NULL on error; otherwise the entry point
815 * to call for initializing the DLL.
816 *
817 * REVISIONS
818 *
819 * NOTE
820 *
821 */
822 PEPFUNC LdrPEStartup (PVOID ImageBase,
823 HANDLE SectionHandle)
824 {
825 NTSTATUS Status;
826 PEPFUNC EntryPoint;
827 PIMAGE_DOS_HEADER DosHeader;
828 PIMAGE_NT_HEADERS NTHeaders;
829
830
831 /*
832 * Overlay DOS and WNT headers structures
833 * to the DLL's image.
834 */
835 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
836 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
837
838 /*
839 * Initialize image sections.
840 */
841 LdrMapSections(NtCurrentProcess(),
842 ImageBase,
843 SectionHandle,
844 NTHeaders);
845
846 /*
847 * If the base address is different from the
848 * one the DLL is actually loaded, perform any
849 * relocation.
850 */
851 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
852 {
853 Status = LdrPerformRelocations(NTHeaders, ImageBase);
854 if (!NT_SUCCESS(Status))
855 {
856 dprintf("LdrPerformRelocations() failed\n");
857 return NULL;
858 }
859 }
860
861 /*
862 * If the DLL's imports symbols from other
863 * modules, fixup the imported calls entry points.
864 */
865 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
866 .VirtualAddress != 0)
867 {
868 DPRINT("About to fixup imports\n");
869 Status = LdrFixupImports(NTHeaders, ImageBase);
870 if (!NT_SUCCESS(Status))
871 {
872 dprintf("LdrFixupImports() failed\n");
873 return NULL;
874 }
875 }
876
877 /*
878 * Compute the DLL's entry point's address.
879 */
880 EntryPoint = (PEPFUNC) (ImageBase
881 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
882 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
883 return EntryPoint;
884 }
885
886 NTSTATUS LdrUnloadDll(PDLL Dll)
887 {
888 PDLLMAIN_FUNC Entrypoint;
889 NTSTATUS Status;
890
891 if ( Dll == NULL || Dll == &LdrDllListHead )
892 return -1;
893
894
895 if ( Dll->ReferenceCount > 1 )
896 {
897 Dll->ReferenceCount--;
898 return STATUS_SUCCESS;
899 }
900
901 if (( Dll->Headers->FileHeader.Characteristics & IMAGE_FILE_DLL ) == IMAGE_FILE_DLL ) {
902
903 Entrypoint = (PDLLMAIN_FUNC) LdrPEStartup(Dll->BaseAddress,
904 Dll->SectionHandle);
905 if (Entrypoint != NULL)
906 {
907 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
908 if (FALSE == Entrypoint(Dll,
909 DLL_PROCESS_DETACH,
910 NULL))
911 {
912 DPRINT("NTDLL.LDR: DLL failed to detach\n");
913 return -1;
914 }
915 else
916 {
917 DPRINT("NTDLL.LDR: DLL detached successfully\n");
918 }
919 }
920 else
921 {
922 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
923 }
924
925 }
926 Status = ZwUnmapViewOfSection(NtCurrentProcess(),
927 Dll->BaseAddress);
928
929 ZwClose(Dll->SectionHandle);
930
931 return Status;
932 }
933
934 static IMAGE_RESOURCE_DIRECTORY_ENTRY * LdrGetNextEntry(IMAGE_RESOURCE_DIRECTORY *ResourceDir, LPCWSTR ResourceName, ULONG Offset)
935 {
936
937
938 WORD NumberOfNamedEntries;
939 WORD NumberOfIdEntries;
940 WORD Entries;
941 ULONG Length;
942
943 if ( (((ULONG)ResourceDir) & 0xF0000000) != 0 ) {
944 return (IMAGE_RESOURCE_DIRECTORY_ENTRY *)NULL;
945 }
946
947
948 NumberOfIdEntries = ResourceDir->NumberOfIdEntries;
949 NumberOfNamedEntries = ResourceDir->NumberOfNamedEntries;
950 if ( ( NumberOfIdEntries + NumberOfNamedEntries) == 0) {
951 return &ResourceDir->DirectoryEntries[0];
952 }
953
954 if ( HIWORD(ResourceName) != 0 ) {
955 Length = wcslen(ResourceName);
956 Entries = ResourceDir->NumberOfNamedEntries;
957 do {
958 IMAGE_RESOURCE_DIR_STRING_U *DirString;
959
960 Entries--;
961 DirString = (IMAGE_RESOURCE_DIR_STRING_U *)(((ULONG)ResourceDir->DirectoryEntries[Entries].Name & (~0xF0000000)) + Offset);
962
963 if ( DirString->Length == Length && wcscmp(DirString->NameString, ResourceName ) == 0 ) {
964 return &ResourceDir->DirectoryEntries[Entries];
965 }
966 } while (Entries > 0);
967 }
968 else {
969 Entries = ResourceDir->NumberOfIdEntries + ResourceDir->NumberOfNamedEntries;
970 do {
971 Entries--;
972
973 if ( (LPWSTR)ResourceDir->DirectoryEntries[Entries].Name == ResourceName ) {
974 return &ResourceDir->DirectoryEntries[Entries];
975 }
976 } while (Entries > ResourceDir->NumberOfNamedEntries);
977
978 }
979
980
981
982 return NULL;
983
984 }
985
986
987
988 NTSTATUS LdrFindResource_U(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY **ResourceDataEntry,LPCWSTR ResourceName, ULONG ResourceType,ULONG Language)
989 {
990 IMAGE_RESOURCE_DIRECTORY *ResourceTypeDir;
991 IMAGE_RESOURCE_DIRECTORY *ResourceNameDir;
992 IMAGE_RESOURCE_DIRECTORY *ResourceLangDir;
993
994 IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceTypeDirEntry;
995 IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceNameDirEntry;
996 IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceLangDirEntry;
997
998 PIMAGE_OPTIONAL_HEADER OptionalHeader;
999
1000
1001
1002 ULONG Offset;
1003
1004 OptionalHeader = & Dll->Headers->OptionalHeader;
1005 ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY)
1006 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
1007 ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY)
1008 ((ULONG)ResourceTypeDir + (ULONG)Dll->BaseAddress);
1009
1010
1011 Offset = (ULONG)ResourceTypeDir;
1012
1013 ResourceTypeDirEntry = LdrGetNextEntry(ResourceTypeDir, (LPWSTR)ResourceType, Offset);
1014
1015 if ( ResourceTypeDirEntry != NULL ) {
1016 ResourceNameDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceTypeDirEntry->OffsetToData & (~0xF0000000)) + Offset);
1017
1018 ResourceNameDirEntry = LdrGetNextEntry(ResourceNameDir, ResourceName, Offset);
1019
1020 if ( ResourceNameDirEntry != NULL ) {
1021
1022 ResourceLangDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceNameDirEntry->OffsetToData & (~0xF0000000)) + Offset);
1023
1024 ResourceLangDirEntry = LdrGetNextEntry(ResourceLangDir, (LPWSTR)Language, Offset);
1025 if ( ResourceLangDirEntry != NULL ) {
1026
1027 *ResourceDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)(ResourceLangDirEntry->OffsetToData +
1028 (ULONG)ResourceTypeDir);
1029 return STATUS_SUCCESS;
1030 }
1031 else {
1032 return -1;
1033 }
1034 }
1035 else {
1036 return -1;
1037 }
1038
1039 }
1040
1041 return -1;
1042
1043 }
1044
1045 NTSTATUS LdrAccessResource(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry, void **Data)
1046 {
1047 PIMAGE_SECTION_HEADER Sections;
1048 int i;
1049
1050 if ( Data == NULL )
1051 return -1;
1052
1053 if ( ResourceDataEntry == NULL )
1054 return -1;
1055
1056 if ( Dll == NULL )
1057 return -1;
1058
1059 Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(Dll->BaseAddress);
1060
1061 for ( i = 0;
1062 (i < Dll->Headers->FileHeader.NumberOfSections);
1063 i++
1064 )
1065 {
1066 if (Sections[i].VirtualAddress <= ResourceDataEntry->OffsetToData
1067 && Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize > ResourceDataEntry->OffsetToData )
1068 break;
1069 }
1070
1071 if ( i == Dll->Headers->FileHeader.NumberOfSections ) {
1072 *Data = NULL;
1073 return -1;
1074 }
1075
1076 *Data = (void *)(((ULONG)Dll->BaseAddress + ResourceDataEntry->OffsetToData - (ULONG)Sections[i].VirtualAddress) +
1077 (ULONG)Sections[i].PointerToRawData);
1078
1079
1080 return STATUS_SUCCESS;
1081 }
1082
1083 /* EOF */