Merge trunk HEAD (r46369)
[reactos.git] / reactos / dll / ntdll / ldr / utils.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/ntdll/ldr/utils.c
5 * PURPOSE: Process startup for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
8 * Michael Martin
9 */
10
11 /*
12 * TODO:
13 * - Handle loading flags correctly
14 * - Handle errors correctly (unload dll's)
15 * - Implement a faster way to find modules (hash table)
16 * - any more ??
17 */
18
19 /* INCLUDES *****************************************************************/
20
21 #include <ntdll.h>
22 #define NDEBUG
23 #include <debug.h>
24
25 #define LDRP_PROCESS_CREATION_TIME 0xffff
26 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
27
28 /* GLOBALS *******************************************************************/
29
30 #ifdef NDEBUG
31 #define TRACE_LDR(...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
32 #endif
33
34 typedef struct _TLS_DATA
35 {
36 PVOID StartAddressOfRawData;
37 DWORD TlsDataSize;
38 DWORD TlsZeroSize;
39 PIMAGE_TLS_CALLBACK *TlsAddressOfCallBacks;
40 PLDR_DATA_TABLE_ENTRY Module;
41 } TLS_DATA, *PTLS_DATA;
42
43 static BOOLEAN LdrpDllShutdownInProgress = FALSE;
44 static PTLS_DATA LdrpTlsArray = NULL;
45 static ULONG LdrpTlsCount = 0;
46 static ULONG LdrpTlsSize = 0;
47 static HANDLE LdrpKnownDllsDirHandle = NULL;
48 static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
49 static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL;
50 extern PLDR_DATA_TABLE_ENTRY ExeModule;
51
52 /* PROTOTYPES ****************************************************************/
53
54 static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref);
55 static PVOID LdrFixupForward(PCHAR ForwardName);
56 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
57 static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
58 IN ULONG LoadFlags,
59 IN PUNICODE_STRING Name,
60 OUT PLDR_DATA_TABLE_ENTRY *Module,
61 OUT PVOID *BaseAddress OPTIONAL);
62 static NTSTATUS LdrpAttachProcess(VOID);
63 static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
64 static NTSTATUS LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Unload);
65
66 NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fulldosname );
67 NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module );
68
69 /* FUNCTIONS *****************************************************************/
70
71 BOOLEAN
72 LdrMappedAsDataFile(PVOID *BaseAddress)
73 {
74 if (0 != ((DWORD_PTR) *BaseAddress & (PAGE_SIZE - 1)))
75 {
76 *BaseAddress = (PVOID) ((DWORD_PTR) *BaseAddress & ~ ((DWORD_PTR) PAGE_SIZE - 1));
77 return TRUE;
78 }
79
80 return FALSE;
81 }
82
83 static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
84 {
85 LONG LoadCount;
86 if (!Locked)
87 {
88 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
89 }
90 LoadCount = Module->LoadCount;
91 if (Module->LoadCount > 0 && Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
92 {
93 Module->LoadCount--;
94 }
95 if (!Locked)
96 {
97 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
98 }
99 return LoadCount;
100 }
101
102 static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
103 {
104 LONG LoadCount;
105 if (!Locked)
106 {
107 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
108 }
109 LoadCount = Module->LoadCount;
110 if (Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
111 {
112 Module->LoadCount++;
113 }
114 if (!Locked)
115 {
116 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
117 }
118 return LoadCount;
119 }
120
121 static __inline VOID LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module, ULONG Size, BOOLEAN Locked)
122 {
123 if (!Locked)
124 {
125 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
126 }
127 Module->TlsIndex = (SHORT)LdrpTlsCount;
128 LdrpTlsCount++;
129 LdrpTlsSize += Size;
130 if (!Locked)
131 {
132 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
133 }
134 }
135
136 static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
137 {
138 PIMAGE_TLS_CALLBACK *TlsCallback;
139 if (Module->TlsIndex != 0xFFFF && Module->LoadCount == LDRP_PROCESS_CREATION_TIME)
140 {
141 TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
142 if (TlsCallback)
143 {
144 while (*TlsCallback)
145 {
146 TRACE_LDR("%wZ - Calling tls callback at %x\n",
147 &Module->BaseDllName, *TlsCallback);
148 (*TlsCallback)(Module->DllBase, dwReason, NULL);
149 TlsCallback++;
150 }
151 }
152 }
153 }
154
155 static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PVOID lpReserved)
156 {
157 if (!(Module->Flags & LDRP_IMAGE_DLL) ||
158 Module->EntryPoint == 0)
159 {
160 return TRUE;
161 }
162 LdrpTlsCallback(Module, dwReason);
163 return ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);
164 }
165
166 static PWSTR
167 LdrpQueryAppPaths(IN PCWSTR ImageName)
168 {
169 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
170 OBJECT_ATTRIBUTES ObjectAttributes;
171 WCHAR SearchPathBuffer[5*MAX_PATH];
172 UNICODE_STRING ValueNameString;
173 UNICODE_STRING KeyName;
174 WCHAR NameBuffer[MAX_PATH];
175 ULONG KeyInfoSize;
176 ULONG ResultSize;
177 PWCHAR Backslash;
178 HANDLE KeyHandle;
179 NTSTATUS Status;
180 PWSTR Path = NULL;
181
182 _snwprintf(NameBuffer,
183 sizeof(NameBuffer) / sizeof(WCHAR),
184 L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s",
185 ImageName);
186
187 RtlInitUnicodeString(&KeyName, NameBuffer);
188
189 InitializeObjectAttributes(&ObjectAttributes,
190 &KeyName,
191 OBJ_CASE_INSENSITIVE,
192 NULL,
193 NULL);
194
195 Status = NtOpenKey(&KeyHandle,
196 KEY_READ,
197 &ObjectAttributes);
198 if (!NT_SUCCESS(Status))
199 {
200 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
201 return NULL;
202 }
203
204 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR);
205
206 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize);
207 if (KeyInfo == NULL)
208 {
209 DPRINT("RtlAllocateHeap() failed\n");
210 NtClose(KeyHandle);
211 return NULL;
212 }
213
214 RtlInitUnicodeString(&ValueNameString,
215 L"Path");
216
217 Status = NtQueryValueKey(KeyHandle,
218 &ValueNameString,
219 KeyValuePartialInformation,
220 KeyInfo,
221 KeyInfoSize,
222 &ResultSize);
223
224 if (!NT_SUCCESS(Status))
225 {
226 NtClose(KeyHandle);
227 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
228 return NULL;
229 }
230
231 RtlCopyMemory(SearchPathBuffer,
232 &KeyInfo->Data,
233 KeyInfo->DataLength);
234
235 /* Free KeyInfo memory, we won't need it anymore */
236 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
237
238 /* Close the key handle */
239 NtClose(KeyHandle);
240
241 /* get application running path */
242 wcscat(SearchPathBuffer, L";");
243 wcscat(SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer); // FIXME: Don't rely on it being NULL-terminated!!!
244
245 /* Remove trailing backslash */
246 Backslash = wcsrchr(SearchPathBuffer, L'\\');
247 if (Backslash) Backslash = L'\0';
248
249 wcscat(SearchPathBuffer, L";");
250
251 wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
252 wcscat(SearchPathBuffer, L"\\system32;");
253 wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
254 wcscat(SearchPathBuffer, L";.");
255
256 /* Copy it to the heap allocd memory */
257 Path = RtlAllocateHeap(RtlGetProcessHeap(),
258 0,
259 wcslen(SearchPathBuffer) * sizeof(WCHAR));
260
261 if (!Path)
262 {
263 DPRINT1("RtlAllocateHeap() failed\n");
264 return NULL;
265 }
266
267 wcscpy(Path, SearchPathBuffer);
268
269 return Path;
270 }
271
272 static NTSTATUS
273 LdrpInitializeTlsForThread(VOID)
274 {
275 PVOID* TlsPointers;
276 PTLS_DATA TlsInfo;
277 PVOID TlsData;
278 ULONG i;
279 PTEB Teb = NtCurrentTeb();
280
281 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
282
283 Teb->StaticUnicodeString.Length = 0;
284 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
285 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
286
287 if (LdrpTlsCount > 0)
288 {
289 TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),
290 0,
291 LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);
292 if (TlsPointers == NULL)
293 {
294 DPRINT1("failed to allocate thread tls data\n");
295 return STATUS_NO_MEMORY;
296 }
297
298 TlsData = (PVOID)((ULONG_PTR)TlsPointers + LdrpTlsCount * sizeof(PVOID));
299 Teb->ThreadLocalStoragePointer = TlsPointers;
300
301 TlsInfo = LdrpTlsArray;
302 for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)
303 {
304 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo->Module->BaseDllName);
305 TlsPointers[i] = TlsData;
306 if (TlsInfo->TlsDataSize)
307 {
308 memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);
309 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsDataSize);
310 }
311 if (TlsInfo->TlsZeroSize)
312 {
313 memset(TlsData, 0, TlsInfo->TlsZeroSize);
314 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsZeroSize);
315 }
316 }
317 }
318
319 DPRINT("LdrpInitializeTlsForThread() done\n");
320 return STATUS_SUCCESS;
321 }
322
323 static NTSTATUS
324 LdrpInitializeTlsForProccess(VOID)
325 {
326 PLIST_ENTRY ModuleListHead;
327 PLIST_ENTRY Entry;
328 PLDR_DATA_TABLE_ENTRY Module;
329 PIMAGE_TLS_DIRECTORY TlsDirectory;
330 PTLS_DATA TlsData;
331 ULONG Size;
332
333 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule->BaseDllName);
334
335 if (LdrpTlsCount > 0)
336 {
337 LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
338 0,
339 LdrpTlsCount * sizeof(TLS_DATA));
340 if (LdrpTlsArray == NULL)
341 {
342 DPRINT1("Failed to allocate global tls data\n");
343 return STATUS_NO_MEMORY;
344 }
345
346 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
347 Entry = ModuleListHead->Flink;
348 while (Entry != ModuleListHead)
349 {
350 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
351 if (Module->LoadCount == LDRP_PROCESS_CREATION_TIME &&
352 Module->TlsIndex != 0xFFFF)
353 {
354 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
355 RtlImageDirectoryEntryToData(Module->DllBase,
356 TRUE,
357 IMAGE_DIRECTORY_ENTRY_TLS,
358 &Size);
359 ASSERT(Module->TlsIndex < LdrpTlsCount);
360 TlsData = &LdrpTlsArray[Module->TlsIndex];
361 TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;
362 TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
363 TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
364 if (TlsDirectory->AddressOfCallBacks)
365 TlsData->TlsAddressOfCallBacks = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;
366 else
367 TlsData->TlsAddressOfCallBacks = NULL;
368 TlsData->Module = Module;
369 #if 0
370 DbgPrint("TLS directory for %wZ\n", &Module->BaseDllName);
371 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory->StartAddressOfRawData);
372 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory->EndAddressOfRawData);
373 DbgPrint("SizeOfRawData: %d\n", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);
374 DbgPrint("AddressOfIndex: %x\n", TlsDirectory->AddressOfIndex);
375 DbgPrint("AddressOfCallBacks: %x\n", TlsDirectory->AddressOfCallBacks);
376 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory->SizeOfZeroFill);
377 DbgPrint("Characteristics: %x\n", TlsDirectory->Characteristics);
378 #endif
379 /*
380 * FIXME:
381 * Is this region allways writable ?
382 */
383 *(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;
384 }
385 Entry = Entry->Flink;
386 }
387 }
388
389 DPRINT("LdrpInitializeTlsForProccess() done\n");
390 return STATUS_SUCCESS;
391 }
392
393 VOID
394 LdrpInitLoader(VOID)
395 {
396 OBJECT_ATTRIBUTES ObjectAttributes;
397 UNICODE_STRING LinkTarget;
398 UNICODE_STRING Name;
399 HANDLE LinkHandle;
400 ULONG Length;
401 NTSTATUS Status;
402
403 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule->BaseDllName);
404
405 /* Get handle to the 'KnownDlls' directory */
406 RtlInitUnicodeString(&Name,
407 L"\\KnownDlls");
408 InitializeObjectAttributes(&ObjectAttributes,
409 &Name,
410 OBJ_CASE_INSENSITIVE,
411 NULL,
412 NULL);
413 Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
414 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
415 &ObjectAttributes);
416 if (!NT_SUCCESS(Status))
417 {
418 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
419 LdrpKnownDllsDirHandle = NULL;
420 return;
421 }
422
423 /* Allocate target name string */
424 LinkTarget.Length = 0;
425 LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
426 LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
427 0,
428 MAX_PATH * sizeof(WCHAR));
429 if (LinkTarget.Buffer == NULL)
430 {
431 NtClose(LdrpKnownDllsDirHandle);
432 LdrpKnownDllsDirHandle = NULL;
433 return;
434 }
435
436 RtlInitUnicodeString(&Name,
437 L"KnownDllPath");
438 InitializeObjectAttributes(&ObjectAttributes,
439 &Name,
440 OBJ_CASE_INSENSITIVE,
441 LdrpKnownDllsDirHandle,
442 NULL);
443 Status = NtOpenSymbolicLinkObject(&LinkHandle,
444 SYMBOLIC_LINK_ALL_ACCESS,
445 &ObjectAttributes);
446 if (!NT_SUCCESS(Status))
447 {
448 RtlFreeUnicodeString(&LinkTarget);
449 NtClose(LdrpKnownDllsDirHandle);
450 LdrpKnownDllsDirHandle = NULL;
451 return;
452 }
453
454 Status = NtQuerySymbolicLinkObject(LinkHandle,
455 &LinkTarget,
456 &Length);
457 NtClose(LinkHandle);
458 if (!NT_SUCCESS(Status))
459 {
460 RtlFreeUnicodeString(&LinkTarget);
461 NtClose(LdrpKnownDllsDirHandle);
462 LdrpKnownDllsDirHandle = NULL;
463 }
464
465 RtlCreateUnicodeString(&LdrpKnownDllPath,
466 LinkTarget.Buffer);
467
468 RtlFreeUnicodeString(&LinkTarget);
469
470 DPRINT("LdrpInitLoader() done\n");
471 }
472
473
474 /***************************************************************************
475 * NAME LOCAL
476 * LdrAdjustDllName
477 *
478 * DESCRIPTION
479 * Adjusts the name of a dll to a fully qualified name.
480 *
481 * ARGUMENTS
482 * FullDllName: Pointer to caller supplied storage for the fully
483 * qualified dll name.
484 * DllName: Pointer to the dll name.
485 * BaseName: TRUE: Only the file name is passed to FullDllName
486 * FALSE: The full path is preserved in FullDllName
487 *
488 * RETURN VALUE
489 * None
490 *
491 * REVISIONS
492 *
493 * NOTE
494 * A given path is not affected by the adjustment, but the file
495 * name only:
496 * ntdll --> ntdll.dll
497 * ntdll. --> ntdll
498 * ntdll.xyz --> ntdll.xyz
499 */
500 static VOID
501 LdrAdjustDllName (PUNICODE_STRING FullDllName,
502 PUNICODE_STRING DllName,
503 BOOLEAN BaseName)
504 {
505 WCHAR Buffer[MAX_PATH];
506 ULONG Length;
507 PWCHAR Extension;
508 PWCHAR Pointer;
509
510 Length = DllName->Length / sizeof(WCHAR);
511
512 if (BaseName)
513 {
514 /* get the base dll name */
515 Pointer = DllName->Buffer + Length;
516 Extension = Pointer;
517
518 do
519 {
520 --Pointer;
521 }
522 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
523
524 Pointer++;
525 Length = Extension - Pointer;
526 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
527 Buffer[Length] = L'\0';
528 }
529 else
530 {
531 /* get the full dll name */
532 memmove (Buffer, DllName->Buffer, DllName->Length);
533 Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
534 }
535
536 /* Build the DLL's absolute name */
537 Extension = wcsrchr (Buffer, L'.');
538 if ((Extension != NULL) && (*Extension == L'.'))
539 {
540 /* with extension - remove dot if it's the last character */
541 if (Buffer[Length - 1] == L'.')
542 Length--;
543 Buffer[Length] = 0;
544 }
545 else
546 {
547 /* name without extension - assume that it is .dll */
548 memmove (Buffer + Length, L".dll", 10);
549 }
550
551 RtlCreateUnicodeString(FullDllName, Buffer);
552 }
553
554 PLDR_DATA_TABLE_ENTRY
555 LdrAddModuleEntry(PVOID ImageBase,
556 PIMAGE_NT_HEADERS NTHeaders,
557 PWSTR FullDosName)
558 {
559 PLDR_DATA_TABLE_ENTRY Module;
560
561 Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY));
562 ASSERT(Module);
563 memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY));
564 Module->DllBase = (PVOID)ImageBase;
565 Module->EntryPoint = (PVOID)(ULONG_PTR)NTHeaders->OptionalHeader.AddressOfEntryPoint;
566 if (Module->EntryPoint != 0)
567 Module->EntryPoint = (PVOID)((ULONG_PTR)Module->EntryPoint + (ULONG_PTR)Module->DllBase);
568 Module->SizeOfImage = LdrpGetResidentSize(NTHeaders);
569 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
570 {
571 /* loading while app is running */
572 Module->LoadCount = 1;
573 } else {
574 /*
575 * loading while app is initializing
576 * dll must not be unloaded
577 */
578 Module->LoadCount = LDRP_PROCESS_CREATION_TIME;
579 }
580
581 Module->Flags = 0;
582 Module->TlsIndex = -1;
583 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
584 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
585
586 RtlCreateUnicodeString (&Module->FullDllName,
587 FullDosName);
588 RtlCreateUnicodeString (&Module->BaseDllName,
589 wcsrchr(FullDosName, L'\\') + 1);
590 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
591
592 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
593 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
594 &Module->InLoadOrderLinks);
595 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
596
597 return(Module);
598 }
599
600
601 static NTSTATUS
602 LdrpMapKnownDll(IN PUNICODE_STRING DllName,
603 OUT PUNICODE_STRING FullDosName,
604 OUT PHANDLE SectionHandle)
605 {
606 OBJECT_ATTRIBUTES ObjectAttributes;
607 NTSTATUS Status;
608
609 DPRINT("LdrpMapKnownDll() called\n");
610
611 if (LdrpKnownDllsDirHandle == NULL)
612 {
613 DPRINT("Invalid 'KnownDlls' directory\n");
614 return STATUS_UNSUCCESSFUL;
615 }
616
617 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath);
618
619 InitializeObjectAttributes(&ObjectAttributes,
620 DllName,
621 OBJ_CASE_INSENSITIVE,
622 LdrpKnownDllsDirHandle,
623 NULL);
624 Status = NtOpenSection(SectionHandle,
625 SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
626 &ObjectAttributes);
627 if (!NT_SUCCESS(Status))
628 {
629 DPRINT("NtOpenSection() failed for '%wZ' (Status 0x%08lx)\n", DllName, Status);
630 return Status;
631 }
632
633 FullDosName->Length = LdrpKnownDllPath.Length + DllName->Length + sizeof(WCHAR);
634 FullDosName->MaximumLength = FullDosName->Length + sizeof(WCHAR);
635 FullDosName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
636 0,
637 FullDosName->MaximumLength);
638 if (FullDosName->Buffer == NULL)
639 {
640 FullDosName->Length = 0;
641 FullDosName->MaximumLength = 0;
642 return STATUS_SUCCESS;
643 }
644
645 wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer);
646 wcscat(FullDosName->Buffer, L"\\");
647 wcscat(FullDosName->Buffer, DllName->Buffer);
648
649 DPRINT("FullDosName '%wZ'\n", FullDosName);
650
651 DPRINT("LdrpMapKnownDll() done\n");
652
653 return STATUS_SUCCESS;
654 }
655
656
657 static NTSTATUS
658 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
659 IN PUNICODE_STRING DllName,
660 OUT PUNICODE_STRING FullDosName,
661 IN BOOLEAN MapAsDataFile,
662 OUT PHANDLE SectionHandle)
663 {
664 WCHAR *SearchPathBuffer = NULL;
665 WCHAR *ImagePathNameBufferPtr = NULL;
666 WCHAR DosName[MAX_PATH];
667 UNICODE_STRING FullNtFileName;
668 UNICODE_STRING PathEnvironmentVar_U;
669 UNICODE_STRING PathName_U;
670 OBJECT_ATTRIBUTES FileObjectAttributes;
671 HANDLE FileHandle;
672 char BlockBuffer [1024];
673 PIMAGE_DOS_HEADER DosHeader;
674 PIMAGE_NT_HEADERS NTHeaders;
675 IO_STATUS_BLOCK IoStatusBlock;
676 NTSTATUS Status;
677 ULONG len;
678 ULONG ImagePathLen;
679
680 DPRINT("LdrpMapDllImageFile() called\n");
681
682 if (SearchPath == NULL)
683 {
684 /* get application running path */
685 ImagePathNameBufferPtr = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;
686
687 /* Length of ImagePathName */
688 ImagePathLen = wcslen(ImagePathNameBufferPtr);
689
690 /* Subtract application name leaveing only the directory length */
691 while (ImagePathLen && ImagePathNameBufferPtr[ImagePathLen - 1] != L'\\')
692 ImagePathLen--;
693
694 /* Length of directory + semicolon */
695 len = ImagePathLen + 1;
696
697 /* Length of SystemRoot + "//system32" + semicolon*/
698 len += wcslen(SharedUserData->NtSystemRoot) + 10;
699 /* Length of SystemRoot + semicolon */
700 len += wcslen(SharedUserData->NtSystemRoot) + 1;
701
702 RtlInitUnicodeString (&PathName_U, L"PATH");
703 PathEnvironmentVar_U.Length = 0;
704 PathEnvironmentVar_U.MaximumLength = 0;
705 PathEnvironmentVar_U.Buffer = NULL;
706
707 /* Get the path environment variable */
708 Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
709
710 /* Check that valid information was returned */
711 if ((Status == STATUS_BUFFER_TOO_SMALL) && (PathEnvironmentVar_U.Length > 0))
712 {
713 /* Allocate memory for the path env var */
714 PathEnvironmentVar_U.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, PathEnvironmentVar_U.Length + sizeof(WCHAR));
715 if (!PathEnvironmentVar_U.Buffer)
716 {
717 DPRINT1("Fatal! Out of Memory!!\n");
718 return STATUS_NO_MEMORY;
719 }
720 PathEnvironmentVar_U.MaximumLength = PathEnvironmentVar_U.Length + sizeof(WCHAR);
721
722 /* Retry */
723 Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
724
725 if (!NT_SUCCESS(Status))
726 {
727 DPRINT1("Unable to get path environment string!\n");
728 ASSERT(FALSE);
729 }
730 /* Length of path evn var + semicolon */
731 len += (PathEnvironmentVar_U.Length / sizeof(WCHAR)) + 1;
732 }
733
734 /* Allocate the size needed to hold all the above paths + period */
735 SearchPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (len + 2) * sizeof(WCHAR));
736 if (!SearchPathBuffer)
737 {
738 DPRINT1("Fatal! Out of Memory!!\n");
739 return STATUS_NO_MEMORY;
740 }
741
742 wcsncpy(SearchPathBuffer, ImagePathNameBufferPtr, ImagePathLen);
743 wcscat (SearchPathBuffer, L";");
744 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
745 wcscat (SearchPathBuffer, L"\\system32;");
746 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
747 wcscat (SearchPathBuffer, L";");
748
749 if (PathEnvironmentVar_U.Buffer)
750 {
751 wcscat (SearchPathBuffer, PathEnvironmentVar_U.Buffer);
752 wcscat (SearchPathBuffer, L";");
753 RtlFreeHeap(RtlGetProcessHeap(), 0, PathEnvironmentVar_U.Buffer);
754 }
755 wcscat (SearchPathBuffer, L".");
756
757 SearchPath = SearchPathBuffer;
758 }
759
760 if (RtlDosSearchPath_U (SearchPath,
761 DllName->Buffer,
762 NULL,
763 MAX_PATH,
764 DosName,
765 NULL) == 0)
766 {
767 /* try to find active context dll */
768 Status = find_actctx_dll(DllName->Buffer, DosName);
769 if(Status == STATUS_SUCCESS)
770 DPRINT("found %S for %S\n", DosName,DllName->Buffer);
771 else
772 return STATUS_DLL_NOT_FOUND;
773 }
774
775 if (!RtlDosPathNameToNtPathName_U (DosName,
776 &FullNtFileName,
777 NULL,
778 NULL))
779 {
780 DPRINT("Dll %wZ not found!\n", DllName);
781 return STATUS_DLL_NOT_FOUND;
782 }
783
784 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
785
786 InitializeObjectAttributes(&FileObjectAttributes,
787 &FullNtFileName,
788 0,
789 NULL,
790 NULL);
791
792 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
793
794 Status = NtOpenFile(&FileHandle,
795 GENERIC_READ|SYNCHRONIZE,
796 &FileObjectAttributes,
797 &IoStatusBlock,
798 FILE_SHARE_READ,
799 FILE_SYNCHRONOUS_IO_NONALERT);
800 if (!NT_SUCCESS(Status))
801 {
802 DPRINT1("Dll open of %wZ failed: Status = 0x%08lx\n",
803 &FullNtFileName, Status);
804 RtlFreeHeap (RtlGetProcessHeap (),
805 0,
806 FullNtFileName.Buffer);
807 return Status;
808 }
809 RtlFreeHeap (RtlGetProcessHeap (),
810 0,
811 FullNtFileName.Buffer);
812
813 if (!MapAsDataFile)
814 {
815
816 Status = NtReadFile(FileHandle,
817 NULL,
818 NULL,
819 NULL,
820 &IoStatusBlock,
821 BlockBuffer,
822 sizeof(BlockBuffer),
823 NULL,
824 NULL);
825 if (!NT_SUCCESS(Status))
826 {
827 DPRINT("Dll header read failed: Status = 0x%08lx\n", Status);
828 NtClose(FileHandle);
829 return Status;
830 }
831
832 /*
833 * Overlay DOS and NT headers structures to the
834 * buffer with DLL's header raw data.
835 */
836 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
837 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
838 /*
839 * Check it is a PE image file.
840 */
841 if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
842 || (DosHeader->e_lfanew == 0L)
843 || (*(PULONG)(NTHeaders) != IMAGE_NT_SIGNATURE))
844 {
845 DPRINT("NTDLL format invalid\n");
846 NtClose(FileHandle);
847
848 return STATUS_UNSUCCESSFUL;
849 }
850 }
851
852 /*
853 * Create a section for dll.
854 */
855 Status = NtCreateSection(SectionHandle,
856 SECTION_ALL_ACCESS,
857 NULL,
858 NULL,
859 PAGE_READONLY,
860 MapAsDataFile ? SEC_COMMIT : SEC_IMAGE,
861 FileHandle);
862 NtClose(FileHandle);
863
864 if (!NT_SUCCESS(Status))
865 {
866 DPRINT("NTDLL create section failed: Status = 0x%08lx\n", Status);
867 return Status;
868 }
869
870 RtlCreateUnicodeString(FullDosName,
871 DosName);
872
873 return Status;
874 }
875
876
877
878 /***************************************************************************
879 * NAME EXPORTED
880 * LdrLoadDll
881 *
882 * DESCRIPTION
883 *
884 * ARGUMENTS
885 *
886 * RETURN VALUE
887 *
888 * REVISIONS
889 *
890 * NOTE
891 *
892 * @implemented
893 */
894 NTSTATUS NTAPI
895 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
896 IN PULONG LoadFlags OPTIONAL,
897 IN PUNICODE_STRING Name,
898 OUT PVOID *BaseAddress /* also known as HMODULE*, and PHANDLE 'DllHandle' */)
899 {
900 NTSTATUS Status;
901 PLDR_DATA_TABLE_ENTRY Module;
902 ULONG_PTR cookie;
903 PPEB Peb = NtCurrentPeb();
904
905 TRACE_LDR("LdrLoadDll loading %wZ%S%S with flags %d\n",
906 Name,
907 SearchPath ? L" from " : L"",
908 SearchPath ? SearchPath : L"",
909 LoadFlags ? *LoadFlags : 0);
910
911 Status = LdrpLoadModule(SearchPath, LoadFlags ? *LoadFlags : 0, Name, &Module, BaseAddress);
912
913 if (NT_SUCCESS(Status) &&
914 (!LoadFlags || 0 == (*LoadFlags & LOAD_LIBRARY_AS_DATAFILE)))
915 {
916 if (!create_module_activation_context( Module ))
917 {
918 RtlActivateActivationContext(0, Module->EntryPointActivationContext, &cookie);
919 }
920
921 if (!(Module->Flags & LDRP_PROCESS_ATTACH_CALLED))
922 {
923 RtlEnterCriticalSection(Peb->LoaderLock);
924 Status = LdrpAttachProcess();
925 RtlLeaveCriticalSection(Peb->LoaderLock);
926 }
927 if (Module->EntryPointActivationContext) RtlDeactivateActivationContext(0, cookie);
928 }
929
930 if ((!Module) && (NT_SUCCESS(Status)))
931 return Status;
932
933 *BaseAddress = NT_SUCCESS(Status) ? Module->DllBase : NULL;
934
935 return Status;
936 }
937
938
939 /***************************************************************************
940 * NAME EXPORTED
941 * LdrFindEntryForAddress
942 *
943 * DESCRIPTION
944 *
945 * ARGUMENTS
946 *
947 * RETURN VALUE
948 *
949 * REVISIONS
950 *
951 * NOTE
952 *
953 * @implemented
954 */
955 NTSTATUS NTAPI
956 LdrFindEntryForAddress(PVOID Address,
957 PLDR_DATA_TABLE_ENTRY *Module)
958 {
959 PLIST_ENTRY ModuleListHead;
960 PLIST_ENTRY Entry;
961 PLDR_DATA_TABLE_ENTRY ModulePtr;
962
963 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
964
965 if (NtCurrentPeb()->Ldr == NULL)
966 return(STATUS_NO_MORE_ENTRIES);
967
968 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
969 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
970 Entry = ModuleListHead->Flink;
971 if (Entry == ModuleListHead)
972 {
973 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
974 return(STATUS_NO_MORE_ENTRIES);
975 }
976
977 while (Entry != ModuleListHead)
978 {
979 ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
980
981 DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->DllBase);
982
983 if ((Address >= ModulePtr->DllBase) &&
984 ((ULONG_PTR)Address <= ((ULONG_PTR)ModulePtr->DllBase + ModulePtr->SizeOfImage)))
985 {
986 *Module = ModulePtr;
987 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
988 return(STATUS_SUCCESS);
989 }
990
991 Entry = Entry->Flink;
992 }
993
994 DPRINT("Failed to find module entry.\n");
995
996 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
997 return(STATUS_NO_MORE_ENTRIES);
998 }
999
1000
1001 /***************************************************************************
1002 * NAME LOCAL
1003 * LdrFindEntryForName
1004 *
1005 * DESCRIPTION
1006 *
1007 * ARGUMENTS
1008 *
1009 * RETURN VALUE
1010 *
1011 * REVISIONS
1012 *
1013 * NOTE
1014 *
1015 */
1016 static NTSTATUS
1017 LdrFindEntryForName(PUNICODE_STRING Name,
1018 PLDR_DATA_TABLE_ENTRY *Module,
1019 BOOLEAN Ref)
1020 {
1021 PLIST_ENTRY ModuleListHead;
1022 PLIST_ENTRY Entry;
1023 PLDR_DATA_TABLE_ENTRY ModulePtr;
1024 BOOLEAN ContainsPath;
1025 UNICODE_STRING AdjustedName;
1026
1027 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name);
1028
1029 if (NtCurrentPeb()->Ldr == NULL)
1030 return(STATUS_NO_MORE_ENTRIES);
1031
1032 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
1033 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1034 Entry = ModuleListHead->Flink;
1035 if (Entry == ModuleListHead)
1036 {
1037 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1038 return(STATUS_NO_MORE_ENTRIES);
1039 }
1040
1041 // NULL is the current process
1042 if (Name == NULL)
1043 {
1044 *Module = ExeModule;
1045 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1046 return(STATUS_SUCCESS);
1047 }
1048
1049 ContainsPath = (Name->Length >= 2 * sizeof(WCHAR) && L':' == Name->Buffer[1]);
1050 LdrAdjustDllName (&AdjustedName, Name, !ContainsPath);
1051
1052 if (LdrpLastModule)
1053 {
1054 if ((! ContainsPath &&
1055 0 == RtlCompareUnicodeString(&LdrpLastModule->BaseDllName, &AdjustedName, TRUE)) ||
1056 (ContainsPath &&
1057 0 == RtlCompareUnicodeString(&LdrpLastModule->FullDllName, &AdjustedName, TRUE)))
1058 {
1059 *Module = LdrpLastModule;
1060 if (Ref && (*Module)->LoadCount != LDRP_PROCESS_CREATION_TIME)
1061 {
1062 (*Module)->LoadCount++;
1063 }
1064 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1065 RtlFreeUnicodeString(&AdjustedName);
1066 return(STATUS_SUCCESS);
1067 }
1068 }
1069 while (Entry != ModuleListHead)
1070 {
1071 ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1072
1073 DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, &AdjustedName);
1074
1075 if ((! ContainsPath &&
1076 0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, &AdjustedName, TRUE)) ||
1077 (ContainsPath &&
1078 0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, &AdjustedName, TRUE)))
1079 {
1080 *Module = LdrpLastModule = ModulePtr;
1081 if (Ref && ModulePtr->LoadCount != LDRP_PROCESS_CREATION_TIME)
1082 {
1083 ModulePtr->LoadCount++;
1084 }
1085 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1086 RtlFreeUnicodeString(&AdjustedName);
1087 return(STATUS_SUCCESS);
1088 }
1089
1090 Entry = Entry->Flink;
1091 }
1092
1093 DPRINT("Failed to find dll %wZ\n", Name);
1094 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
1095 RtlFreeUnicodeString(&AdjustedName);
1096 return(STATUS_NO_MORE_ENTRIES);
1097 }
1098
1099 /**********************************************************************
1100 * NAME LOCAL
1101 * LdrFixupForward
1102 *
1103 * DESCRIPTION
1104 *
1105 * ARGUMENTS
1106 *
1107 * RETURN VALUE
1108 *
1109 * REVISIONS
1110 *
1111 * NOTE
1112 *
1113 */
1114 static PVOID
1115 LdrFixupForward(PCHAR ForwardName)
1116 {
1117 CHAR NameBuffer[128];
1118 UNICODE_STRING DllName;
1119 NTSTATUS Status;
1120 PCHAR p;
1121 PLDR_DATA_TABLE_ENTRY Module;
1122 PVOID BaseAddress;
1123
1124 strcpy(NameBuffer, ForwardName);
1125 p = strchr(NameBuffer, '.');
1126 if (p != NULL)
1127 {
1128 *p = 0;
1129
1130 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
1131 RtlCreateUnicodeStringFromAsciiz (&DllName,
1132 NameBuffer);
1133
1134 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
1135 /* FIXME:
1136 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
1137 */
1138 if (!NT_SUCCESS(Status))
1139 {
1140 Status = LdrLoadDll(NULL,
1141 NULL,
1142 &DllName,
1143 &BaseAddress);
1144 if (NT_SUCCESS(Status))
1145 {
1146 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
1147 }
1148 }
1149 RtlFreeUnicodeString (&DllName);
1150 if (!NT_SUCCESS(Status))
1151 {
1152 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer);
1153 return NULL;
1154 }
1155
1156 DPRINT("BaseAddress: %p\n", Module->DllBase);
1157
1158 return LdrGetExportByName(Module->DllBase, (PUCHAR)(p+1), -1);
1159 }
1160
1161 return NULL;
1162 }
1163
1164
1165 /**********************************************************************
1166 * NAME LOCAL
1167 * LdrGetExportByOrdinal
1168 *
1169 * DESCRIPTION
1170 *
1171 * ARGUMENTS
1172 *
1173 * RETURN VALUE
1174 *
1175 * REVISIONS
1176 *
1177 * NOTE
1178 *
1179 */
1180 static PVOID
1181 LdrGetExportByOrdinal (
1182 PVOID BaseAddress,
1183 ULONG Ordinal
1184 )
1185 {
1186 PIMAGE_EXPORT_DIRECTORY ExportDir;
1187 ULONG ExportDirSize;
1188 PDWORD * ExFunctions;
1189 PVOID Function;
1190
1191 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1192 RtlImageDirectoryEntryToData (BaseAddress,
1193 TRUE,
1194 IMAGE_DIRECTORY_ENTRY_EXPORT,
1195 &ExportDirSize);
1196
1197
1198 ExFunctions = (PDWORD *)
1199 RVA(
1200 BaseAddress,
1201 ExportDir->AddressOfFunctions
1202 );
1203 DPRINT(
1204 "LdrGetExportByOrdinal(Ordinal %lu) = %p\n",
1205 Ordinal,
1206 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1207 );
1208
1209 Function = (0 != ExFunctions[Ordinal - ExportDir->Base]
1210 ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1211 : NULL);
1212
1213 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1214 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1215 {
1216 DPRINT("Forward: %s\n", (PCHAR)Function);
1217 Function = LdrFixupForward((PCHAR)Function);
1218 }
1219
1220 return Function;
1221 }
1222
1223
1224 /**********************************************************************
1225 * NAME LOCAL
1226 * LdrGetExportByName
1227 *
1228 * DESCRIPTION
1229 *
1230 * ARGUMENTS
1231 *
1232 * RETURN VALUE
1233 *
1234 * REVISIONS
1235 *
1236 * NOTE
1237 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1238 * both with NumberOfNames entries.
1239 *
1240 */
1241 static PVOID
1242 LdrGetExportByName(PVOID BaseAddress,
1243 PUCHAR SymbolName,
1244 WORD Hint)
1245 {
1246 PIMAGE_EXPORT_DIRECTORY ExportDir;
1247 PDWORD * ExFunctions;
1248 PDWORD * ExNames;
1249 USHORT * ExOrdinals;
1250 PVOID ExName;
1251 ULONG Ordinal;
1252 PVOID Function;
1253 LONG minn, maxn;
1254 ULONG ExportDirSize;
1255
1256 DPRINT("LdrGetExportByName %p %s %hu\n", BaseAddress, SymbolName, Hint);
1257
1258 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1259 RtlImageDirectoryEntryToData(BaseAddress,
1260 TRUE,
1261 IMAGE_DIRECTORY_ENTRY_EXPORT,
1262 &ExportDirSize);
1263 if (ExportDir == NULL)
1264 {
1265 DPRINT1("LdrGetExportByName(): no export directory, "
1266 "can't lookup %s/%hu!\n", SymbolName, Hint);
1267 return NULL;
1268 }
1269
1270
1271 //The symbol names may be missing entirely
1272 if (ExportDir->AddressOfNames == 0)
1273 {
1274 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1275 return NULL;
1276 }
1277
1278 /*
1279 * Get header pointers
1280 */
1281 ExNames = (PDWORD *)RVA(BaseAddress,
1282 ExportDir->AddressOfNames);
1283 ExOrdinals = (USHORT *)RVA(BaseAddress,
1284 ExportDir->AddressOfNameOrdinals);
1285 ExFunctions = (PDWORD *)RVA(BaseAddress,
1286 ExportDir->AddressOfFunctions);
1287
1288 /*
1289 * Check the hint first
1290 */
1291 if (Hint < ExportDir->NumberOfNames)
1292 {
1293 ExName = RVA(BaseAddress, ExNames[Hint]);
1294 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
1295 {
1296 Ordinal = ExOrdinals[Hint];
1297 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1298 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1299 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1300 {
1301 DPRINT("Forward: %s\n", (PCHAR)Function);
1302 Function = LdrFixupForward((PCHAR)Function);
1303 if (Function == NULL)
1304 {
1305 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
1306 }
1307 return Function;
1308 }
1309 if (Function != NULL)
1310 return Function;
1311 }
1312 }
1313
1314 /*
1315 * Binary search
1316 */
1317 minn = 0;
1318 maxn = ExportDir->NumberOfNames - 1;
1319 while (minn <= maxn)
1320 {
1321 LONG mid;
1322 LONG res;
1323
1324 mid = (minn + maxn) / 2;
1325
1326 ExName = RVA(BaseAddress, ExNames[mid]);
1327 res = strcmp(ExName, (PCHAR)SymbolName);
1328 if (res == 0)
1329 {
1330 Ordinal = ExOrdinals[mid];
1331 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1332 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1333 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1334 {
1335 DPRINT("Forward: %s\n", (PCHAR)Function);
1336 Function = LdrFixupForward((PCHAR)Function);
1337 if (Function == NULL)
1338 {
1339 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
1340 }
1341 return Function;
1342 }
1343 if (Function != NULL)
1344 return Function;
1345 }
1346 else if (minn == maxn)
1347 {
1348 DPRINT("LdrGetExportByName(): binary search failed\n");
1349 break;
1350 }
1351 else if (res > 0)
1352 {
1353 maxn = mid - 1;
1354 }
1355 else
1356 {
1357 minn = mid + 1;
1358 }
1359 }
1360
1361 DPRINT("LdrGetExportByName(): failed to find %s\n",SymbolName);
1362 return (PVOID)NULL;
1363 }
1364
1365
1366 /**********************************************************************
1367 * NAME LOCAL
1368 * LdrPerformRelocations
1369 *
1370 * DESCRIPTION
1371 * Relocate a DLL's memory image.
1372 *
1373 * ARGUMENTS
1374 *
1375 * RETURN VALUE
1376 *
1377 * REVISIONS
1378 *
1379 * NOTE
1380 *
1381 */
1382 static NTSTATUS
1383 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
1384 PVOID ImageBase)
1385 {
1386 PIMAGE_DATA_DIRECTORY RelocationDDir;
1387 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
1388 ULONG Count, OldProtect, OldProtect2;
1389 SIZE_T ProtectSize;
1390 PVOID Page, ProtectPage, ProtectPage2;
1391 PUSHORT TypeOffset;
1392 ULONG_PTR Delta;
1393 NTSTATUS Status;
1394
1395 if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1396 {
1397 return STATUS_SUCCESS;
1398 }
1399
1400 RelocationDDir =
1401 &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1402
1403 if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
1404 {
1405 return STATUS_SUCCESS;
1406 }
1407
1408 ProtectSize = PAGE_SIZE;
1409 Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
1410 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1411 RelocationDDir->VirtualAddress);
1412 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1413 RelocationDDir->VirtualAddress + RelocationDDir->Size);
1414
1415 while (RelocationDir < RelocationEnd &&
1416 RelocationDir->SizeOfBlock > 0)
1417 {
1418 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
1419 sizeof(USHORT);
1420 Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
1421 TypeOffset = (PUSHORT)(RelocationDir + 1);
1422
1423 /* Unprotect the page(s) we're about to relocate. */
1424 ProtectPage = Page;
1425 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1426 &ProtectPage,
1427 &ProtectSize,
1428 PAGE_READWRITE,
1429 &OldProtect);
1430 if (!NT_SUCCESS(Status))
1431 {
1432 DPRINT1("Failed to unprotect relocation target.\n");
1433 return Status;
1434 }
1435
1436 if (RelocationDir->VirtualAddress + PAGE_SIZE <
1437 NTHeaders->OptionalHeader.SizeOfImage)
1438 {
1439 ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
1440 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1441 &ProtectPage2,
1442 &ProtectSize,
1443 PAGE_READWRITE,
1444 &OldProtect2);
1445 if (!NT_SUCCESS(Status))
1446 {
1447 DPRINT1("Failed to unprotect relocation target (2).\n");
1448 NtProtectVirtualMemory(NtCurrentProcess(),
1449 &ProtectPage,
1450 &ProtectSize,
1451 OldProtect,
1452 &OldProtect);
1453 return Status;
1454 }
1455 }
1456 else
1457 {
1458 ProtectPage2 = NULL;
1459 }
1460
1461 RelocationDir = LdrProcessRelocationBlock((ULONG_PTR)Page,
1462 Count,
1463 TypeOffset,
1464 Delta);
1465 if (RelocationDir == NULL)
1466 return STATUS_UNSUCCESSFUL;
1467
1468 /* Restore old page protection. */
1469 NtProtectVirtualMemory(NtCurrentProcess(),
1470 &ProtectPage,
1471 &ProtectSize,
1472 OldProtect,
1473 &OldProtect);
1474
1475 if (ProtectPage2 != NULL)
1476 {
1477 NtProtectVirtualMemory(NtCurrentProcess(),
1478 &ProtectPage2,
1479 &ProtectSize,
1480 OldProtect2,
1481 &OldProtect2);
1482 }
1483 }
1484
1485 return STATUS_SUCCESS;
1486 }
1487
1488 static NTSTATUS
1489 LdrpGetOrLoadModule(PWCHAR SearchPath,
1490 PCHAR Name,
1491 PLDR_DATA_TABLE_ENTRY* Module,
1492 BOOLEAN Load)
1493 {
1494 ANSI_STRING AnsiDllName;
1495 UNICODE_STRING DllName;
1496 NTSTATUS Status;
1497
1498 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name);
1499
1500 RtlInitAnsiString(&AnsiDllName, Name);
1501 Status = RtlAnsiStringToUnicodeString(&DllName, &AnsiDllName, TRUE);
1502 if (!NT_SUCCESS(Status))
1503 {
1504 return Status;
1505 }
1506
1507 Status = LdrFindEntryForName (&DllName, Module, Load);
1508 if (Load && !NT_SUCCESS(Status))
1509 {
1510 Status = LdrpLoadModule(SearchPath,
1511 0,
1512 &DllName,
1513 Module,
1514 NULL);
1515 if (NT_SUCCESS(Status))
1516 {
1517 Status = LdrFindEntryForName (&DllName, Module, FALSE);
1518 }
1519 if (!NT_SUCCESS(Status))
1520 {
1521 ULONG ErrorResponse;
1522 ULONG_PTR ErrorParameter = (ULONG_PTR)&DllName;
1523
1524 DPRINT1("failed to load %wZ\n", &DllName);
1525
1526 NtRaiseHardError(STATUS_DLL_NOT_FOUND,
1527 1,
1528 1,
1529 &ErrorParameter,
1530 OptionOk,
1531 &ErrorResponse);
1532 }
1533 }
1534 RtlFreeUnicodeString (&DllName);
1535 return Status;
1536 }
1537
1538 void
1539 RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName)
1540 {
1541 ULONG ErrorResponse;
1542 ULONG_PTR ErrorParameters[2];
1543 ANSI_STRING ProcNameAnsi;
1544 UNICODE_STRING ProcName;
1545 CHAR Buffer[8];
1546
1547 if (!FuncName)
1548 {
1549 _snprintf(Buffer, 8, "# %ld", Ordinal);
1550 FuncName = Buffer;
1551 }
1552
1553 RtlInitAnsiString(&ProcNameAnsi, FuncName);
1554 RtlAnsiStringToUnicodeString(&ProcName, &ProcNameAnsi, TRUE);
1555 ErrorParameters[0] = (ULONG_PTR)&ProcName;
1556 ErrorParameters[1] = (ULONG_PTR)DllName;
1557 NtRaiseHardError(STATUS_ENTRYPOINT_NOT_FOUND,
1558 2,
1559 3,
1560 ErrorParameters,
1561 OptionOk,
1562 &ErrorResponse);
1563 RtlFreeUnicodeString(&ProcName);
1564 }
1565
1566 static NTSTATUS
1567 LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
1568 PLDR_DATA_TABLE_ENTRY ImportedModule,
1569 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
1570 {
1571 NTSTATUS Status;
1572 PVOID* ImportAddressList;
1573 PULONG FunctionNameList;
1574 PVOID IATBase;
1575 ULONG OldProtect;
1576 ULONG Ordinal;
1577 SIZE_T IATSize;
1578
1579 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
1580 {
1581 return STATUS_UNSUCCESSFUL;
1582 }
1583
1584 /* Get the import address list. */
1585 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1586
1587 /* Get the list of functions to import. */
1588 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1589 {
1590 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1591 }
1592 else
1593 {
1594 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1595 }
1596
1597 /* Get the size of IAT. */
1598 IATSize = 0;
1599 while (FunctionNameList[IATSize] != 0L)
1600 {
1601 IATSize++;
1602 }
1603
1604 /* No need to fixup anything if IAT is empty */
1605 if (IATSize == 0) return STATUS_SUCCESS;
1606
1607 /* Unprotect the region we are about to write into. */
1608 IATBase = (PVOID)ImportAddressList;
1609 IATSize *= sizeof(PVOID*);
1610 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1611 &IATBase,
1612 &IATSize,
1613 PAGE_READWRITE,
1614 &OldProtect);
1615 if (!NT_SUCCESS(Status))
1616 {
1617 DPRINT1("Failed to unprotect IAT.\n");
1618 return(Status);
1619 }
1620
1621 /* Walk through function list and fixup addresses. */
1622 while (*FunctionNameList != 0L)
1623 {
1624 if ((*FunctionNameList) & 0x80000000)
1625 {
1626 Ordinal = (*FunctionNameList) & 0x7fffffff;
1627 *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
1628 if ((*ImportAddressList) == NULL)
1629 {
1630 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
1631 RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName);
1632 return STATUS_ENTRYPOINT_NOT_FOUND;
1633 }
1634 }
1635 else
1636 {
1637 IMAGE_IMPORT_BY_NAME *pe_name;
1638 pe_name = RVA(Module->DllBase, *FunctionNameList);
1639 *ImportAddressList = LdrGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
1640 if ((*ImportAddressList) == NULL)
1641 {
1642 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
1643 RtlpRaiseImportNotFound((CHAR*)pe_name->Name, 0, &ImportedModule->FullDllName);
1644 return STATUS_ENTRYPOINT_NOT_FOUND;
1645 }
1646 }
1647 ImportAddressList++;
1648 FunctionNameList++;
1649 }
1650
1651 /* Protect the region we are about to write into. */
1652 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1653 &IATBase,
1654 &IATSize,
1655 OldProtect,
1656 &OldProtect);
1657 if (!NT_SUCCESS(Status))
1658 {
1659 DPRINT1("Failed to protect IAT.\n");
1660 return(Status);
1661 }
1662
1663 return STATUS_SUCCESS;
1664 }
1665
1666 static NTSTATUS
1667 LdrpProcessImportDirectory(
1668 PLDR_DATA_TABLE_ENTRY Module,
1669 PLDR_DATA_TABLE_ENTRY ImportedModule,
1670 PCHAR ImportedName)
1671 {
1672 NTSTATUS Status;
1673 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1674 PCHAR Name;
1675 ULONG Size;
1676
1677 DPRINT("LdrpProcessImportDirectory(%p '%wZ', '%s')\n",
1678 Module, &Module->BaseDllName, ImportedName);
1679
1680
1681 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1682 RtlImageDirectoryEntryToData(Module->DllBase,
1683 TRUE,
1684 IMAGE_DIRECTORY_ENTRY_IMPORT,
1685 &Size);
1686 if (ImportModuleDirectory == NULL)
1687 {
1688 return STATUS_UNSUCCESSFUL;
1689 }
1690
1691 while (ImportModuleDirectory->Name)
1692 {
1693 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1694 if (0 == _stricmp(Name, ImportedName))
1695 {
1696 Status = LdrpProcessImportDirectoryEntry(Module,
1697 ImportedModule,
1698 ImportModuleDirectory);
1699 if (!NT_SUCCESS(Status))
1700 {
1701 return Status;
1702 }
1703 }
1704 ImportModuleDirectory++;
1705 }
1706
1707
1708 return STATUS_SUCCESS;
1709 }
1710
1711
1712 static NTSTATUS
1713 LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
1714 PLDR_DATA_TABLE_ENTRY ImportedModule,
1715 PCHAR ImportedName)
1716 {
1717 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1718 NTSTATUS Status;
1719 PVOID* ImportAddressList;
1720 PVOID Start;
1721 PVOID End;
1722 PULONG FunctionNameList;
1723 PVOID IATBase;
1724 ULONG OldProtect;
1725 ULONG Offset;
1726 SIZE_T IATSize;
1727 PIMAGE_NT_HEADERS NTHeaders;
1728 PCHAR Name;
1729 ULONG Size;
1730
1731 DPRINT("LdrpAdjustImportDirectory(Module %p '%wZ', %p '%wZ', '%s')\n",
1732 Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
1733
1734 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1735 RtlImageDirectoryEntryToData(Module->DllBase,
1736 TRUE,
1737 IMAGE_DIRECTORY_ENTRY_IMPORT,
1738 &Size);
1739 if (ImportModuleDirectory == NULL)
1740 {
1741 return STATUS_UNSUCCESSFUL;
1742 }
1743
1744 while (ImportModuleDirectory->Name)
1745 {
1746 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1747 if (0 == _stricmp(Name, (PCHAR)ImportedName))
1748 {
1749
1750 /* Get the import address list. */
1751 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1752
1753 /* Get the list of functions to import. */
1754 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1755 {
1756 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1757 }
1758 else
1759 {
1760 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1761 }
1762
1763 /* Get the size of IAT. */
1764 IATSize = 0;
1765 while (FunctionNameList[IATSize] != 0L)
1766 {
1767 IATSize++;
1768 }
1769
1770 /* Unprotect the region we are about to write into. */
1771 IATBase = (PVOID)ImportAddressList;
1772 IATSize *= sizeof(PVOID*);
1773 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1774 &IATBase,
1775 &IATSize,
1776 PAGE_READWRITE,
1777 &OldProtect);
1778 if (!NT_SUCCESS(Status))
1779 {
1780 DPRINT1("Failed to unprotect IAT.\n");
1781 return(Status);
1782 }
1783
1784 NTHeaders = RtlImageNtHeader (ImportedModule->DllBase);
1785 Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
1786 End = (PVOID)((ULONG_PTR)Start + ImportedModule->SizeOfImage);
1787 Offset = (ULONG)((ULONG_PTR)ImportedModule->DllBase - (ULONG_PTR)Start);
1788
1789 /* Walk through function list and fixup addresses. */
1790 while (*FunctionNameList != 0L)
1791 {
1792 if (*ImportAddressList >= Start && *ImportAddressList < End)
1793 {
1794 (*ImportAddressList) = (PVOID)((ULONG_PTR)(*ImportAddressList) + Offset);
1795 }
1796 ImportAddressList++;
1797 FunctionNameList++;
1798 }
1799
1800 /* Protect the region we are about to write into. */
1801 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1802 &IATBase,
1803 &IATSize,
1804 OldProtect,
1805 &OldProtect);
1806 if (!NT_SUCCESS(Status))
1807 {
1808 DPRINT1("Failed to protect IAT.\n");
1809 return(Status);
1810 }
1811 }
1812 ImportModuleDirectory++;
1813 }
1814 return STATUS_SUCCESS;
1815 }
1816
1817
1818 /**********************************************************************
1819 * NAME LOCAL
1820 * LdrFixupImports
1821 *
1822 * DESCRIPTION
1823 * Compute the entry point for every symbol the DLL imports
1824 * from other modules.
1825 *
1826 * ARGUMENTS
1827 *
1828 * RETURN VALUE
1829 *
1830 * REVISIONS
1831 *
1832 * NOTE
1833 *
1834 */
1835 static NTSTATUS
1836 LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
1837 IN PLDR_DATA_TABLE_ENTRY Module)
1838 {
1839 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1840 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent;
1841 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
1842 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
1843 PIMAGE_TLS_DIRECTORY TlsDirectory;
1844 ULONG TlsSize = 0;
1845 NTSTATUS Status = STATUS_SUCCESS;
1846 PLDR_DATA_TABLE_ENTRY ImportedModule;
1847 PCHAR ImportedName;
1848 PWSTR ModulePath;
1849 ULONG Size;
1850 ULONG_PTR cookie;
1851
1852 DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
1853
1854 /* Check for tls data */
1855 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
1856 RtlImageDirectoryEntryToData(Module->DllBase,
1857 TRUE,
1858 IMAGE_DIRECTORY_ENTRY_TLS,
1859 &Size);
1860 if (TlsDirectory)
1861 {
1862 TlsSize = TlsDirectory->EndAddressOfRawData
1863 - TlsDirectory->StartAddressOfRawData
1864 + TlsDirectory->SizeOfZeroFill;
1865
1866 if (TlsSize > 0 && NtCurrentPeb()->Ldr->Initialized)
1867 {
1868 TRACE_LDR("Trying to dynamically load %wZ which contains a TLS directory\n",
1869 &Module->BaseDllName);
1870 TlsDirectory = NULL;
1871 }
1872 }
1873
1874 if (!create_module_activation_context( Module ))
1875 {
1876 if (Module->EntryPointActivationContext == NULL)
1877 {
1878 DPRINT("EntryPointActivationContext has not be allocated\n");
1879 DPRINT("Module->DllBaseName %wZ\n", Module->BaseDllName);
1880 }
1881 RtlActivateActivationContext( 0, Module->EntryPointActivationContext, &cookie );
1882 }
1883
1884 /*
1885 * Process each import module.
1886 */
1887 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1888 RtlImageDirectoryEntryToData(Module->DllBase,
1889 TRUE,
1890 IMAGE_DIRECTORY_ENTRY_IMPORT,
1891 &Size);
1892
1893 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
1894 RtlImageDirectoryEntryToData(Module->DllBase,
1895 TRUE,
1896 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
1897 &Size);
1898
1899 if (BoundImportDescriptor != NULL && ImportModuleDirectory == NULL)
1900 {
1901 DPRINT1("%wZ has only a bound import directory\n", &Module->BaseDllName);
1902 return STATUS_UNSUCCESSFUL;
1903 }
1904 if (BoundImportDescriptor)
1905 {
1906 DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor);
1907
1908 BoundImportDescriptorCurrent = BoundImportDescriptor;
1909 while (BoundImportDescriptorCurrent->OffsetModuleName)
1910 {
1911 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
1912 TRACE_LDR("%wZ bound to %s\n", &Module->BaseDllName, ImportedName);
1913 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
1914 if (!NT_SUCCESS(Status))
1915 {
1916 DPRINT1("failed to load %s\n", ImportedName);
1917 return Status;
1918 }
1919 if (Module == ImportedModule)
1920 {
1921 LdrpDecrementLoadCount(Module, FALSE);
1922 }
1923 if (ImportedModule->TimeDateStamp != BoundImportDescriptorCurrent->TimeDateStamp)
1924 {
1925 TRACE_LDR("%wZ has stale binding to %wZ\n",
1926 &Module->BaseDllName, &ImportedModule->BaseDllName);
1927 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1928 if (!NT_SUCCESS(Status))
1929 {
1930 DPRINT1("failed to import %s\n", ImportedName);
1931 return Status;
1932 }
1933 }
1934 else
1935 {
1936 BOOLEAN WrongForwarder;
1937 WrongForwarder = FALSE;
1938 if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1939 {
1940 TRACE_LDR("%wZ has stale binding to %s\n",
1941 &Module->BaseDllName, ImportedName);
1942 }
1943 else
1944 {
1945 TRACE_LDR("%wZ has correct binding to %wZ\n",
1946 &Module->BaseDllName, &ImportedModule->BaseDllName);
1947 }
1948 if (BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs)
1949 {
1950 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef;
1951 ULONG i;
1952 PLDR_DATA_TABLE_ENTRY ForwarderModule;
1953 PCHAR ForwarderName;
1954
1955 BoundForwarderRef = (PIMAGE_BOUND_FORWARDER_REF)(BoundImportDescriptorCurrent + 1);
1956 for (i = 0; i < BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs; i++, BoundForwarderRef++)
1957 {
1958 ForwarderName = (PCHAR)BoundImportDescriptor + BoundForwarderRef->OffsetModuleName;
1959 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1960 &Module->BaseDllName, ForwarderName, ImportedName);
1961 Status = LdrpGetOrLoadModule(SearchPath, ForwarderName, &ForwarderModule, TRUE);
1962 if (!NT_SUCCESS(Status))
1963 {
1964 DPRINT1("failed to load %s\n", ForwarderName);
1965 return Status;
1966 }
1967 if (Module == ImportedModule)
1968 {
1969 LdrpDecrementLoadCount(Module, FALSE);
1970 }
1971 if (ForwarderModule->TimeDateStamp != BoundForwarderRef->TimeDateStamp ||
1972 ForwarderModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1973 {
1974 TRACE_LDR("%wZ has stale binding to %s\n",
1975 &Module->BaseDllName, ForwarderName);
1976 WrongForwarder = TRUE;
1977 }
1978 else
1979 {
1980 TRACE_LDR("%wZ has correct binding to %s\n",
1981 &Module->BaseDllName, ForwarderName);
1982 }
1983 }
1984 }
1985 if (WrongForwarder ||
1986 ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1987 {
1988 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1989 if (!NT_SUCCESS(Status))
1990 {
1991 DPRINT1("failed to import %s\n", ImportedName);
1992 return Status;
1993 }
1994 }
1995 else if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1996 {
1997 TRACE_LDR("Adjust imports for %s from %wZ\n",
1998 ImportedName, &Module->BaseDllName);
1999 Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName);
2000 if (!NT_SUCCESS(Status))
2001 {
2002 DPRINT1("failed to adjust import entries for %s\n", ImportedName);
2003 return Status;
2004 }
2005 }
2006 else if (WrongForwarder)
2007 {
2008 /*
2009 * FIXME:
2010 * Update only forwarders
2011 */
2012 TRACE_LDR("Stale BIND %s from %wZ\n",
2013 ImportedName, &Module->BaseDllName);
2014 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
2015 if (!NT_SUCCESS(Status))
2016 {
2017 DPRINT1("faild to import %s\n", ImportedName);
2018 return Status;
2019 }
2020 }
2021 else
2022 {
2023 /* nothing to do */
2024 }
2025 }
2026 BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1;
2027 }
2028 }
2029 else if (ImportModuleDirectory)
2030 {
2031 DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory);
2032
2033 ImportModuleDirectoryCurrent = ImportModuleDirectory;
2034 while (ImportModuleDirectoryCurrent->Name)
2035 {
2036 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2037 TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName);
2038
2039 if (SearchPath == NULL)
2040 {
2041 ModulePath = LdrpQueryAppPaths(Module->BaseDllName.Buffer);
2042
2043 Status = LdrpGetOrLoadModule(ModulePath, ImportedName, &ImportedModule, TRUE);
2044 if (ModulePath != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, ModulePath);
2045 if (NT_SUCCESS(Status)) goto Success;
2046 }
2047
2048 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
2049 if (!NT_SUCCESS(Status))
2050 {
2051 DPRINT1("failed to load %s\n", ImportedName);
2052 break;
2053 }
2054 Success:
2055 if (Module == ImportedModule)
2056 {
2057 LdrpDecrementLoadCount(Module, FALSE);
2058 }
2059
2060 TRACE_LDR("Initializing imports for %wZ from %s\n",
2061 &Module->BaseDllName, ImportedName);
2062 Status = LdrpProcessImportDirectoryEntry(Module, ImportedModule, ImportModuleDirectoryCurrent);
2063 if (!NT_SUCCESS(Status))
2064 {
2065 DPRINT1("failed to import %s\n", ImportedName);
2066 break;
2067 }
2068 ImportModuleDirectoryCurrent++;
2069 }
2070
2071 if (!NT_SUCCESS(Status))
2072 {
2073 NTSTATUS errorStatus = Status;
2074
2075 while (ImportModuleDirectoryCurrent >= ImportModuleDirectory)
2076 {
2077 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2078
2079 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2080 if (NT_SUCCESS(Status) && Module != ImportedModule)
2081 {
2082 Status = LdrpUnloadModule(ImportedModule, FALSE);
2083 if (!NT_SUCCESS(Status)) DPRINT1("unable to unload %s\n", ImportedName);
2084 }
2085 ImportModuleDirectoryCurrent--;
2086 }
2087 return errorStatus;
2088 }
2089 }
2090
2091 if (TlsDirectory && TlsSize > 0)
2092 {
2093 LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
2094 }
2095
2096 if (Module->EntryPointActivationContext) RtlDeactivateActivationContext( 0, cookie );
2097
2098 return STATUS_SUCCESS;
2099 }
2100
2101
2102 /**********************************************************************
2103 * NAME
2104 * LdrPEStartup
2105 *
2106 * DESCRIPTION
2107 * 1. Relocate, if needed the EXE.
2108 * 2. Fixup any imported symbol.
2109 * 3. Compute the EXE's entry point.
2110 *
2111 * ARGUMENTS
2112 * ImageBase
2113 * Address at which the EXE's image
2114 * is loaded.
2115 *
2116 * SectionHandle
2117 * Handle of the section that contains
2118 * the EXE's image.
2119 *
2120 * RETURN VALUE
2121 * NULL on error; otherwise the entry point
2122 * to call for initializing the DLL.
2123 *
2124 * REVISIONS
2125 *
2126 * NOTE
2127 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
2128 * Currently the function is only used for the exe.
2129 */
2130 PEPFUNC LdrPEStartup (PVOID ImageBase,
2131 HANDLE SectionHandle,
2132 PLDR_DATA_TABLE_ENTRY* Module,
2133 PWSTR FullDosName)
2134 {
2135 NTSTATUS Status;
2136 PEPFUNC EntryPoint = NULL;
2137 PIMAGE_DOS_HEADER DosHeader;
2138 PIMAGE_NT_HEADERS NTHeaders;
2139 PLDR_DATA_TABLE_ENTRY tmpModule;
2140 PVOID ActivationContextStack;
2141
2142 DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
2143 ImageBase, SectionHandle);
2144
2145 /*
2146 * Overlay DOS and WNT headers structures
2147 * to the DLL's image.
2148 */
2149 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
2150 NTHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR)ImageBase + DosHeader->e_lfanew);
2151
2152 /*
2153 * If the base address is different from the
2154 * one the DLL is actually loaded, perform any
2155 * relocation.
2156 */
2157 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2158 {
2159 DPRINT("LDR: Performing relocations\n");
2160 Status = LdrPerformRelocations(NTHeaders, ImageBase);
2161 if (!NT_SUCCESS(Status))
2162 {
2163 DPRINT1("LdrPerformRelocations() failed\n");
2164 return NULL;
2165 }
2166 }
2167
2168 if (Module != NULL)
2169 {
2170 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
2171 (*Module)->SectionPointer = SectionHandle;
2172 }
2173 else
2174 {
2175 Module = &tmpModule;
2176 Status = LdrFindEntryForAddress(ImageBase, Module);
2177 if (!NT_SUCCESS(Status))
2178 {
2179 return NULL;
2180 }
2181 }
2182
2183 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2184 {
2185 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2186 }
2187
2188 /* Allocate memory for the ActivationContextStack */
2189 /* FIXME: Verify RtlAllocateActivationContextStack behavior */
2190 Status = RtlAllocateActivationContextStack(&ActivationContextStack);
2191 if (NT_SUCCESS(Status))
2192 {
2193 DPRINT("ActivationContextStack %x\n",ActivationContextStack);
2194 DPRINT("ActiveFrame %x\n", ((PACTIVATION_CONTEXT_STACK)ActivationContextStack)->ActiveFrame);
2195 NtCurrentTeb()->ActivationContextStackPointer = ActivationContextStack;
2196 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL;
2197 }
2198 else
2199 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
2200
2201 /*
2202 * If the DLL's imports symbols from other
2203 * modules, fixup the imported calls entry points.
2204 */
2205 DPRINT("About to fixup imports\n");
2206 Status = LdrFixupImports(NULL, *Module);
2207 if (!NT_SUCCESS(Status))
2208 {
2209 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName);
2210 return NULL;
2211 }
2212 DPRINT("Fixup done\n");
2213 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2214 Status = LdrpInitializeTlsForProccess();
2215 if (NT_SUCCESS(Status))
2216 {
2217 Status = LdrpAttachProcess();
2218 }
2219 if (NT_SUCCESS(Status))
2220 {
2221 LdrpTlsCallback(*Module, DLL_PROCESS_ATTACH);
2222 }
2223
2224
2225 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
2226 if (!NT_SUCCESS(Status))
2227 {
2228 return NULL;
2229 }
2230
2231 /*
2232 * Compute the DLL's entry point's address.
2233 */
2234 DPRINT("ImageBase = %p\n", ImageBase);
2235 DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
2236 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
2237 {
2238 EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase
2239 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
2240 }
2241 DPRINT("LdrPEStartup() = %p\n",EntryPoint);
2242 return EntryPoint;
2243 }
2244
2245 static NTSTATUS
2246 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
2247 IN ULONG LoadFlags,
2248 IN PUNICODE_STRING Name,
2249 PLDR_DATA_TABLE_ENTRY *Module,
2250 PVOID *BaseAddress OPTIONAL)
2251 {
2252 UNICODE_STRING AdjustedName;
2253 UNICODE_STRING FullDosName;
2254 NTSTATUS Status;
2255 PLDR_DATA_TABLE_ENTRY tmpModule;
2256 HANDLE SectionHandle;
2257 SIZE_T ViewSize;
2258 PVOID ImageBase;
2259 PIMAGE_NT_HEADERS NtHeaders;
2260 BOOLEAN MappedAsDataFile;
2261 PVOID ArbitraryUserPointer;
2262
2263 if (Module == NULL)
2264 {
2265 Module = &tmpModule;
2266 }
2267 /* adjust the full dll name */
2268 LdrAdjustDllName(&AdjustedName, Name, FALSE);
2269
2270 DPRINT("%wZ\n", &AdjustedName);
2271
2272 MappedAsDataFile = FALSE;
2273 /* Test if dll is already loaded */
2274 Status = LdrFindEntryForName(&AdjustedName, Module, TRUE);
2275 if (NT_SUCCESS(Status))
2276 {
2277 RtlFreeUnicodeString(&AdjustedName);
2278 if (NULL != BaseAddress)
2279 {
2280 *BaseAddress = (*Module)->DllBase;
2281 }
2282 }
2283 else
2284 {
2285 /* Open or create dll image section */
2286 Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle);
2287 if (!NT_SUCCESS(Status))
2288 {
2289 MappedAsDataFile = (0 != (LoadFlags & LOAD_LIBRARY_AS_DATAFILE));
2290 Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName,
2291 MappedAsDataFile, &SectionHandle);
2292 }
2293 if (!NT_SUCCESS(Status))
2294 {
2295 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName, Status);
2296 RtlFreeUnicodeString(&AdjustedName);
2297 return Status;
2298 }
2299 RtlFreeUnicodeString(&AdjustedName);
2300 /* Map the dll into the process */
2301 ViewSize = 0;
2302 ImageBase = 0;
2303 ArbitraryUserPointer = NtCurrentTeb()->NtTib.ArbitraryUserPointer;
2304 NtCurrentTeb()->NtTib.ArbitraryUserPointer = FullDosName.Buffer;
2305 Status = NtMapViewOfSection(SectionHandle,
2306 NtCurrentProcess(),
2307 &ImageBase,
2308 0,
2309 0,
2310 NULL,
2311 &ViewSize,
2312 ViewShare,
2313 0,
2314 PAGE_READONLY);
2315 NtCurrentTeb()->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
2316 if (!NT_SUCCESS(Status))
2317 {
2318 DPRINT1("map view of section failed (Status 0x%08lx)\n", Status);
2319 RtlFreeUnicodeString(&FullDosName);
2320 NtClose(SectionHandle);
2321 return(Status);
2322 }
2323 if (NULL != BaseAddress)
2324 {
2325 *BaseAddress = ImageBase;
2326 }
2327 if (!MappedAsDataFile)
2328 {
2329 /* Get and check the NT headers */
2330 NtHeaders = RtlImageNtHeader(ImageBase);
2331 if (NtHeaders == NULL)
2332 {
2333 DPRINT1("RtlImageNtHeaders() failed\n");
2334 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2335 NtClose (SectionHandle);
2336 RtlFreeUnicodeString(&FullDosName);
2337 return STATUS_UNSUCCESSFUL;
2338 }
2339 }
2340 DPRINT("Mapped %wZ at %x\n", &FullDosName, ImageBase);
2341 if (MappedAsDataFile)
2342 {
2343 ASSERT(NULL != BaseAddress);
2344 if (NULL != BaseAddress)
2345 {
2346 *BaseAddress = (PVOID) ((char *) *BaseAddress + 1);
2347 }
2348 *Module = NULL;
2349 RtlFreeUnicodeString(&FullDosName);
2350 NtClose(SectionHandle);
2351 return STATUS_SUCCESS;
2352 }
2353 /* If the base address is different from the
2354 * one the DLL is actually loaded, perform any
2355 * relocation. */
2356 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2357 {
2358 DPRINT1("Relocating (%lx -> %p) %wZ\n",
2359 NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
2360 Status = LdrPerformRelocations(NtHeaders, ImageBase);
2361 if (!NT_SUCCESS(Status))
2362 {
2363 DPRINT1("LdrPerformRelocations() failed\n");
2364 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2365 NtClose (SectionHandle);
2366 RtlFreeUnicodeString(&FullDosName);
2367 return STATUS_UNSUCCESSFUL;
2368 }
2369 }
2370 *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer);
2371 (*Module)->SectionPointer = SectionHandle;
2372 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2373 {
2374 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2375 }
2376 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
2377 {
2378 (*Module)->Flags |= LDRP_IMAGE_DLL;
2379 }
2380 /* fixup the imported calls entry points */
2381 Status = LdrFixupImports(SearchPath, *Module);
2382 if (!NT_SUCCESS(Status))
2383 {
2384 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
2385 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2386 NtClose (SectionHandle);
2387 RtlFreeUnicodeString (&FullDosName);
2388 RtlFreeUnicodeString (&(*Module)->FullDllName);
2389 RtlFreeUnicodeString (&(*Module)->BaseDllName);
2390 RemoveEntryList (&(*Module)->InLoadOrderLinks);
2391 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2392 return Status;
2393 }
2394
2395 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2396 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
2397 &(*Module)->InInitializationOrderLinks);
2398 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2399 }
2400 return STATUS_SUCCESS;
2401 }
2402
2403 static NTSTATUS
2404 LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
2405 BOOLEAN Unload)
2406 {
2407 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
2408 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
2409 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
2410 PCHAR ImportedName;
2411 PLDR_DATA_TABLE_ENTRY ImportedModule;
2412 NTSTATUS Status = 0;
2413 LONG LoadCount;
2414 ULONG Size;
2415
2416 if (Unload)
2417 {
2418 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2419 }
2420
2421 LoadCount = LdrpDecrementLoadCount(Module, Unload);
2422
2423 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
2424
2425 if (LoadCount == 0)
2426 {
2427 /* ?????????????????? */
2428 }
2429 else if (!(Module->Flags & LDRP_STATIC_LINK) && LoadCount == 1)
2430 {
2431 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
2432 RtlImageDirectoryEntryToData(Module->DllBase,
2433 TRUE,
2434 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
2435 &Size);
2436 if (BoundImportDescriptor)
2437 {
2438 /* dereferencing all imported modules, use the bound import descriptor */
2439 BoundImportDescriptorCurrent = BoundImportDescriptor;
2440 while (BoundImportDescriptorCurrent->OffsetModuleName)
2441 {
2442 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
2443 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2444 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2445 if (!NT_SUCCESS(Status))
2446 {
2447 DPRINT1("unable to found imported modul %s\n", ImportedName);
2448 }
2449 else
2450 {
2451 if (Module != ImportedModule)
2452 {
2453 Status = LdrpUnloadModule(ImportedModule, FALSE);
2454 if (!NT_SUCCESS(Status))
2455 {
2456 DPRINT1("unable to unload %s\n", ImportedName);
2457 }
2458 }
2459 }
2460 BoundImportDescriptorCurrent++;
2461 }
2462 }
2463 else
2464 {
2465 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
2466 RtlImageDirectoryEntryToData(Module->DllBase,
2467 TRUE,
2468 IMAGE_DIRECTORY_ENTRY_IMPORT,
2469 &Size);
2470 if (ImportModuleDirectory)
2471 {
2472 /* dereferencing all imported modules, use the import descriptor */
2473 while (ImportModuleDirectory->Name)
2474 {
2475 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
2476 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2477 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2478 if (!NT_SUCCESS(Status))
2479 {
2480 DPRINT1("unable to found imported modul %s\n", ImportedName);
2481 }
2482 else
2483 {
2484 if (Module != ImportedModule)
2485 {
2486 Status = LdrpUnloadModule(ImportedModule, FALSE);
2487 if (!NT_SUCCESS(Status))
2488 {
2489 DPRINT1("unable to unload %s\n", ImportedName);
2490 }
2491 }
2492 }
2493 ImportModuleDirectory++;
2494 }
2495 }
2496 }
2497 }
2498
2499 if (Unload)
2500 {
2501 if (!(Module->Flags & LDRP_STATIC_LINK))
2502 {
2503 LdrpDetachProcess(FALSE);
2504 }
2505
2506 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2507 }
2508 return STATUS_SUCCESS;
2509
2510 }
2511
2512 /*
2513 * @implemented
2514 */
2515 NTSTATUS NTAPI
2516 LdrUnloadDll (IN PVOID BaseAddress)
2517 {
2518 PLDR_DATA_TABLE_ENTRY Module;
2519 NTSTATUS Status;
2520
2521 if (BaseAddress == NULL)
2522 return STATUS_SUCCESS;
2523
2524 if (LdrMappedAsDataFile(&BaseAddress))
2525 {
2526 Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
2527 }
2528 else
2529 {
2530 Status = LdrFindEntryForAddress(BaseAddress, &Module);
2531 if (NT_SUCCESS(Status))
2532 {
2533 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
2534 Status = LdrpUnloadModule(Module, TRUE);
2535 }
2536 }
2537
2538 return Status;
2539 }
2540
2541 /*
2542 * @implemented
2543 */
2544 NTSTATUS NTAPI
2545 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
2546 {
2547 PLIST_ENTRY ModuleListHead;
2548 PLIST_ENTRY Entry;
2549 PLDR_DATA_TABLE_ENTRY Module;
2550 NTSTATUS Status;
2551
2552 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
2553
2554 Status = STATUS_DLL_NOT_FOUND;
2555 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2556 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2557 Entry = ModuleListHead->Flink;
2558 while (Entry != ModuleListHead)
2559 {
2560 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2561
2562 DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module->BaseDllName, Module->DllBase);
2563
2564 if (Module->DllBase == BaseAddress)
2565 {
2566 if (Module->TlsIndex == 0xFFFF)
2567 {
2568 Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
2569 Status = STATUS_SUCCESS;
2570 }
2571 break;
2572 }
2573 Entry = Entry->Flink;
2574 }
2575 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2576 return Status;
2577 }
2578
2579 /*
2580 * @implemented
2581 */
2582 NTSTATUS NTAPI
2583 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
2584 IN PULONG DllCharacteristics,
2585 IN PUNICODE_STRING DllName,
2586 OUT PVOID *DllHandle)
2587 {
2588 PLDR_DATA_TABLE_ENTRY Module;
2589 NTSTATUS Status;
2590
2591 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
2592 DllName, DllPath ? DllPath : L"");
2593
2594 /* NULL is the current executable */
2595 if (DllName == NULL)
2596 {
2597 *DllHandle = ExeModule->DllBase;
2598 DPRINT("BaseAddress 0x%lx\n", *DllHandle);
2599 return STATUS_SUCCESS;
2600 }
2601
2602 Status = LdrFindEntryForName(DllName, &Module, FALSE);
2603 if (NT_SUCCESS(Status))
2604 {
2605 *DllHandle = Module->DllBase;
2606 return STATUS_SUCCESS;
2607 }
2608
2609 DPRINT("Failed to find dll %wZ\n", DllName);
2610 *DllHandle = NULL;
2611 return STATUS_DLL_NOT_FOUND;
2612 }
2613
2614 /*
2615 * @implemented
2616 */
2617 NTSTATUS NTAPI
2618 LdrAddRefDll(IN ULONG Flags,
2619 IN PVOID BaseAddress)
2620 {
2621 PLIST_ENTRY ModuleListHead;
2622 PLIST_ENTRY Entry;
2623 PLDR_DATA_TABLE_ENTRY Module;
2624 NTSTATUS Status;
2625
2626 if (Flags & ~(LDR_PIN_MODULE))
2627 {
2628 return STATUS_INVALID_PARAMETER;
2629 }
2630
2631 Status = STATUS_DLL_NOT_FOUND;
2632 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2633 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2634 Entry = ModuleListHead->Flink;
2635 while (Entry != ModuleListHead)
2636 {
2637 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2638
2639 if (Module->DllBase == BaseAddress)
2640 {
2641 if (Flags & LDR_PIN_MODULE)
2642 {
2643 Module->Flags |= LDRP_STATIC_LINK;
2644 }
2645 else
2646 {
2647 LdrpIncrementLoadCount(Module,
2648 FALSE);
2649 }
2650 Status = STATUS_SUCCESS;
2651 break;
2652 }
2653 Entry = Entry->Flink;
2654 }
2655 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2656 return Status;
2657 }
2658
2659 /*
2660 * @implemented
2661 */
2662 PVOID NTAPI
2663 RtlPcToFileHeader(IN PVOID PcValue,
2664 PVOID* BaseOfImage)
2665 {
2666 PLIST_ENTRY ModuleListHead;
2667 PLIST_ENTRY Entry;
2668 PLDR_DATA_TABLE_ENTRY Module;
2669 PVOID ImageBase = NULL;
2670
2671 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2672 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2673 Entry = ModuleListHead->Flink;
2674 while (Entry != ModuleListHead)
2675 {
2676 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2677
2678 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
2679 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
2680 {
2681 ImageBase = Module->DllBase;
2682 break;
2683 }
2684 Entry = Entry->Flink;
2685 }
2686 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2687
2688 *BaseOfImage = ImageBase;
2689 return ImageBase;
2690 }
2691
2692 /*
2693 * @implemented
2694 */
2695 NTSTATUS NTAPI
2696 LdrGetProcedureAddress (IN PVOID BaseAddress,
2697 IN PANSI_STRING Name,
2698 IN ULONG Ordinal,
2699 OUT PVOID *ProcedureAddress)
2700 {
2701 NTSTATUS Status = STATUS_PROCEDURE_NOT_FOUND;
2702 if (Name && Name->Length)
2703 {
2704 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
2705 }
2706 else
2707 {
2708 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
2709 }
2710
2711 DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
2712 BaseAddress, Name, Ordinal, ProcedureAddress);
2713
2714 _SEH2_TRY
2715 {
2716 if (Name && Name->Length)
2717 {
2718 /* by name */
2719 *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
2720 if (*ProcedureAddress != NULL)
2721 {
2722 Status = STATUS_SUCCESS;
2723 }
2724 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
2725 }
2726 else
2727 {
2728 /* by ordinal */
2729 Ordinal &= 0x0000FFFF;
2730 *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
2731 if (*ProcedureAddress)
2732 {
2733 Status = STATUS_SUCCESS;
2734 }
2735 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal);
2736 }
2737 }
2738 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2739 {
2740 Status = STATUS_DLL_NOT_FOUND;
2741 }
2742 _SEH2_END;
2743
2744 return Status;
2745 }
2746
2747 /**********************************************************************
2748 * NAME LOCAL
2749 * LdrpDetachProcess
2750 *
2751 * DESCRIPTION
2752 * Unload dll's which are no longer referenced from others dll's
2753 *
2754 * ARGUMENTS
2755 * none
2756 *
2757 * RETURN VALUE
2758 * none
2759 *
2760 * REVISIONS
2761 *
2762 * NOTE
2763 * The loader lock must be held on enty.
2764 */
2765 static VOID
2766 LdrpDetachProcess(BOOLEAN UnloadAll)
2767 {
2768 PLIST_ENTRY ModuleListHead;
2769 PLIST_ENTRY Entry;
2770 PLDR_DATA_TABLE_ENTRY Module;
2771 static ULONG CallingCount = 0;
2772
2773 DPRINT("LdrpDetachProcess() called for %wZ\n",
2774 &ExeModule->BaseDllName);
2775
2776 if (UnloadAll)
2777 LdrpDllShutdownInProgress = TRUE;
2778
2779 CallingCount++;
2780
2781 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2782 Entry = ModuleListHead->Blink;
2783 while (Entry != ModuleListHead)
2784 {
2785 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2786 if (((UnloadAll && Module->LoadCount == LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0) &&
2787 Module->Flags & LDRP_ENTRY_PROCESSED &&
2788 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2789 {
2790 Module->Flags |= LDRP_UNLOAD_IN_PROGRESS;
2791 if (Module == LdrpLastModule)
2792 {
2793 LdrpLastModule = NULL;
2794 }
2795 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED)
2796 {
2797 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2798 &Module->BaseDllName, Module->EntryPoint);
2799 LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2800 }
2801 else
2802 {
2803 TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
2804 }
2805 Entry = ModuleListHead->Blink;
2806 }
2807 else
2808 {
2809 Entry = Entry->Blink;
2810 }
2811 }
2812
2813 if (CallingCount == 1)
2814 {
2815 Entry = ModuleListHead->Blink;
2816 while (Entry != ModuleListHead)
2817 {
2818 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2819 Entry = Entry->Blink;
2820 if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
2821 ((UnloadAll && Module->LoadCount != LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0))
2822 {
2823 /* remove the module entry from the list */
2824 RemoveEntryList (&Module->InLoadOrderLinks);
2825 RemoveEntryList (&Module->InInitializationOrderLinks);
2826
2827 NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase);
2828 NtClose (Module->SectionPointer);
2829
2830 TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
2831
2832 RtlFreeUnicodeString (&Module->FullDllName);
2833 RtlFreeUnicodeString (&Module->BaseDllName);
2834
2835 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2836 }
2837 }
2838 }
2839 CallingCount--;
2840 DPRINT("LdrpDetachProcess() done\n");
2841 }
2842
2843 /**********************************************************************
2844 * NAME LOCAL
2845 * LdrpAttachProcess
2846 *
2847 * DESCRIPTION
2848 * Initialize all dll's which are prepered for loading
2849 *
2850 * ARGUMENTS
2851 * none
2852 *
2853 * RETURN VALUE
2854 * status
2855 *
2856 * REVISIONS
2857 *
2858 * NOTE
2859 * The loader lock must be held on entry.
2860 *
2861 */
2862 static NTSTATUS
2863 LdrpAttachProcess(VOID)
2864 {
2865 PLIST_ENTRY ModuleListHead;
2866 PLIST_ENTRY Entry;
2867 PLDR_DATA_TABLE_ENTRY Module;
2868 BOOLEAN Result;
2869 NTSTATUS Status = STATUS_SUCCESS;
2870
2871 DPRINT("LdrpAttachProcess() called for %wZ\n",
2872 &ExeModule->BaseDllName);
2873
2874 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2875 Entry = ModuleListHead->Flink;
2876 while (Entry != ModuleListHead)
2877 {
2878 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2879 if (!(Module->Flags & (LDRP_LOAD_IN_PROGRESS|LDRP_UNLOAD_IN_PROGRESS|LDRP_ENTRY_PROCESSED)))
2880 {
2881 Module->Flags |= LDRP_LOAD_IN_PROGRESS;
2882 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2883 &Module->BaseDllName, Module->EntryPoint);
2884 Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2885 if (!Result)
2886 {
2887 Status = STATUS_DLL_INIT_FAILED;
2888 break;
2889 }
2890 if (Module->Flags & LDRP_IMAGE_DLL && Module->EntryPoint != 0)
2891 {
2892 Module->Flags |= LDRP_PROCESS_ATTACH_CALLED|LDRP_ENTRY_PROCESSED;
2893 }
2894 else
2895 {
2896 Module->Flags |= LDRP_ENTRY_PROCESSED;
2897 }
2898 Module->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2899 }
2900 Entry = Entry->Flink;
2901 }
2902
2903 DPRINT("LdrpAttachProcess() done\n");
2904
2905 return Status;
2906 }
2907
2908 /*
2909 * @implemented
2910 */
2911 BOOLEAN NTAPI
2912 RtlDllShutdownInProgress (VOID)
2913 {
2914 return LdrpDllShutdownInProgress;
2915 }
2916
2917 /*
2918 * @implemented
2919 */
2920 NTSTATUS NTAPI
2921 LdrShutdownProcess (VOID)
2922 {
2923 LdrpDetachProcess(TRUE);
2924 return STATUS_SUCCESS;
2925 }
2926
2927 /*
2928 * @implemented
2929 */
2930
2931 NTSTATUS
2932 LdrpAttachThread (VOID)
2933 {
2934 PLIST_ENTRY ModuleListHead;
2935 PLIST_ENTRY Entry;
2936 PLDR_DATA_TABLE_ENTRY Module;
2937 NTSTATUS Status;
2938
2939 DPRINT("LdrpAttachThread() called for %wZ\n",
2940 &ExeModule->BaseDllName);
2941
2942 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2943
2944 Status = LdrpInitializeTlsForThread();
2945
2946 if (NT_SUCCESS(Status))
2947 {
2948 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2949 Entry = ModuleListHead->Flink;
2950
2951 while (Entry != ModuleListHead)
2952 {
2953 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2954 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2955 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2956 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2957 {
2958 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2959 &Module->BaseDllName, Module->EntryPoint);
2960 LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);
2961 }
2962 Entry = Entry->Flink;
2963 }
2964
2965 Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
2966 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2967 LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
2968 }
2969
2970 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2971
2972 DPRINT("LdrpAttachThread() done\n");
2973
2974 return Status;
2975 }
2976
2977
2978 /*
2979 * @implemented
2980 */
2981 NTSTATUS NTAPI
2982 LdrShutdownThread (VOID)
2983 {
2984 PLIST_ENTRY ModuleListHead;
2985 PLIST_ENTRY Entry;
2986 PLDR_DATA_TABLE_ENTRY Module;
2987
2988 DPRINT("LdrShutdownThread() called for %wZ\n",
2989 &ExeModule->BaseDllName);
2990
2991 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2992
2993 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2994 Entry = ModuleListHead->Blink;
2995 while (Entry != ModuleListHead)
2996 {
2997 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
2998
2999 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
3000 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
3001 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
3002 {
3003 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
3004 &Module->BaseDllName, Module->EntryPoint);
3005 LdrpCallDllEntry(Module, DLL_THREAD_DETACH, NULL);
3006 }
3007 Entry = Entry->Blink;
3008 }
3009
3010 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3011
3012 if (LdrpTlsArray)
3013 {
3014 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer);
3015 }
3016
3017 DPRINT("LdrShutdownThread() done\n");
3018
3019 return STATUS_SUCCESS;
3020 }
3021
3022
3023 /***************************************************************************
3024 * NAME EXPORTED
3025 * LdrQueryProcessModuleInformation
3026 *
3027 * DESCRIPTION
3028 *
3029 * ARGUMENTS
3030 *
3031 * RETURN VALUE
3032 *
3033 * REVISIONS
3034 *
3035 * NOTE
3036 *
3037 * @implemented
3038 */
3039 NTSTATUS NTAPI
3040 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
3041 IN ULONG Size OPTIONAL,
3042 OUT PULONG ReturnedSize)
3043 {
3044 PLIST_ENTRY ModuleListHead;
3045 PLIST_ENTRY Entry;
3046 PLDR_DATA_TABLE_ENTRY Module;
3047 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
3048 NTSTATUS Status = STATUS_SUCCESS;
3049 ULONG UsedSize = sizeof(ULONG);
3050 ANSI_STRING AnsiString;
3051 PCHAR p;
3052
3053 DPRINT("LdrQueryProcessModuleInformation() called\n");
3054 // FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c
3055 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
3056
3057 if (ModuleInformation == NULL || Size == 0)
3058 {
3059 Status = STATUS_INFO_LENGTH_MISMATCH;
3060 }
3061 else
3062 {
3063 ModuleInformation->NumberOfModules = 0;
3064 ModulePtr = &ModuleInformation->Modules[0];
3065 Status = STATUS_SUCCESS;
3066 }
3067
3068 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
3069 Entry = ModuleListHead->Flink;
3070
3071 while (Entry != ModuleListHead)
3072 {
3073 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3074
3075 DPRINT(" Module %wZ\n",
3076 &Module->FullDllName);
3077
3078 if (UsedSize > Size)
3079 {
3080 Status = STATUS_INFO_LENGTH_MISMATCH;
3081 }
3082 else if (ModuleInformation != NULL)
3083 {
3084 ModulePtr->Section = 0;
3085 ModulePtr->MappedBase = NULL; // FIXME: ??
3086 ModulePtr->ImageBase = Module->DllBase;
3087 ModulePtr->ImageSize = Module->SizeOfImage;
3088 ModulePtr->Flags = Module->Flags;
3089 ModulePtr->LoadOrderIndex = 0; // FIXME: ??
3090 ModulePtr->InitOrderIndex = 0; // FIXME: ??
3091 ModulePtr->LoadCount = Module->LoadCount;
3092
3093 AnsiString.Length = 0;
3094 AnsiString.MaximumLength = 256;
3095 AnsiString.Buffer = ModulePtr->FullPathName;
3096 RtlUnicodeStringToAnsiString(&AnsiString,
3097 &Module->FullDllName,
3098 FALSE);
3099
3100 p = strrchr(ModulePtr->FullPathName, '\\');
3101 if (p != NULL)
3102 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
3103 else
3104 ModulePtr->OffsetToFileName = 0;
3105
3106 ModulePtr++;
3107 ModuleInformation->NumberOfModules++;
3108 }
3109 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
3110
3111 Entry = Entry->Flink;
3112 }
3113
3114 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3115
3116 if (ReturnedSize != 0)
3117 *ReturnedSize = UsedSize;
3118
3119 DPRINT("LdrQueryProcessModuleInformation() done\n");
3120
3121 return(Status);
3122 }
3123
3124
3125 static BOOLEAN
3126 LdrpCheckImageChecksum (IN PVOID BaseAddress,
3127 IN ULONG ImageSize)
3128 {
3129 PIMAGE_NT_HEADERS Header;
3130 PUSHORT Ptr;
3131 ULONG Sum;
3132 ULONG CalcSum;
3133 ULONG HeaderSum;
3134 ULONG i;
3135
3136 Header = RtlImageNtHeader (BaseAddress);
3137 if (Header == NULL)
3138 return FALSE;
3139
3140 HeaderSum = Header->OptionalHeader.CheckSum;
3141 if (HeaderSum == 0)
3142 return TRUE;
3143
3144 Sum = 0;
3145 Ptr = (PUSHORT) BaseAddress;
3146 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
3147 {
3148 Sum += (ULONG)*Ptr;
3149 if (HIWORD(Sum) != 0)
3150 {
3151 Sum = LOWORD(Sum) + HIWORD(Sum);
3152 }
3153 Ptr++;
3154 }
3155
3156 if (ImageSize & 1)
3157 {
3158 Sum += (ULONG)*((PUCHAR)Ptr);
3159 if (HIWORD(Sum) != 0)
3160 {
3161 Sum = LOWORD(Sum) + HIWORD(Sum);
3162 }
3163 }
3164
3165 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
3166
3167 /* Subtract image checksum from calculated checksum. */
3168 /* fix low word of checksum */
3169 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
3170 {
3171 CalcSum -= LOWORD(HeaderSum);
3172 }
3173 else
3174 {
3175 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
3176 }
3177
3178 /* fix high word of checksum */
3179 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
3180 {
3181 CalcSum -= HIWORD(HeaderSum);
3182 }
3183 else
3184 {
3185 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
3186 }
3187
3188 /* add file length */
3189 CalcSum += ImageSize;
3190
3191 return (BOOLEAN)(CalcSum == HeaderSum);
3192 }
3193
3194 /*
3195 * Compute size of an image as it is actually present in virt memory
3196 * (i.e. excluding NEVER_LOAD sections)
3197 */
3198 ULONG
3199 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders)
3200 {
3201 PIMAGE_SECTION_HEADER SectionHeader;
3202 unsigned SectionIndex;
3203 ULONG ResidentSize;
3204
3205 SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader
3206 + NTHeaders->FileHeader.SizeOfOptionalHeader);
3207 ResidentSize = 0;
3208 for (SectionIndex = 0; SectionIndex < NTHeaders->FileHeader.NumberOfSections; SectionIndex++)
3209 {
3210 if (0 == (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE)
3211 && ResidentSize < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)
3212 {
3213 ResidentSize = SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize;
3214 }
3215 SectionHeader++;
3216 }
3217
3218 return ResidentSize;
3219 }
3220
3221
3222 /***************************************************************************
3223 * NAME EXPORTED
3224 * LdrVerifyImageMatchesChecksum
3225 *
3226 * DESCRIPTION
3227 *
3228 * ARGUMENTS
3229 *
3230 * RETURN VALUE
3231 *
3232 * REVISIONS
3233 *
3234 * NOTE
3235 *
3236 * @implemented
3237 */
3238 NTSTATUS NTAPI
3239 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
3240 ULONG Unknown1,
3241 ULONG Unknown2,
3242 ULONG Unknown3)
3243 {
3244 FILE_STANDARD_INFORMATION FileInfo;
3245 IO_STATUS_BLOCK IoStatusBlock;
3246 HANDLE SectionHandle;
3247 SIZE_T ViewSize;
3248 PVOID BaseAddress;
3249 BOOLEAN Result;
3250 NTSTATUS Status;
3251
3252 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
3253
3254 Status = NtCreateSection (&SectionHandle,
3255 SECTION_MAP_READ,
3256 NULL,
3257 NULL,
3258 PAGE_READONLY,
3259 SEC_COMMIT,
3260 FileHandle);
3261 if (!NT_SUCCESS(Status))
3262 {
3263 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
3264 return Status;
3265 }
3266
3267 ViewSize = 0;
3268 BaseAddress = NULL;
3269 Status = NtMapViewOfSection (SectionHandle,
3270 NtCurrentProcess (),
3271 &BaseAddress,
3272 0,
3273 0,
3274 NULL,
3275 &ViewSize,
3276 ViewShare,
3277 0,
3278 PAGE_READONLY);
3279 if (!NT_SUCCESS(Status))
3280 {
3281 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3282 NtClose (SectionHandle);
3283 return Status;
3284 }
3285
3286 Status = NtQueryInformationFile (FileHandle,
3287 &IoStatusBlock,
3288 &FileInfo,
3289 sizeof (FILE_STANDARD_INFORMATION),
3290 FileStandardInformation);
3291 if (!NT_SUCCESS(Status))
3292 {
3293 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3294 NtUnmapViewOfSection (NtCurrentProcess (),
3295 BaseAddress);
3296 NtClose (SectionHandle);
3297 return Status;
3298 }
3299
3300 Result = LdrpCheckImageChecksum (BaseAddress,
3301 FileInfo.EndOfFile.u.LowPart);
3302 if (Result == FALSE)
3303 {
3304 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
3305 }
3306
3307 NtUnmapViewOfSection (NtCurrentProcess (),
3308 BaseAddress);
3309
3310 NtClose (SectionHandle);
3311
3312 return Status;
3313 }
3314
3315
3316 /***************************************************************************
3317 * NAME EXPORTED
3318 * LdrQueryImageFileExecutionOptions
3319 *
3320 * DESCRIPTION
3321 *
3322 * ARGUMENTS
3323 *
3324 * RETURN VALUE
3325 *
3326 * REVISIONS
3327 *
3328 * NOTE
3329 *
3330 * @implemented
3331 */
3332 NTSTATUS NTAPI
3333 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
3334 IN PCWSTR ValueName,
3335 IN ULONG Type,
3336 OUT PVOID Buffer,
3337 IN ULONG BufferSize,
3338 OUT PULONG ReturnedLength OPTIONAL)
3339 {
3340 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
3341 OBJECT_ATTRIBUTES ObjectAttributes;
3342 UNICODE_STRING ValueNameString;
3343 UNICODE_STRING KeyName;
3344 WCHAR NameBuffer[256];
3345 HANDLE KeyHandle;
3346 ULONG KeyInfoSize;
3347 ULONG ResultSize;
3348 PWCHAR Ptr;
3349 NTSTATUS Status;
3350
3351 wcscpy (NameBuffer,
3352 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
3353 Ptr = wcsrchr (SubKey->Buffer, L'\\');
3354 if (Ptr == NULL)
3355 {
3356 Ptr = SubKey->Buffer;
3357 }
3358 else
3359 {
3360 Ptr++;
3361 }
3362 wcscat (NameBuffer, Ptr);
3363 RtlInitUnicodeString (&KeyName,
3364 NameBuffer);
3365
3366 InitializeObjectAttributes (&ObjectAttributes,
3367 &KeyName,
3368 OBJ_CASE_INSENSITIVE,
3369 NULL,
3370 NULL);
3371
3372 Status = NtOpenKey (&KeyHandle,
3373 KEY_READ,
3374 &ObjectAttributes);
3375 if (!NT_SUCCESS(Status))
3376 {
3377 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
3378 return Status;
3379 }
3380
3381 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
3382 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3383 HEAP_ZERO_MEMORY,
3384 KeyInfoSize);
3385 if (KeyInfo == NULL)
3386 {
3387 NtClose (KeyHandle);
3388 return STATUS_INSUFFICIENT_RESOURCES;
3389 }
3390
3391 RtlInitUnicodeString (&ValueNameString,
3392 (PWSTR)ValueName);
3393 Status = NtQueryValueKey (KeyHandle,
3394 &ValueNameString,
3395 KeyValuePartialInformation,
3396 KeyInfo,
3397 KeyInfoSize,
3398 &ResultSize);
3399 if (Status == STATUS_BUFFER_OVERFLOW)
3400 {
3401 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
3402 RtlFreeHeap (RtlGetProcessHeap(),
3403 0,
3404 KeyInfo);
3405 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3406 HEAP_ZERO_MEMORY,
3407 KeyInfoSize);
3408 if (KeyInfo == NULL)
3409 {
3410 NtClose (KeyHandle);
3411 return STATUS_INSUFFICIENT_RESOURCES;
3412 }
3413
3414 Status = NtQueryValueKey (KeyHandle,
3415 &ValueNameString,
3416 KeyValuePartialInformation,
3417 KeyInfo,
3418 KeyInfoSize,
3419 &ResultSize);
3420 }
3421 NtClose (KeyHandle);
3422
3423 if (!NT_SUCCESS(Status))
3424 {
3425 if (KeyInfo != NULL)
3426 {
3427 RtlFreeHeap (RtlGetProcessHeap(),
3428 0,
3429 KeyInfo);
3430 }
3431 return Status;
3432 }
3433
3434 if (KeyInfo->Type != Type)
3435 {
3436 RtlFreeHeap (RtlGetProcessHeap(),
3437 0,
3438 KeyInfo);
3439 return STATUS_OBJECT_TYPE_MISMATCH;
3440 }
3441
3442 ResultSize = BufferSize;
3443 if (ResultSize < KeyInfo->DataLength)
3444 {
3445 Status = STATUS_BUFFER_OVERFLOW;
3446 }
3447 else
3448 {
3449 ResultSize = KeyInfo->DataLength;
3450 }
3451 RtlCopyMemory (Buffer,
3452 &KeyInfo->Data,
3453 ResultSize);
3454
3455 RtlFreeHeap (RtlGetProcessHeap(),
3456 0,
3457 KeyInfo);
3458
3459 if (ReturnedLength != NULL)
3460 {
3461 *ReturnedLength = ResultSize;
3462 }
3463
3464 return Status;
3465 }
3466
3467
3468 PIMAGE_BASE_RELOCATION NTAPI
3469 LdrProcessRelocationBlock(IN ULONG_PTR Address,
3470 IN ULONG Count,
3471 IN PUSHORT TypeOffset,
3472 IN LONG_PTR Delta)
3473 {
3474 SHORT Offset;
3475 USHORT Type;
3476 USHORT i;
3477 PUSHORT ShortPtr;
3478 PULONG LongPtr;
3479
3480 for (i = 0; i < Count; i++)
3481 {
3482 Offset = *TypeOffset & 0xFFF;
3483 Type = *TypeOffset >> 12;
3484
3485 switch (Type)
3486 {
3487 case IMAGE_REL_BASED_ABSOLUTE:
3488 break;
3489
3490 case IMAGE_REL_BASED_HIGH:
3491 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3492 *ShortPtr += HIWORD(Delta);
3493 break;
3494
3495 case IMAGE_REL_BASED_LOW:
3496 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3497 *ShortPtr += LOWORD(Delta);
3498 break;
3499
3500 case IMAGE_REL_BASED_HIGHLOW:
3501 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3502 *LongPtr += Delta;
3503 break;
3504 #ifdef _WIN64
3505 case IMAGE_REL_BASED_DIR64:
3506 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3507 *LongPtr += Delta;
3508 break;
3509 #endif
3510
3511 case IMAGE_REL_BASED_HIGHADJ:
3512 case IMAGE_REL_BASED_MIPS_JMPADDR:
3513 default:
3514 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
3515 return NULL;
3516 }
3517
3518 TypeOffset++;
3519 }
3520
3521 return (PIMAGE_BASE_RELOCATION)TypeOffset;
3522 }
3523
3524 NTSTATUS
3525 NTAPI
3526 LdrLockLoaderLock(IN ULONG Flags,
3527 OUT PULONG Disposition OPTIONAL,
3528 OUT PULONG Cookie OPTIONAL)
3529 {
3530 NTSTATUS Status;
3531 BOOLEAN Ret;
3532 BOOLEAN CookieSet = FALSE;
3533
3534 if ((Flags != 0x01) && (Flags != 0x02))
3535 return STATUS_INVALID_PARAMETER_1;
3536
3537 if (!Cookie) return STATUS_INVALID_PARAMETER_3;
3538
3539 /* Set some defaults for failure while verifying params */
3540 _SEH2_TRY
3541 {
3542 *Cookie = 0;
3543 CookieSet = TRUE;
3544 if (Disposition) *Disposition = 0;
3545 }
3546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3547 {
3548 if (CookieSet)
3549 Status = STATUS_INVALID_PARAMETER_3;
3550 else
3551 Status = STATUS_INVALID_PARAMETER_2;
3552 }
3553 _SEH2_END;
3554
3555 if (Flags == 0x01)
3556 {
3557 DPRINT1("Warning: Reporting errors with exception not supported yet!\n");
3558 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3559 Status = STATUS_SUCCESS;
3560
3561 }
3562 else
3563 {
3564 if (!Disposition) return STATUS_INVALID_PARAMETER_2;
3565
3566 Ret = RtlTryEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3567
3568 if (Ret)
3569 *Disposition = 0x01;
3570 else
3571 *Disposition = 0x02;
3572
3573 Status = STATUS_SUCCESS;
3574 }
3575
3576 /* FIXME: Cookie is based on part of the thread id */
3577 *Cookie = (ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread;
3578 return Status;
3579 }
3580
3581 NTSTATUS
3582 NTAPI
3583 LdrUnlockLoaderLock(IN ULONG Flags,
3584 IN ULONG Cookie OPTIONAL)
3585 {
3586 if (Flags != 0x01)
3587 return STATUS_INVALID_PARAMETER_1;
3588
3589 if (Cookie != (ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread)
3590 return STATUS_INVALID_PARAMETER_2;
3591
3592 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
3593
3594 return STATUS_SUCCESS;
3595 }
3596
3597 BOOLEAN
3598 NTAPI
3599 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
3600 {
3601 UNIMPLEMENTED;
3602 return FALSE;
3603 }