1 /* $Id: utils.c,v 1.70 2003/07/27 14:00:04 hbirr Exp $
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)
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
18 /* INCLUDES *****************************************************************/
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
29 #ifdef DBG_NTDLL_LDR_UTILS
32 #include <ntdll/ntdll.h>
34 /* GLOBALS *******************************************************************/
36 static HANDLE LdrpKnownDllsDirHandle
= NULL
;
37 static UNICODE_STRING LdrpKnownDllPath
= {0, 0, NULL
};
40 /* PROTOTYPES ****************************************************************/
42 static NTSTATUS
LdrFindEntryForName(PUNICODE_STRING Name
, PLDR_MODULE
*Module
);
43 static PVOID
LdrFixupForward(PCHAR ForwardName
);
44 static PVOID
LdrGetExportByName(PVOID BaseAddress
, PUCHAR SymbolName
, USHORT Hint
);
47 /* FUNCTIONS *****************************************************************/
53 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule
)
70 OBJECT_ATTRIBUTES ObjectAttributes
;
71 UNICODE_STRING LinkTarget
;
77 DPRINT("LdrpInitLoader() called\n");
79 /* Get handle to the 'KnownDlls' directory */
80 RtlInitUnicodeString(&Name
,
82 InitializeObjectAttributes(&ObjectAttributes
,
87 Status
= NtOpenDirectoryObject(&LdrpKnownDllsDirHandle
,
88 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
90 if (!NT_SUCCESS(Status
))
92 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status
);
93 LdrpKnownDllsDirHandle
= NULL
;
97 /* Allocate target name string */
98 LinkTarget
.Length
= 0;
99 LinkTarget
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
100 LinkTarget
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
102 MAX_PATH
* sizeof(WCHAR
));
103 if (LinkTarget
.Buffer
== NULL
)
105 NtClose(LdrpKnownDllsDirHandle
);
106 LdrpKnownDllsDirHandle
= NULL
;
110 RtlInitUnicodeString(&Name
,
112 InitializeObjectAttributes(&ObjectAttributes
,
114 OBJ_CASE_INSENSITIVE
| OBJ_OPENLINK
,
115 LdrpKnownDllsDirHandle
,
117 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
118 SYMBOLIC_LINK_ALL_ACCESS
,
120 if (!NT_SUCCESS(Status
))
122 RtlFreeUnicodeString(&LinkTarget
);
123 NtClose(LdrpKnownDllsDirHandle
);
124 LdrpKnownDllsDirHandle
= NULL
;
128 Status
= NtQuerySymbolicLinkObject(LinkHandle
,
132 if (!NT_SUCCESS(Status
))
134 RtlFreeUnicodeString(&LinkTarget
);
135 NtClose(LdrpKnownDllsDirHandle
);
136 LdrpKnownDllsDirHandle
= NULL
;
139 RtlCreateUnicodeString(&LdrpKnownDllPath
,
142 RtlFreeUnicodeString(&LinkTarget
);
144 DPRINT("LdrpInitLoader() done\n");
148 /***************************************************************************
153 * Adjusts the name of a dll to a fully qualified name.
156 * FullDllName: Pointer to caller supplied storage for the fully
157 * qualified dll name.
158 * DllName: Pointer to the dll name.
159 * BaseName: TRUE: Only the file name is passed to FullDllName
160 * FALSE: The full path is preserved in FullDllName
168 * A given path is not affected by the adjustment, but the file
170 * ntdll --> ntdll.dll
172 * ntdll.xyz --> ntdll.xyz
176 LdrAdjustDllName (PUNICODE_STRING FullDllName
,
177 PUNICODE_STRING DllName
,
180 WCHAR Buffer
[MAX_PATH
];
185 Length
= DllName
->Length
/ sizeof(WCHAR
);
187 if (BaseName
== TRUE
)
189 /* get the base dll name */
190 Pointer
= DllName
->Buffer
+ Length
;
197 while (Pointer
>= DllName
->Buffer
&& *Pointer
!= L
'\\' && *Pointer
!= L
'/');
200 Length
= Extension
- Pointer
;
201 memmove (Buffer
, Pointer
, Length
* sizeof(WCHAR
));
202 Buffer
[Length
] = L
'\0';
206 /* get the full dll name */
207 memmove (Buffer
, DllName
->Buffer
, DllName
->Length
);
208 Buffer
[DllName
->Length
/ sizeof(WCHAR
)] = L
'\0';
211 /* Build the DLL's absolute name */
212 Extension
= wcsrchr (Buffer
, L
'.');
213 if ((Extension
!= NULL
) && (*Extension
== L
'.'))
215 /* with extension - remove dot if it's the last character */
216 if (Buffer
[Length
- 1] == L
'.')
222 /* name without extension - assume that it is .dll */
223 memmove (Buffer
+ Length
, L
".dll", 10);
226 RtlCreateUnicodeString(FullDllName
, Buffer
);
230 LdrAddModuleEntry(PVOID ImageBase
,
231 PIMAGE_NT_HEADERS NTHeaders
,
235 Module
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE
));
237 memset(Module
, 0, sizeof(LDR_MODULE
));
238 Module
->BaseAddress
= (PVOID
)ImageBase
;
239 Module
->EntryPoint
= NTHeaders
->OptionalHeader
.AddressOfEntryPoint
;
240 if (Module
->EntryPoint
!= 0)
241 Module
->EntryPoint
+= (ULONG
)Module
->BaseAddress
;
242 Module
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
243 if (NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
245 /* loading while app is running */
246 Module
->LoadCount
= 1;
249 * loading while app is initializing
250 * dll must not be unloaded
252 Module
->LoadCount
= -1;
255 Module
->TlsIndex
= 0;
256 Module
->CheckSum
= NTHeaders
->OptionalHeader
.CheckSum
;
257 Module
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
259 RtlCreateUnicodeString (&Module
->FullDllName
,
261 RtlCreateUnicodeString (&Module
->BaseDllName
,
262 wcsrchr(FullDosName
, L
'\\') + 1);
263 DPRINT ("BaseDllName %wZ\n", &Module
->BaseDllName
);
265 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
266 InsertTailList(&NtCurrentPeb()->Ldr
->InLoadOrderModuleList
,
267 &Module
->InLoadOrderModuleList
);
268 InsertTailList(&NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
,
269 &Module
->InInitializationOrderModuleList
);
270 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
277 LdrpMapKnownDll(IN PUNICODE_STRING DllName
,
278 OUT PUNICODE_STRING FullDosName
,
279 OUT PHANDLE SectionHandle
)
281 OBJECT_ATTRIBUTES ObjectAttributes
;
282 UNICODE_STRING ObjectDirName
;
285 DPRINT("LdrpMapKnownDll() called\n");
287 if (LdrpKnownDllsDirHandle
== NULL
)
289 DPRINT("Invalid 'KnownDlls' directory\n");
290 return STATUS_UNSUCCESSFUL
;
293 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath
);
295 InitializeObjectAttributes(&ObjectAttributes
,
297 OBJ_CASE_INSENSITIVE
,
298 LdrpKnownDllsDirHandle
,
300 Status
= NtOpenSection(SectionHandle
,
301 SECTION_MAP_READ
| SECTION_MAP_WRITE
| SECTION_MAP_EXECUTE
,
303 if (!NT_SUCCESS(Status
))
305 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName
, Status
);
309 FullDosName
->Length
= LdrpKnownDllPath
.Length
+ DllName
->Length
+ sizeof(WCHAR
);
310 FullDosName
->MaximumLength
= FullDosName
->Length
+ sizeof(WCHAR
);
311 FullDosName
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
313 FullDosName
->MaximumLength
);
314 if (FullDosName
->Buffer
== NULL
)
316 FullDosName
->Length
= 0;
317 FullDosName
->MaximumLength
= 0;
318 return STATUS_SUCCESS
;
321 wcscpy(FullDosName
->Buffer
, LdrpKnownDllPath
.Buffer
);
322 wcscat(FullDosName
->Buffer
, L
"\\");
323 wcscat(FullDosName
->Buffer
, DllName
->Buffer
);
325 DPRINT("FullDosName '%wZ'\n", FullDosName
);
327 DPRINT("LdrpMapKnownDll() done\n");
329 return STATUS_SUCCESS
;
334 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL
,
335 IN PUNICODE_STRING DllName
,
336 OUT PUNICODE_STRING FullDosName
,
337 OUT PHANDLE SectionHandle
)
339 WCHAR SearchPathBuffer
[MAX_PATH
];
340 WCHAR DosName
[MAX_PATH
];
341 UNICODE_STRING FullNtFileName
;
342 OBJECT_ATTRIBUTES FileObjectAttributes
;
344 char BlockBuffer
[1024];
345 PIMAGE_DOS_HEADER DosHeader
;
346 PIMAGE_NT_HEADERS NTHeaders
;
351 DPRINT("LdrpMapDllImageFile() called\n");
353 if (SearchPath
== NULL
)
355 SearchPath
= SearchPathBuffer
;
356 wcscpy (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
357 wcscat (SearchPathBuffer
, L
"\\system32;");
358 wcscat (SearchPathBuffer
, SharedUserData
->NtSystemRoot
);
359 wcscat (SearchPathBuffer
, L
";.");
362 DPRINT("SearchPath %S\n", SearchPath
);
364 if (RtlDosSearchPath_U (SearchPath
,
370 return STATUS_DLL_NOT_FOUND
;
372 DPRINT("DosName %S\n", DosName
);
374 if (!RtlDosPathNameToNtPathName_U (DosName
,
378 return STATUS_DLL_NOT_FOUND
;
380 DPRINT("FullNtFileName %wZ\n", &FullNtFileName
);
382 InitializeObjectAttributes(&FileObjectAttributes
,
388 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName
);
390 Status
= ZwOpenFile(&FileHandle
,
392 &FileObjectAttributes
,
396 if (!NT_SUCCESS(Status
))
398 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
399 &FullNtFileName
, Status
);
400 RtlFreeUnicodeString (&FullNtFileName
);
403 RtlFreeUnicodeString (&FullNtFileName
);
405 Status
= ZwReadFile(FileHandle
,
414 if (!NT_SUCCESS(Status
))
416 DPRINT("Dll header read failed: Status = 0x%08x\n", Status
);
421 * Overlay DOS and NT headers structures to the
422 * buffer with DLL's header raw data.
424 DosHeader
= (PIMAGE_DOS_HEADER
) BlockBuffer
;
425 NTHeaders
= (PIMAGE_NT_HEADERS
) (BlockBuffer
+ DosHeader
->e_lfanew
);
427 * Check it is a PE image file.
429 if ((DosHeader
->e_magic
!= IMAGE_DOS_MAGIC
)
430 || (DosHeader
->e_lfanew
== 0L)
431 || (*(PULONG
)(NTHeaders
) != IMAGE_PE_MAGIC
))
433 DPRINT("NTDLL format invalid\n");
436 return STATUS_UNSUCCESSFUL
;
439 ImageBase
= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
;
440 ImageSize
= NTHeaders
->OptionalHeader
.SizeOfImage
;
442 DPRINT("ImageBase 0x%08x\n", ImageBase
);
445 * Create a section for dll.
447 Status
= ZwCreateSection(SectionHandle
,
452 SEC_COMMIT
| SEC_IMAGE
,
456 if (!NT_SUCCESS(Status
))
458 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status
);
462 RtlCreateUnicodeString(FullDosName
,
470 /***************************************************************************
488 LdrLoadDll (IN PWSTR SearchPath OPTIONAL
,
490 IN PUNICODE_STRING Name
,
491 OUT PVOID
*BaseAddress OPTIONAL
)
493 UNICODE_STRING FullDosName
;
494 UNICODE_STRING AdjustedName
;
496 PIMAGE_NT_HEADERS NTHeaders
;
499 HANDLE SectionHandle
;
500 PDLLMAIN_FUNC Entrypoint
= NULL
;
506 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
507 return STATUS_SUCCESS
;
512 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
515 /* adjust the full dll name */
516 LdrAdjustDllName (&AdjustedName
,
519 DPRINT("AdjustedName: %wZ\n", &AdjustedName
);
522 * Test if dll is already loaded.
524 if (LdrFindEntryForName(&AdjustedName
, &Module
) == STATUS_SUCCESS
)
526 DPRINT("DLL %wZ already loaded.\n", &AdjustedName
);
527 *BaseAddress
= Module
->BaseAddress
;
528 return STATUS_SUCCESS
;
530 DPRINT("Loading \"%wZ\"\n", Name
);
532 /* Open or create dll image section */
533 Status
= LdrpMapKnownDll(&AdjustedName
,
536 if (!NT_SUCCESS(Status
))
538 Status
= LdrpMapDllImageFile(SearchPath
,
544 RtlFreeUnicodeString(&AdjustedName
);
546 if (!NT_SUCCESS(Status
))
548 DPRINT1("Failed to create or open dll section (Status %lx)\n", Status
);
553 * Map the dll into the process.
557 Status
= NtMapViewOfSection(SectionHandle
,
567 if (!NT_SUCCESS(Status
))
569 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n", Status
);
570 RtlFreeUnicodeString(&FullDosName
);
571 NtClose(SectionHandle
);
575 /* Get and check the NT headers */
576 NTHeaders
= RtlImageNtHeader(ImageBase
);
577 if (NTHeaders
== NULL
)
579 DPRINT1("RtlImageNtHeaders() failed\n");
580 RtlFreeUnicodeString(&FullDosName
);
581 return STATUS_UNSUCCESSFUL
;
584 /* relocate dll and fixup import table */
585 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
589 (PDLLMAIN_FUNC
) LdrPEStartup(ImageBase
, SectionHandle
, &Module
,
591 if (Entrypoint
== NULL
)
593 RtlFreeUnicodeString(&FullDosName
);
594 return(STATUS_UNSUCCESSFUL
);
598 RtlFreeUnicodeString(&FullDosName
);
602 LdrpLoadUserModuleSymbols(Module
);
607 if ((NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) ==
610 if (Module
->EntryPoint
!= 0)
612 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
614 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
615 if (FALSE
== Entrypoint(Module
->BaseAddress
,
619 /* Do this as a DPRINT1 for now, until clean up and fail implemented */
620 DPRINT1("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
621 &Module
->BaseDllName
);
622 /* FIXME: should clean up and fail */
626 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
627 &Module
->BaseDllName
);
632 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
633 &Module
->BaseDllName
);
637 *BaseAddress
= Module
->BaseAddress
;
638 return STATUS_SUCCESS
;
642 /***************************************************************************
644 * LdrFindEntryForAddress
659 LdrFindEntryForAddress(PVOID Address
,
662 PLIST_ENTRY ModuleListHead
;
664 PLDR_MODULE ModulePtr
;
666 DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address
);
668 if (NtCurrentPeb()->Ldr
== NULL
)
669 return(STATUS_NO_MORE_ENTRIES
);
671 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
672 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
673 Entry
= ModuleListHead
->Flink
;
674 if (Entry
== ModuleListHead
)
676 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
677 return(STATUS_NO_MORE_ENTRIES
);
680 while (Entry
!= ModuleListHead
)
682 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
684 DPRINT("Scanning %wZ at %p\n", &ModulePtr
->BaseDllName
, ModulePtr
->BaseAddress
);
686 if ((Address
>= ModulePtr
->BaseAddress
) &&
687 (Address
<= (ModulePtr
->BaseAddress
+ ModulePtr
->SizeOfImage
)))
690 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
691 return(STATUS_SUCCESS
);
694 Entry
= Entry
->Flink
;
697 DPRINT("Failed to find module entry.\n");
699 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
700 return(STATUS_NO_MORE_ENTRIES
);
704 /***************************************************************************
706 * LdrFindEntryForName
720 LdrFindEntryForName(PUNICODE_STRING Name
,
723 PLIST_ENTRY ModuleListHead
;
725 PLDR_MODULE ModulePtr
;
726 BOOLEAN ContainsPath
;
729 DPRINT("NTDLL.LdrFindEntryForName(Name %wZ)\n", Name
);
731 if (NtCurrentPeb()->Ldr
== NULL
)
732 return(STATUS_NO_MORE_ENTRIES
);
734 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
735 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
736 Entry
= ModuleListHead
->Flink
;
737 if (Entry
== ModuleListHead
)
739 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
740 return(STATUS_NO_MORE_ENTRIES
);
743 // NULL is the current process
746 *Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
747 if ((*Module
)->LoadCount
!= -1)
748 (*Module
)->LoadCount
++;
750 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
751 return(STATUS_SUCCESS
);
754 ContainsPath
= (Name
->Length
>= 2 * sizeof(WCHAR
) && L
':' == Name
->Buffer
[1]);
755 for (i
= 0; ! ContainsPath
&& i
< Name
->Length
/ sizeof(WCHAR
); i
++)
757 ContainsPath
= L
'\\' == Name
->Buffer
[i
] ||
758 L
'/' == Name
->Buffer
[i
];
760 while (Entry
!= ModuleListHead
)
762 ModulePtr
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
764 DPRINT("Scanning %wZ %wZ\n", &ModulePtr
->BaseDllName
, Name
);
766 if ((! ContainsPath
&&
767 0 == RtlCompareUnicodeString(&ModulePtr
->BaseDllName
, Name
, TRUE
)) ||
769 0 == RtlCompareUnicodeString(&ModulePtr
->FullDllName
, Name
, TRUE
)))
772 if (ModulePtr
->LoadCount
!= -1)
773 ModulePtr
->LoadCount
++;
774 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
775 return(STATUS_SUCCESS
);
778 Entry
= Entry
->Flink
;
781 DPRINT("Failed to find dll %wZ\n", Name
);
782 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
783 return(STATUS_NO_MORE_ENTRIES
);
786 /**********************************************************************
802 LdrFixupForward(PCHAR ForwardName
)
804 CHAR NameBuffer
[128];
805 UNICODE_STRING DllName
;
806 UNICODE_STRING FunctionName
;
811 strcpy(NameBuffer
, ForwardName
);
812 p
= strchr(NameBuffer
, '.');
817 DPRINT("Dll: %s Function: %s\n", NameBuffer
, p
+1);
818 RtlCreateUnicodeStringFromAsciiz (&DllName
,
821 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
822 if (!NT_SUCCESS(Status
))
824 Status
= LdrLoadDll(NULL
,
828 if (!NT_SUCCESS(Status
))
830 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName
);
831 RtlFreeUnicodeString (&DllName
);
836 RtlFreeUnicodeString (&DllName
);
837 DPRINT("BaseAddress: %p\n", BaseAddress
);
839 return LdrGetExportByName(BaseAddress
, p
+1, -1);
846 /**********************************************************************
848 * LdrGetExportByOrdinal
862 LdrGetExportByOrdinal (
867 PIMAGE_EXPORT_DIRECTORY ExportDir
;
868 PDWORD
* ExFunctions
;
871 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
872 RtlImageDirectoryEntryToData (BaseAddress
,
874 IMAGE_DIRECTORY_ENTRY_EXPORT
,
878 ExOrdinals
= (USHORT
*)
881 ExportDir
->AddressOfNameOrdinals
883 ExFunctions
= (PDWORD
*)
886 ExportDir
->AddressOfFunctions
889 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
891 RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] )
893 return(RVA(BaseAddress
, ExFunctions
[Ordinal
- ExportDir
->Base
] ));
897 /**********************************************************************
910 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
911 * both with NumberOfNames entries.
915 LdrGetExportByName(PVOID BaseAddress
,
919 PIMAGE_EXPORT_DIRECTORY ExportDir
;
920 PDWORD
* ExFunctions
;
930 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress
, SymbolName
, Hint
);
932 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
933 RtlImageDirectoryEntryToData(BaseAddress
,
935 IMAGE_DIRECTORY_ENTRY_EXPORT
,
937 if (ExportDir
== NULL
)
939 DbgPrint("LdrGetExportByName(): no export directory!\n");
944 //The symbol names may be missing entirely
945 if (ExportDir
->AddressOfNames
== 0)
947 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
952 * Get header pointers
954 ExNames
= (PDWORD
*)RVA(BaseAddress
,
955 ExportDir
->AddressOfNames
);
956 ExOrdinals
= (USHORT
*)RVA(BaseAddress
,
957 ExportDir
->AddressOfNameOrdinals
);
958 ExFunctions
= (PDWORD
*)RVA(BaseAddress
,
959 ExportDir
->AddressOfFunctions
);
962 * Check the hint first
964 if (Hint
< ExportDir
->NumberOfNames
)
966 ExName
= RVA(BaseAddress
, ExNames
[Hint
]);
967 if (strcmp(ExName
, SymbolName
) == 0)
969 Ordinal
= ExOrdinals
[Hint
];
970 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
971 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
972 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
974 DPRINT("Forward: %s\n", (PCHAR
)Function
);
975 Function
= LdrFixupForward((PCHAR
)Function
);
977 if (Function
!= NULL
)
983 * Try a binary search first
986 maxn
= ExportDir
->NumberOfNames
;
992 mid
= (minn
+ maxn
) / 2;
994 ExName
= RVA(BaseAddress
, ExNames
[mid
]);
995 res
= strcmp(ExName
, SymbolName
);
998 Ordinal
= ExOrdinals
[mid
];
999 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1000 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1001 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1003 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1004 Function
= LdrFixupForward((PCHAR
)Function
);
1006 if (Function
!= NULL
)
1009 else if (minn
== maxn
)
1011 DPRINT("LdrGetExportByName(): binary search failed\n");
1025 * Fall back on a linear search
1027 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1028 for (i
= 0; i
< ExportDir
->NumberOfNames
; i
++)
1030 ExName
= RVA(BaseAddress
, ExNames
[i
]);
1031 if (strcmp(ExName
,SymbolName
) == 0)
1033 Ordinal
= ExOrdinals
[i
];
1034 Function
= RVA(BaseAddress
, ExFunctions
[Ordinal
]);
1035 DPRINT("%x %x %x\n", Function
, ExportDir
, ExportDir
+ ExportDirSize
);
1036 if (((ULONG
)Function
>= (ULONG
)ExportDir
) &&
1037 ((ULONG
)Function
< (ULONG
)ExportDir
+ (ULONG
)ExportDirSize
))
1039 DPRINT("Forward: %s\n", (PCHAR
)Function
);
1040 Function
= LdrFixupForward((PCHAR
)Function
);
1045 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName
);
1050 /**********************************************************************
1052 * LdrPerformRelocations
1055 * Relocate a DLL's memory image.
1066 static NTSTATUS
LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders
,
1069 USHORT NumberOfEntries
;
1071 ULONG RelocationRVA
;
1075 PRELOCATION_DIRECTORY RelocationDir
;
1076 PRELOCATION_ENTRY RelocationBlock
;
1078 PIMAGE_DATA_DIRECTORY RelocationDDir
;
1082 PIMAGE_SECTION_HEADER Sections
;
1086 if (NTHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_RELOCS_STRIPPED
)
1088 return STATUS_UNSUCCESSFUL
;
1092 (PIMAGE_SECTION_HEADER
)((PVOID
)NTHeaders
+ sizeof(IMAGE_NT_HEADERS
));
1094 for (i
= 0; i
< NTHeaders
->FileHeader
.NumberOfSections
; i
++)
1096 if (!(Sections
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
1100 (ULONG
)(Sections
[i
].VirtualAddress
+ Sections
[i
].Misc
.VirtualSize
);
1101 MaxExtend
= max(MaxExtend
, Extend
);
1106 &NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1107 RelocationRVA
= RelocationDDir
->VirtualAddress
;
1112 (PRELOCATION_DIRECTORY
)((PCHAR
)ImageBase
+ RelocationRVA
);
1114 while (RelocationDir
->SizeOfBlock
)
1116 if (RelocationDir
->VirtualAddress
> MaxExtend
)
1118 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
1120 (PRELOCATION_DIRECTORY
) (ImageBase
+ RelocationRVA
);
1124 Delta32
= (ULONG
)(ImageBase
- NTHeaders
->OptionalHeader
.ImageBase
);
1126 (PRELOCATION_ENTRY
) (RelocationRVA
+ ImageBase
+
1127 sizeof (RELOCATION_DIRECTORY
));
1129 RelocationDir
->SizeOfBlock
- sizeof (RELOCATION_DIRECTORY
);
1130 NumberOfEntries
= NumberOfEntries
/ sizeof (RELOCATION_ENTRY
);
1132 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1134 RelocationDir
->VirtualAddress
,
1138 if (!NT_SUCCESS(Status
))
1140 DPRINT1("Failed to unprotect relocation target.\n");
1144 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
< MaxExtend
)
1146 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1148 RelocationDir
->VirtualAddress
+ PAGE_SIZE
,
1152 if (!NT_SUCCESS(Status
))
1154 DPRINT1("Failed to unprotect relocation target (2).\n");
1155 NtProtectVirtualMemory(NtCurrentProcess(),
1157 RelocationDir
->VirtualAddress
,
1165 for (i
= 0; i
< NumberOfEntries
; i
++)
1167 Offset
= (RelocationBlock
[i
].TypeOffset
& 0xfff);
1168 Offset
+= (ULONG
)(RelocationDir
->VirtualAddress
+ ImageBase
);
1171 * What kind of relocations should we perform
1172 * for the current entry?
1174 switch (RelocationBlock
[i
].TypeOffset
>> 12)
1176 case TYPE_RELOC_ABSOLUTE
:
1179 case TYPE_RELOC_HIGH
:
1180 pValue16
= (PUSHORT
)Offset
;
1181 *pValue16
+= Delta32
>> 16;
1184 case TYPE_RELOC_LOW
:
1185 pValue16
= (PUSHORT
)Offset
;
1186 *pValue16
+= Delta32
& 0xffff;
1189 case TYPE_RELOC_HIGHLOW
:
1190 pValue32
= (PULONG
)Offset
;
1191 *pValue32
+= Delta32
;
1194 case TYPE_RELOC_HIGHADJ
:
1195 /* FIXME: do the highadjust fixup */
1196 DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
1197 return(STATUS_UNSUCCESSFUL
);
1200 DPRINT("unexpected fixup type\n");
1201 return STATUS_UNSUCCESSFUL
;
1205 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1207 RelocationDir
->VirtualAddress
,
1211 if (!NT_SUCCESS(Status
))
1213 DPRINT1("Failed to protect relocation target.\n");
1217 if (RelocationDir
->VirtualAddress
+ PAGE_SIZE
< MaxExtend
)
1219 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1221 RelocationDir
->VirtualAddress
+ PAGE_SIZE
,
1225 if (!NT_SUCCESS(Status
))
1227 DPRINT1("Failed to protect relocation target2.\n");
1232 RelocationRVA
+= RelocationDir
->SizeOfBlock
;
1234 (PRELOCATION_DIRECTORY
) (ImageBase
+ RelocationRVA
);
1237 return STATUS_SUCCESS
;
1241 /**********************************************************************
1246 * Compute the entry point for every symbol the DLL imports
1247 * from other modules.
1258 static NTSTATUS
LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders
,
1261 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
1267 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders
,
1271 * Process each import module.
1273 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)(
1274 ImageBase
+ NTHeaders
->OptionalHeader
1275 .DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1277 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory
);
1279 while (ImportModuleDirectory
->dwRVAModuleName
)
1281 PVOID
* ImportAddressList
;
1282 PULONG FunctionNameList
;
1283 UNICODE_STRING DllName
;
1289 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
1290 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
1292 RtlCreateUnicodeStringFromAsciiz (&DllName
,
1293 (PCHAR
)(ImageBase
+ ImportModuleDirectory
->dwRVAModuleName
));
1295 Status
= LdrGetDllHandle (0, 0, &DllName
, &BaseAddress
);
1296 if (!NT_SUCCESS(Status
))
1298 Status
= LdrLoadDll(NULL
,
1302 RtlFreeUnicodeString (&DllName
);
1303 if (!NT_SUCCESS(Status
))
1305 DbgPrint("LdrFixupImports:failed to load %s\n"
1307 + ImportModuleDirectory
->dwRVAModuleName
));
1314 * Get the import address list.
1316 ImportAddressList
= (PVOID
*)(ImageBase
1317 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
1320 * Get the list of functions to import.
1322 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
1324 FunctionNameList
= (PULONG
) (
1326 + ImportModuleDirectory
->dwRVAFunctionNameList
1333 + ImportModuleDirectory
->dwRVAFunctionAddressList
);
1337 * Get the size of IAT.
1340 while (FunctionNameList
[IATSize
] != 0L)
1346 * Unprotect the region we are about to write into.
1348 IATBase
= (PVOID
)ImportAddressList
;
1349 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1351 IATSize
* sizeof(PVOID
*),
1354 if (!NT_SUCCESS(Status
))
1356 DbgPrint("LDR: Failed to unprotect IAT.\n");
1361 * Walk through function list and fixup addresses.
1363 while (*FunctionNameList
!= 0L)
1365 if ((*FunctionNameList
) & 0x80000000)
1367 Ordinal
= (*FunctionNameList
) & 0x7fffffff;
1368 *ImportAddressList
=
1369 LdrGetExportByOrdinal(BaseAddress
,
1374 pName
= (DWORD
) (ImageBase
+ *FunctionNameList
+ 2);
1375 pHint
= *(PWORD
)(ImageBase
+ *FunctionNameList
);
1377 *ImportAddressList
=
1378 LdrGetExportByName(BaseAddress
, (PUCHAR
)pName
, pHint
);
1379 if ((*ImportAddressList
) == NULL
)
1381 DbgPrint("Failed to import %s\n", pName
);
1382 return STATUS_UNSUCCESSFUL
;
1385 ImportAddressList
++;
1390 * Protect the region we are about to write into.
1392 Status
= NtProtectVirtualMemory(NtCurrentProcess(),
1394 IATSize
* sizeof(PVOID
*),
1397 if (!NT_SUCCESS(Status
))
1399 DbgPrint("LDR: Failed to protect IAT.\n");
1403 ImportModuleDirectory
++;
1405 return STATUS_SUCCESS
;
1409 /**********************************************************************
1414 * 1. Map the DLL's sections into memory.
1415 * 2. Relocate, if needed the DLL.
1416 * 3. Fixup any imported symbol.
1417 * 4. Compute the DLL's entry point.
1421 * Address at which the DLL's image
1425 * Handle of the section that contains
1429 * NULL on error; otherwise the entry point
1430 * to call for initializing the DLL.
1437 PEPFUNC
LdrPEStartup (PVOID ImageBase
,
1438 HANDLE SectionHandle
,
1439 PLDR_MODULE
* Module
,
1443 PEPFUNC EntryPoint
= NULL
;
1444 PIMAGE_DOS_HEADER DosHeader
;
1445 PIMAGE_NT_HEADERS NTHeaders
;
1447 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1448 ImageBase
, (ULONG
)SectionHandle
);
1451 * Overlay DOS and WNT headers structures
1452 * to the DLL's image.
1454 DosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
1455 NTHeaders
= (PIMAGE_NT_HEADERS
) (ImageBase
+ DosHeader
->e_lfanew
);
1458 * If the base address is different from the
1459 * one the DLL is actually loaded, perform any
1462 if (ImageBase
!= (PVOID
) NTHeaders
->OptionalHeader
.ImageBase
)
1464 DbgPrint("LDR: Performing relocations\n");
1465 Status
= LdrPerformRelocations(NTHeaders
, ImageBase
);
1466 if (!NT_SUCCESS(Status
))
1468 DbgPrint("LdrPerformRelocations() failed\n");
1475 *Module
= LdrAddModuleEntry(ImageBase
, NTHeaders
, FullDosName
);
1476 (*Module
)->SectionHandle
= SectionHandle
;
1480 * If the DLL's imports symbols from other
1481 * modules, fixup the imported calls entry points.
1483 if (NTHeaders
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
]
1484 .VirtualAddress
!= 0)
1486 DPRINT("About to fixup imports\n");
1487 Status
= LdrFixupImports(NTHeaders
, ImageBase
);
1488 if (!NT_SUCCESS(Status
))
1490 DbgPrint("LdrFixupImports() failed\n");
1493 DPRINT("Fixup done\n");
1497 * Compute the DLL's entry point's address.
1499 DPRINT("ImageBase = %x\n",(ULONG
)ImageBase
);
1500 DPRINT("AddressOfEntryPoint = %x\n",(ULONG
)NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1501 if (NTHeaders
->OptionalHeader
.AddressOfEntryPoint
!= 0)
1503 EntryPoint
= (PEPFUNC
) (ImageBase
1504 + NTHeaders
->OptionalHeader
.AddressOfEntryPoint
);
1506 DPRINT("LdrPEStartup() = %x\n",EntryPoint
);
1515 LdrUnloadDll (IN PVOID BaseAddress
)
1517 PIMAGE_NT_HEADERS NtHeaders
;
1518 PDLLMAIN_FUNC Entrypoint
;
1519 PLIST_ENTRY ModuleListHead
;
1524 if (BaseAddress
== NULL
)
1525 return STATUS_SUCCESS
;
1527 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1529 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1530 Entry
= ModuleListHead
->Flink
;
1532 while (Entry
!= ModuleListHead
)
1534 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1535 if (Module
->BaseAddress
== BaseAddress
)
1537 if (Module
->LoadCount
== -1)
1539 /* never unload this dll */
1540 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1541 return STATUS_SUCCESS
;
1543 else if (Module
->LoadCount
> 1)
1545 Module
->LoadCount
--;
1546 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1547 return STATUS_SUCCESS
;
1550 NtHeaders
= RtlImageNtHeader (Module
->BaseAddress
);
1551 if ((NtHeaders
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
) == IMAGE_FILE_DLL
)
1553 if (Module
->EntryPoint
!= 0)
1555 Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1556 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1557 Entrypoint(Module
->BaseAddress
,
1563 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1566 Status
= ZwUnmapViewOfSection (NtCurrentProcess (),
1567 Module
->BaseAddress
);
1568 ZwClose (Module
->SectionHandle
);
1570 /* remove the module entry from the list */
1571 RemoveEntryList (&Module
->InLoadOrderModuleList
)
1572 RemoveEntryList (&Module
->InInitializationOrderModuleList
);
1573 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1575 RtlFreeUnicodeString (&Module
->FullDllName
);
1576 RtlFreeUnicodeString (&Module
->BaseDllName
);
1578 RtlFreeHeap (RtlGetProcessHeap (), 0, Module
);
1583 Entry
= Entry
->Flink
;
1585 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1587 DPRINT("NTDLL.LDR: Dll not found\n")
1589 return STATUS_UNSUCCESSFUL
;
1597 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
1599 PLIST_ENTRY ModuleListHead
;
1604 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress
);
1606 Status
= STATUS_DLL_NOT_FOUND
;
1607 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1608 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1609 Entry
= ModuleListHead
->Flink
;
1610 while (Entry
!= ModuleListHead
) {
1611 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1613 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module
->BaseDllName
, Module
->BaseAddress
);
1615 if (Module
->BaseAddress
== BaseAddress
) {
1616 if (Module
->TlsIndex
== 0) {
1617 Module
->Flags
|= 0x00040000;
1618 Status
= STATUS_SUCCESS
;
1622 Entry
= Entry
->Flink
;
1624 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1633 LdrGetDllHandle(IN ULONG Unknown1
,
1635 IN PUNICODE_STRING DllName
,
1636 OUT PVOID
* BaseAddress
)
1638 UNICODE_STRING FullDllName
;
1639 PLIST_ENTRY ModuleListHead
;
1643 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1644 Unknown1
, Unknown2
, DllName
, BaseAddress
);
1646 /* NULL is the current executable */
1647 if (DllName
== NULL
) {
1648 *BaseAddress
= NtCurrentPeb()->ImageBaseAddress
;
1649 DPRINT("BaseAddress %x\n", *BaseAddress
);
1650 return STATUS_SUCCESS
;
1652 LdrAdjustDllName(&FullDllName
, DllName
, TRUE
);
1654 DPRINT("FullDllName %wZ\n", &FullDllName
);
1656 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1657 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1658 Entry
= ModuleListHead
->Flink
;
1659 while (Entry
!= ModuleListHead
) {
1660 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1662 DPRINT("EntryPoint %x\n", Module
->EntryPoint
);
1663 DPRINT("Comparing %wZ and %wZ\n", &Module
->BaseDllName
, &FullDllName
);
1665 if (!RtlCompareUnicodeString(&Module
->BaseDllName
, &FullDllName
, TRUE
)) {
1666 RtlFreeUnicodeString(&FullDllName
);
1667 *BaseAddress
= Module
->BaseAddress
;
1668 DPRINT("BaseAddress %x\n", *BaseAddress
);
1669 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1670 return STATUS_SUCCESS
;
1672 Entry
= Entry
->Flink
;
1675 DPRINT("Failed to find dll %wZ\n", &FullDllName
);
1677 RtlFreeUnicodeString(&FullDllName
);
1678 *BaseAddress
= NULL
;
1679 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1680 return STATUS_DLL_NOT_FOUND
;
1688 LdrGetProcedureAddress (IN PVOID BaseAddress
,
1689 IN PANSI_STRING Name
,
1691 OUT PVOID
*ProcedureAddress
)
1693 PIMAGE_EXPORT_DIRECTORY ExportDir
;
1699 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1700 BaseAddress
, Name
, Ordinal
, ProcedureAddress
);
1702 /* Get the pointer to the export directory */
1703 ExportDir
= (PIMAGE_EXPORT_DIRECTORY
)
1704 RtlImageDirectoryEntryToData (BaseAddress
,
1706 IMAGE_DIRECTORY_ENTRY_EXPORT
,
1709 DPRINT("ExportDir %x i %lu\n", ExportDir
, i
);
1711 if (!ExportDir
|| !i
|| !ProcedureAddress
)
1713 return STATUS_INVALID_PARAMETER
;
1716 AddressPtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfFunctions
);
1717 if (Name
&& Name
->Length
)
1720 OrdinalPtr
= (PUSHORT
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNameOrdinals
);
1721 NamePtr
= (PULONG
)((ULONG
)BaseAddress
+ (ULONG
)ExportDir
->AddressOfNames
);
1722 for( i
= 0; i
< ExportDir
->NumberOfNames
; i
++, NamePtr
++, OrdinalPtr
++)
1724 if (!_strnicmp(Name
->Buffer
, (char*)(BaseAddress
+ *NamePtr
), Name
->Length
))
1726 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[*OrdinalPtr
]);
1727 return STATUS_SUCCESS
;
1730 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name
);
1735 Ordinal
&= 0x0000FFFF;
1736 if (Ordinal
- ExportDir
->Base
< ExportDir
->NumberOfFunctions
)
1738 *ProcedureAddress
= (PVOID
)((ULONG
)BaseAddress
+ (ULONG
)AddressPtr
[Ordinal
- ExportDir
->Base
]);
1739 return STATUS_SUCCESS
;
1741 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal
);
1744 return STATUS_PROCEDURE_NOT_FOUND
;
1752 LdrShutdownProcess (VOID
)
1754 PLIST_ENTRY ModuleListHead
;
1758 DPRINT("LdrShutdownProcess() called\n");
1760 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1762 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1763 Entry
= ModuleListHead
->Blink
;
1765 while (Entry
!= ModuleListHead
)
1767 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1769 DPRINT(" Unloading %wZ\n",
1770 &Module
->BaseDllName
);
1771 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1772 // they loaded dynamically, and when the last reference is gone, that lib will
1774 if (Module
->EntryPoint
!= 0 && Module
->LoadCount
== -1)
1776 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1778 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1779 Entrypoint (Module
->BaseAddress
,
1784 Entry
= Entry
->Blink
;
1787 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1789 DPRINT("LdrShutdownProcess() done\n");
1791 return STATUS_SUCCESS
;
1799 LdrShutdownThread (VOID
)
1801 PLIST_ENTRY ModuleListHead
;
1805 DPRINT("LdrShutdownThread() called\n");
1807 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1809 ModuleListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1810 Entry
= ModuleListHead
->Blink
;
1812 while (Entry
!= ModuleListHead
)
1814 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InInitializationOrderModuleList
);
1816 DPRINT(" Unloading %wZ\n",
1817 &Module
->BaseDllName
);
1819 if (Module
->EntryPoint
!= 0)
1821 PDLLMAIN_FUNC Entrypoint
= (PDLLMAIN_FUNC
)Module
->EntryPoint
;
1823 DPRINT("Calling entry point at 0x%08x\n", Entrypoint
);
1824 Entrypoint (Module
->BaseAddress
,
1829 Entry
= Entry
->Blink
;
1832 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1834 DPRINT("LdrShutdownThread() done\n");
1836 return STATUS_SUCCESS
;
1840 /***************************************************************************
1842 * LdrQueryProcessModuleInformation
1857 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL
,
1858 IN ULONG Size OPTIONAL
,
1859 OUT PULONG ReturnedSize
)
1861 PLIST_ENTRY ModuleListHead
;
1864 PMODULE_ENTRY ModulePtr
= NULL
;
1865 NTSTATUS Status
= STATUS_SUCCESS
;
1866 ULONG UsedSize
= sizeof(ULONG
);
1867 ANSI_STRING AnsiString
;
1870 DPRINT("LdrQueryProcessModuleInformation() called\n");
1872 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
1874 if (ModuleInformation
== NULL
|| Size
== 0)
1876 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1880 ModuleInformation
->ModuleCount
= 0;
1881 ModulePtr
= &ModuleInformation
->ModuleEntry
[0];
1882 Status
= STATUS_SUCCESS
;
1885 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1886 Entry
= ModuleListHead
->Flink
;
1888 while (Entry
!= ModuleListHead
)
1890 Module
= CONTAINING_RECORD(Entry
, LDR_MODULE
, InLoadOrderModuleList
);
1892 DPRINT(" Module %wZ\n",
1893 &Module
->FullDllName
);
1895 if (UsedSize
> Size
)
1897 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1899 else if (ModuleInformation
!= NULL
)
1901 ModulePtr
->Unknown0
= 0; // FIXME: ??
1902 ModulePtr
->Unknown1
= 0; // FIXME: ??
1903 ModulePtr
->BaseAddress
= Module
->BaseAddress
;
1904 ModulePtr
->SizeOfImage
= Module
->SizeOfImage
;
1905 ModulePtr
->Flags
= Module
->Flags
;
1906 ModulePtr
->Unknown2
= 0; // FIXME: load order index ??
1907 ModulePtr
->Unknown3
= 0; // FIXME: ??
1908 ModulePtr
->LoadCount
= Module
->LoadCount
;
1910 AnsiString
.Length
= 0;
1911 AnsiString
.MaximumLength
= 256;
1912 AnsiString
.Buffer
= ModulePtr
->ModuleName
;
1913 RtlUnicodeStringToAnsiString(&AnsiString
,
1914 &Module
->FullDllName
,
1916 p
= strrchr(ModulePtr
->ModuleName
, '\\');
1918 ModulePtr
->PathLength
= p
- ModulePtr
->ModuleName
+ 1;
1920 ModulePtr
->PathLength
= 0;
1923 ModuleInformation
->ModuleCount
++;
1925 UsedSize
+= sizeof(MODULE_ENTRY
);
1927 Entry
= Entry
->Flink
;
1930 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
1932 if (ReturnedSize
!= 0)
1933 *ReturnedSize
= UsedSize
;
1935 DPRINT("LdrQueryProcessModuleInformation() done\n");
1942 LdrpCheckImageChecksum (IN PVOID BaseAddress
,
1945 PIMAGE_NT_HEADERS Header
;
1952 Header
= RtlImageNtHeader (BaseAddress
);
1956 HeaderSum
= Header
->OptionalHeader
.CheckSum
;
1961 Ptr
= (PUSHORT
) BaseAddress
;
1962 for (i
= 0; i
< ImageSize
/ sizeof (USHORT
); i
++)
1965 if (HIWORD(Sum
) != 0)
1967 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
1974 Sum
+= (ULONG
)*((PUCHAR
)Ptr
);
1975 if (HIWORD(Sum
) != 0)
1977 Sum
= LOWORD(Sum
) + HIWORD(Sum
);
1981 CalcSum
= (USHORT
)(LOWORD(Sum
) + HIWORD(Sum
));
1983 /* Subtract image checksum from calculated checksum. */
1984 /* fix low word of checksum */
1985 if (LOWORD(CalcSum
) >= LOWORD(HeaderSum
))
1987 CalcSum
-= LOWORD(HeaderSum
);
1991 CalcSum
= ((LOWORD(CalcSum
) - LOWORD(HeaderSum
)) & 0xFFFF) - 1;
1994 /* fix high word of checksum */
1995 if (LOWORD(CalcSum
) >= HIWORD(HeaderSum
))
1997 CalcSum
-= HIWORD(HeaderSum
);
2001 CalcSum
= ((LOWORD(CalcSum
) - HIWORD(HeaderSum
)) & 0xFFFF) - 1;
2004 /* add file length */
2005 CalcSum
+= ImageSize
;
2007 return (BOOLEAN
)(CalcSum
== HeaderSum
);
2011 /***************************************************************************
2013 * LdrVerifyImageMatchesChecksum
2028 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle
,
2033 FILE_STANDARD_INFORMATION FileInfo
;
2034 IO_STATUS_BLOCK IoStatusBlock
;
2035 HANDLE SectionHandle
;
2041 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2043 Status
= NtCreateSection (&SectionHandle
,
2044 SECTION_MAP_EXECUTE
,
2050 if (!NT_SUCCESS(Status
))
2052 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status
);
2058 Status
= NtMapViewOfSection (SectionHandle
,
2059 NtCurrentProcess (),
2068 if (!NT_SUCCESS(Status
))
2070 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2071 NtClose (SectionHandle
);
2075 Status
= NtQueryInformationFile (FileHandle
,
2078 sizeof (FILE_STANDARD_INFORMATION
),
2079 FileStandardInformation
);
2080 if (!NT_SUCCESS(Status
))
2082 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status
);
2083 NtUnmapViewOfSection (NtCurrentProcess (),
2085 NtClose (SectionHandle
);
2089 Result
= LdrpCheckImageChecksum (BaseAddress
,
2090 FileInfo
.EndOfFile
.u
.LowPart
);
2091 if (Result
== FALSE
)
2093 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
2096 NtUnmapViewOfSection (NtCurrentProcess (),
2099 NtClose (SectionHandle
);
2105 /***************************************************************************
2107 * LdrQueryImageFileExecutionOptions
2122 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey
,
2123 IN PCWSTR ValueName
,
2126 IN ULONG BufferSize
,
2127 OUT PULONG ReturnedLength OPTIONAL
)
2129 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
2130 OBJECT_ATTRIBUTES ObjectAttributes
;
2131 UNICODE_STRING ValueNameString
;
2132 UNICODE_STRING ValueString
;
2133 UNICODE_STRING KeyName
;
2134 WCHAR NameBuffer
[256];
2142 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2143 Ptr
= wcsrchr (SubKey
->Buffer
, L
'\\');
2146 Ptr
= SubKey
->Buffer
;
2152 wcscat (NameBuffer
, Ptr
);
2153 RtlInitUnicodeString (&KeyName
,
2156 InitializeObjectAttributes (&ObjectAttributes
,
2158 OBJ_CASE_INSENSITIVE
,
2162 Status
= NtOpenKey (&KeyHandle
,
2165 if (!NT_SUCCESS(Status
))
2167 DPRINT1 ("NtOpenKey() failed (Status %lx)\n", Status
);
2171 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 32;
2172 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
2176 RtlInitUnicodeString (&ValueNameString
,
2178 Status
= NtQueryValueKey (KeyHandle
,
2180 KeyValuePartialInformation
,
2184 if (Status
== STATUS_BUFFER_OVERFLOW
)
2186 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyInfo
->DataLength
;
2187 RtlFreeHeap (RtlGetProcessHeap(),
2190 KeyInfo
= RtlAllocateHeap (RtlGetProcessHeap(),
2193 if (KeyInfo
== NULL
)
2195 NtClose (KeyHandle
);
2199 Status
= NtQueryValueKey (KeyHandle
,
2201 KeyValuePartialInformation
,
2206 NtClose (KeyHandle
);
2208 if (!NT_SUCCESS(Status
))
2210 if (KeyInfo
!= NULL
)
2212 RtlFreeHeap (RtlGetProcessHeap(),
2219 if (KeyInfo
->Type
!= REG_SZ
)
2221 RtlFreeHeap (RtlGetProcessHeap(),
2224 return STATUS_OBJECT_TYPE_MISMATCH
;
2227 if (ValueSize
== sizeof(ULONG
))
2229 if (BufferSize
!= sizeof(ULONG
))
2232 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2236 ResultSize
= sizeof(ULONG
);
2237 ValueString
.Length
= (USHORT
)KeyInfo
->DataLength
- sizeof(WCHAR
);
2238 ValueString
.MaximumLength
= (USHORT
)KeyInfo
->DataLength
;
2239 ValueString
.Buffer
= (PWSTR
)&KeyInfo
->Data
;
2240 Status
= RtlUnicodeStringToInteger (&ValueString
,
2247 ResultSize
= BufferSize
;
2248 if (ResultSize
< KeyInfo
->DataLength
)
2250 Status
= STATUS_BUFFER_OVERFLOW
;
2254 ResultSize
= KeyInfo
->DataLength
;
2256 RtlCopyMemory (Buffer
,
2261 RtlFreeHeap (RtlGetProcessHeap(),
2265 if (ReturnedLength
!= NULL
)
2267 *ReturnedLength
= ResultSize
;