Sync with trunk head (part 1 of 2)
[reactos.git] / 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)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)Function >= (ULONG)ExportDir) &&
1214 ((ULONG)Function < (ULONG)ExportDir + (ULONG)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)Function >= (ULONG)ExportDir) &&
1299 ((ULONG)Function < (ULONG)ExportDir + (ULONG)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)Function >= (ULONG)ExportDir) &&
1333 ((ULONG)Function < (ULONG)ExportDir + (ULONG)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, ProtectSize, OldProtect, OldProtect2;
1389 PVOID Page, ProtectPage, ProtectPage2;
1390 PUSHORT TypeOffset;
1391 ULONG_PTR Delta;
1392 NTSTATUS Status;
1393
1394 if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1395 {
1396 return STATUS_SUCCESS;
1397 }
1398
1399 RelocationDDir =
1400 &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1401
1402 if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
1403 {
1404 return STATUS_SUCCESS;
1405 }
1406
1407 ProtectSize = PAGE_SIZE;
1408 Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
1409 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1410 RelocationDDir->VirtualAddress);
1411 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1412 RelocationDDir->VirtualAddress + RelocationDDir->Size);
1413
1414 while (RelocationDir < RelocationEnd &&
1415 RelocationDir->SizeOfBlock > 0)
1416 {
1417 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
1418 sizeof(USHORT);
1419 Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
1420 TypeOffset = (PUSHORT)(RelocationDir + 1);
1421
1422 /* Unprotect the page(s) we're about to relocate. */
1423 ProtectPage = Page;
1424 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1425 &ProtectPage,
1426 &ProtectSize,
1427 PAGE_READWRITE,
1428 &OldProtect);
1429 if (!NT_SUCCESS(Status))
1430 {
1431 DPRINT1("Failed to unprotect relocation target.\n");
1432 return Status;
1433 }
1434
1435 if (RelocationDir->VirtualAddress + PAGE_SIZE <
1436 NTHeaders->OptionalHeader.SizeOfImage)
1437 {
1438 ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
1439 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1440 &ProtectPage2,
1441 &ProtectSize,
1442 PAGE_READWRITE,
1443 &OldProtect2);
1444 if (!NT_SUCCESS(Status))
1445 {
1446 DPRINT1("Failed to unprotect relocation target (2).\n");
1447 NtProtectVirtualMemory(NtCurrentProcess(),
1448 &ProtectPage,
1449 &ProtectSize,
1450 OldProtect,
1451 &OldProtect);
1452 return Status;
1453 }
1454 }
1455 else
1456 {
1457 ProtectPage2 = NULL;
1458 }
1459
1460 RelocationDir = LdrProcessRelocationBlock((ULONG_PTR)Page,
1461 Count,
1462 TypeOffset,
1463 Delta);
1464 if (RelocationDir == NULL)
1465 return STATUS_UNSUCCESSFUL;
1466
1467 /* Restore old page protection. */
1468 NtProtectVirtualMemory(NtCurrentProcess(),
1469 &ProtectPage,
1470 &ProtectSize,
1471 OldProtect,
1472 &OldProtect);
1473
1474 if (ProtectPage2 != NULL)
1475 {
1476 NtProtectVirtualMemory(NtCurrentProcess(),
1477 &ProtectPage2,
1478 &ProtectSize,
1479 OldProtect2,
1480 &OldProtect2);
1481 }
1482 }
1483
1484 return STATUS_SUCCESS;
1485 }
1486
1487 static NTSTATUS
1488 LdrpGetOrLoadModule(PWCHAR SearchPath,
1489 PCHAR Name,
1490 PLDR_DATA_TABLE_ENTRY* Module,
1491 BOOLEAN Load)
1492 {
1493 ANSI_STRING AnsiDllName;
1494 UNICODE_STRING DllName;
1495 NTSTATUS Status;
1496
1497 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name);
1498
1499 RtlInitAnsiString(&AnsiDllName, Name);
1500 Status = RtlAnsiStringToUnicodeString(&DllName, &AnsiDllName, TRUE);
1501 if (!NT_SUCCESS(Status))
1502 {
1503 return Status;
1504 }
1505
1506 Status = LdrFindEntryForName (&DllName, Module, Load);
1507 if (Load && !NT_SUCCESS(Status))
1508 {
1509 Status = LdrpLoadModule(SearchPath,
1510 0,
1511 &DllName,
1512 Module,
1513 NULL);
1514 if (NT_SUCCESS(Status))
1515 {
1516 Status = LdrFindEntryForName (&DllName, Module, FALSE);
1517 }
1518 if (!NT_SUCCESS(Status))
1519 {
1520 ULONG ErrorResponse;
1521 ULONG_PTR ErrorParameter = (ULONG_PTR)&DllName;
1522
1523 DPRINT1("failed to load %wZ\n", &DllName);
1524
1525 NtRaiseHardError(STATUS_DLL_NOT_FOUND,
1526 1,
1527 1,
1528 &ErrorParameter,
1529 OptionOk,
1530 &ErrorResponse);
1531 }
1532 }
1533 RtlFreeUnicodeString (&DllName);
1534 return Status;
1535 }
1536
1537 void
1538 RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName)
1539 {
1540 ULONG ErrorResponse;
1541 ULONG_PTR ErrorParameters[2];
1542 ANSI_STRING ProcNameAnsi;
1543 UNICODE_STRING ProcName;
1544 CHAR Buffer[8];
1545
1546 if (!FuncName)
1547 {
1548 _snprintf(Buffer, 8, "# %ld", Ordinal);
1549 FuncName = Buffer;
1550 }
1551
1552 RtlInitAnsiString(&ProcNameAnsi, FuncName);
1553 RtlAnsiStringToUnicodeString(&ProcName, &ProcNameAnsi, TRUE);
1554 ErrorParameters[0] = (ULONG_PTR)&ProcName;
1555 ErrorParameters[1] = (ULONG_PTR)DllName;
1556 NtRaiseHardError(STATUS_ENTRYPOINT_NOT_FOUND,
1557 2,
1558 3,
1559 ErrorParameters,
1560 OptionOk,
1561 &ErrorResponse);
1562 RtlFreeUnicodeString(&ProcName);
1563 }
1564
1565 static NTSTATUS
1566 LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
1567 PLDR_DATA_TABLE_ENTRY ImportedModule,
1568 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
1569 {
1570 NTSTATUS Status;
1571 PVOID* ImportAddressList;
1572 PULONG FunctionNameList;
1573 PVOID IATBase;
1574 ULONG OldProtect;
1575 ULONG Ordinal;
1576 ULONG IATSize;
1577
1578 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
1579 {
1580 return STATUS_UNSUCCESSFUL;
1581 }
1582
1583 /* Get the import address list. */
1584 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1585
1586 /* Get the list of functions to import. */
1587 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1588 {
1589 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1590 }
1591 else
1592 {
1593 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1594 }
1595
1596 /* Get the size of IAT. */
1597 IATSize = 0;
1598 while (FunctionNameList[IATSize] != 0L)
1599 {
1600 IATSize++;
1601 }
1602
1603 /* No need to fixup anything if IAT is empty */
1604 if (IATSize == 0) return STATUS_SUCCESS;
1605
1606 /* Unprotect the region we are about to write into. */
1607 IATBase = (PVOID)ImportAddressList;
1608 IATSize *= sizeof(PVOID*);
1609 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1610 &IATBase,
1611 &IATSize,
1612 PAGE_READWRITE,
1613 &OldProtect);
1614 if (!NT_SUCCESS(Status))
1615 {
1616 DPRINT1("Failed to unprotect IAT.\n");
1617 return(Status);
1618 }
1619
1620 /* Walk through function list and fixup addresses. */
1621 while (*FunctionNameList != 0L)
1622 {
1623 if ((*FunctionNameList) & 0x80000000)
1624 {
1625 Ordinal = (*FunctionNameList) & 0x7fffffff;
1626 *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
1627 if ((*ImportAddressList) == NULL)
1628 {
1629 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
1630 RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName);
1631 return STATUS_ENTRYPOINT_NOT_FOUND;
1632 }
1633 }
1634 else
1635 {
1636 IMAGE_IMPORT_BY_NAME *pe_name;
1637 pe_name = RVA(Module->DllBase, *FunctionNameList);
1638 *ImportAddressList = LdrGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
1639 if ((*ImportAddressList) == NULL)
1640 {
1641 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
1642 RtlpRaiseImportNotFound((CHAR*)pe_name->Name, 0, &ImportedModule->FullDllName);
1643 return STATUS_ENTRYPOINT_NOT_FOUND;
1644 }
1645 }
1646 ImportAddressList++;
1647 FunctionNameList++;
1648 }
1649
1650 /* Protect the region we are about to write into. */
1651 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1652 &IATBase,
1653 &IATSize,
1654 OldProtect,
1655 &OldProtect);
1656 if (!NT_SUCCESS(Status))
1657 {
1658 DPRINT1("Failed to protect IAT.\n");
1659 return(Status);
1660 }
1661
1662 return STATUS_SUCCESS;
1663 }
1664
1665 static NTSTATUS
1666 LdrpProcessImportDirectory(
1667 PLDR_DATA_TABLE_ENTRY Module,
1668 PLDR_DATA_TABLE_ENTRY ImportedModule,
1669 PCHAR ImportedName)
1670 {
1671 NTSTATUS Status;
1672 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1673 PCHAR Name;
1674 ULONG Size;
1675
1676 DPRINT("LdrpProcessImportDirectory(%p '%wZ', '%s')\n",
1677 Module, &Module->BaseDllName, ImportedName);
1678
1679
1680 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1681 RtlImageDirectoryEntryToData(Module->DllBase,
1682 TRUE,
1683 IMAGE_DIRECTORY_ENTRY_IMPORT,
1684 &Size);
1685 if (ImportModuleDirectory == NULL)
1686 {
1687 return STATUS_UNSUCCESSFUL;
1688 }
1689
1690 while (ImportModuleDirectory->Name)
1691 {
1692 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1693 if (0 == _stricmp(Name, ImportedName))
1694 {
1695 Status = LdrpProcessImportDirectoryEntry(Module,
1696 ImportedModule,
1697 ImportModuleDirectory);
1698 if (!NT_SUCCESS(Status))
1699 {
1700 return Status;
1701 }
1702 }
1703 ImportModuleDirectory++;
1704 }
1705
1706
1707 return STATUS_SUCCESS;
1708 }
1709
1710
1711 static NTSTATUS
1712 LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
1713 PLDR_DATA_TABLE_ENTRY ImportedModule,
1714 PCHAR ImportedName)
1715 {
1716 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1717 NTSTATUS Status;
1718 PVOID* ImportAddressList;
1719 PVOID Start;
1720 PVOID End;
1721 PULONG FunctionNameList;
1722 PVOID IATBase;
1723 ULONG OldProtect;
1724 ULONG Offset;
1725 ULONG IATSize;
1726 PIMAGE_NT_HEADERS NTHeaders;
1727 PCHAR Name;
1728 ULONG Size;
1729
1730 DPRINT("LdrpAdjustImportDirectory(Module %p '%wZ', %p '%wZ', '%s')\n",
1731 Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
1732
1733 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1734 RtlImageDirectoryEntryToData(Module->DllBase,
1735 TRUE,
1736 IMAGE_DIRECTORY_ENTRY_IMPORT,
1737 &Size);
1738 if (ImportModuleDirectory == NULL)
1739 {
1740 return STATUS_UNSUCCESSFUL;
1741 }
1742
1743 while (ImportModuleDirectory->Name)
1744 {
1745 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1746 if (0 == _stricmp(Name, (PCHAR)ImportedName))
1747 {
1748
1749 /* Get the import address list. */
1750 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1751
1752 /* Get the list of functions to import. */
1753 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1754 {
1755 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1756 }
1757 else
1758 {
1759 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1760 }
1761
1762 /* Get the size of IAT. */
1763 IATSize = 0;
1764 while (FunctionNameList[IATSize] != 0L)
1765 {
1766 IATSize++;
1767 }
1768
1769 /* Unprotect the region we are about to write into. */
1770 IATBase = (PVOID)ImportAddressList;
1771 IATSize *= sizeof(PVOID*);
1772 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1773 &IATBase,
1774 &IATSize,
1775 PAGE_READWRITE,
1776 &OldProtect);
1777 if (!NT_SUCCESS(Status))
1778 {
1779 DPRINT1("Failed to unprotect IAT.\n");
1780 return(Status);
1781 }
1782
1783 NTHeaders = RtlImageNtHeader (ImportedModule->DllBase);
1784 Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
1785 End = (PVOID)((ULONG_PTR)Start + ImportedModule->SizeOfImage);
1786 Offset = (ULONG)((ULONG_PTR)ImportedModule->DllBase - (ULONG_PTR)Start);
1787
1788 /* Walk through function list and fixup addresses. */
1789 while (*FunctionNameList != 0L)
1790 {
1791 if (*ImportAddressList >= Start && *ImportAddressList < End)
1792 {
1793 (*ImportAddressList) = (PVOID)((ULONG_PTR)(*ImportAddressList) + Offset);
1794 }
1795 ImportAddressList++;
1796 FunctionNameList++;
1797 }
1798
1799 /* Protect the region we are about to write into. */
1800 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1801 &IATBase,
1802 &IATSize,
1803 OldProtect,
1804 &OldProtect);
1805 if (!NT_SUCCESS(Status))
1806 {
1807 DPRINT1("Failed to protect IAT.\n");
1808 return(Status);
1809 }
1810 }
1811 ImportModuleDirectory++;
1812 }
1813 return STATUS_SUCCESS;
1814 }
1815
1816
1817 /**********************************************************************
1818 * NAME LOCAL
1819 * LdrFixupImports
1820 *
1821 * DESCRIPTION
1822 * Compute the entry point for every symbol the DLL imports
1823 * from other modules.
1824 *
1825 * ARGUMENTS
1826 *
1827 * RETURN VALUE
1828 *
1829 * REVISIONS
1830 *
1831 * NOTE
1832 *
1833 */
1834 static NTSTATUS
1835 LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
1836 IN PLDR_DATA_TABLE_ENTRY Module)
1837 {
1838 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1839 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent;
1840 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
1841 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
1842 PIMAGE_TLS_DIRECTORY TlsDirectory;
1843 ULONG TlsSize = 0;
1844 NTSTATUS Status = STATUS_SUCCESS;
1845 PLDR_DATA_TABLE_ENTRY ImportedModule;
1846 PCHAR ImportedName;
1847 PWSTR ModulePath;
1848 ULONG Size;
1849 ULONG_PTR cookie;
1850
1851 DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
1852
1853 /* Check for tls data */
1854 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
1855 RtlImageDirectoryEntryToData(Module->DllBase,
1856 TRUE,
1857 IMAGE_DIRECTORY_ENTRY_TLS,
1858 &Size);
1859 if (TlsDirectory)
1860 {
1861 TlsSize = TlsDirectory->EndAddressOfRawData
1862 - TlsDirectory->StartAddressOfRawData
1863 + TlsDirectory->SizeOfZeroFill;
1864
1865 if (TlsSize > 0 && NtCurrentPeb()->Ldr->Initialized)
1866 {
1867 TRACE_LDR("Trying to dynamically load %wZ which contains a TLS directory\n",
1868 &Module->BaseDllName);
1869 TlsDirectory = NULL;
1870 }
1871 }
1872
1873 if (!create_module_activation_context( Module ))
1874 {
1875 if (Module->EntryPointActivationContext == NULL)
1876 {
1877 DPRINT("EntryPointActivationContext has not be allocated\n");
1878 DPRINT("Module->DllBaseName %wZ\n", Module->BaseDllName);
1879 }
1880 RtlActivateActivationContext( 0, Module->EntryPointActivationContext, &cookie );
1881 }
1882
1883 /*
1884 * Process each import module.
1885 */
1886 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1887 RtlImageDirectoryEntryToData(Module->DllBase,
1888 TRUE,
1889 IMAGE_DIRECTORY_ENTRY_IMPORT,
1890 &Size);
1891
1892 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
1893 RtlImageDirectoryEntryToData(Module->DllBase,
1894 TRUE,
1895 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
1896 &Size);
1897
1898 if (BoundImportDescriptor != NULL && ImportModuleDirectory == NULL)
1899 {
1900 DPRINT1("%wZ has only a bound import directory\n", &Module->BaseDllName);
1901 return STATUS_UNSUCCESSFUL;
1902 }
1903 if (BoundImportDescriptor)
1904 {
1905 DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor);
1906
1907 BoundImportDescriptorCurrent = BoundImportDescriptor;
1908 while (BoundImportDescriptorCurrent->OffsetModuleName)
1909 {
1910 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
1911 TRACE_LDR("%wZ bound to %s\n", &Module->BaseDllName, ImportedName);
1912 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
1913 if (!NT_SUCCESS(Status))
1914 {
1915 DPRINT1("failed to load %s\n", ImportedName);
1916 return Status;
1917 }
1918 if (Module == ImportedModule)
1919 {
1920 LdrpDecrementLoadCount(Module, FALSE);
1921 }
1922 if (ImportedModule->TimeDateStamp != BoundImportDescriptorCurrent->TimeDateStamp)
1923 {
1924 TRACE_LDR("%wZ has stale binding to %wZ\n",
1925 &Module->BaseDllName, &ImportedModule->BaseDllName);
1926 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1927 if (!NT_SUCCESS(Status))
1928 {
1929 DPRINT1("failed to import %s\n", ImportedName);
1930 return Status;
1931 }
1932 }
1933 else
1934 {
1935 BOOLEAN WrongForwarder;
1936 WrongForwarder = FALSE;
1937 if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1938 {
1939 TRACE_LDR("%wZ has stale binding to %s\n",
1940 &Module->BaseDllName, ImportedName);
1941 }
1942 else
1943 {
1944 TRACE_LDR("%wZ has correct binding to %wZ\n",
1945 &Module->BaseDllName, &ImportedModule->BaseDllName);
1946 }
1947 if (BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs)
1948 {
1949 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef;
1950 ULONG i;
1951 PLDR_DATA_TABLE_ENTRY ForwarderModule;
1952 PCHAR ForwarderName;
1953
1954 BoundForwarderRef = (PIMAGE_BOUND_FORWARDER_REF)(BoundImportDescriptorCurrent + 1);
1955 for (i = 0; i < BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs; i++, BoundForwarderRef++)
1956 {
1957 ForwarderName = (PCHAR)BoundImportDescriptor + BoundForwarderRef->OffsetModuleName;
1958 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1959 &Module->BaseDllName, ForwarderName, ImportedName);
1960 Status = LdrpGetOrLoadModule(SearchPath, ForwarderName, &ForwarderModule, TRUE);
1961 if (!NT_SUCCESS(Status))
1962 {
1963 DPRINT1("failed to load %s\n", ForwarderName);
1964 return Status;
1965 }
1966 if (Module == ImportedModule)
1967 {
1968 LdrpDecrementLoadCount(Module, FALSE);
1969 }
1970 if (ForwarderModule->TimeDateStamp != BoundForwarderRef->TimeDateStamp ||
1971 ForwarderModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1972 {
1973 TRACE_LDR("%wZ has stale binding to %s\n",
1974 &Module->BaseDllName, ForwarderName);
1975 WrongForwarder = TRUE;
1976 }
1977 else
1978 {
1979 TRACE_LDR("%wZ has correct binding to %s\n",
1980 &Module->BaseDllName, ForwarderName);
1981 }
1982 }
1983 }
1984 if (WrongForwarder ||
1985 ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1986 {
1987 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1988 if (!NT_SUCCESS(Status))
1989 {
1990 DPRINT1("failed to import %s\n", ImportedName);
1991 return Status;
1992 }
1993 }
1994 else if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1995 {
1996 TRACE_LDR("Adjust imports for %s from %wZ\n",
1997 ImportedName, &Module->BaseDllName);
1998 Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName);
1999 if (!NT_SUCCESS(Status))
2000 {
2001 DPRINT1("failed to adjust import entries for %s\n", ImportedName);
2002 return Status;
2003 }
2004 }
2005 else if (WrongForwarder)
2006 {
2007 /*
2008 * FIXME:
2009 * Update only forwarders
2010 */
2011 TRACE_LDR("Stale BIND %s from %wZ\n",
2012 ImportedName, &Module->BaseDllName);
2013 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
2014 if (!NT_SUCCESS(Status))
2015 {
2016 DPRINT1("faild to import %s\n", ImportedName);
2017 return Status;
2018 }
2019 }
2020 else
2021 {
2022 /* nothing to do */
2023 }
2024 }
2025 BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1;
2026 }
2027 }
2028 else if (ImportModuleDirectory)
2029 {
2030 DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory);
2031
2032 ImportModuleDirectoryCurrent = ImportModuleDirectory;
2033 while (ImportModuleDirectoryCurrent->Name)
2034 {
2035 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2036 TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName);
2037
2038 if (SearchPath == NULL)
2039 {
2040 ModulePath = LdrpQueryAppPaths(Module->BaseDllName.Buffer);
2041
2042 Status = LdrpGetOrLoadModule(ModulePath, ImportedName, &ImportedModule, TRUE);
2043 if (ModulePath != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, ModulePath);
2044 if (NT_SUCCESS(Status)) goto Success;
2045 }
2046
2047 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
2048 if (!NT_SUCCESS(Status))
2049 {
2050 DPRINT1("failed to load %s\n", ImportedName);
2051 break;
2052 }
2053 Success:
2054 if (Module == ImportedModule)
2055 {
2056 LdrpDecrementLoadCount(Module, FALSE);
2057 }
2058
2059 TRACE_LDR("Initializing imports for %wZ from %s\n",
2060 &Module->BaseDllName, ImportedName);
2061 Status = LdrpProcessImportDirectoryEntry(Module, ImportedModule, ImportModuleDirectoryCurrent);
2062 if (!NT_SUCCESS(Status))
2063 {
2064 DPRINT1("failed to import %s\n", ImportedName);
2065 break;
2066 }
2067 ImportModuleDirectoryCurrent++;
2068 }
2069
2070 if (!NT_SUCCESS(Status))
2071 {
2072 NTSTATUS errorStatus = Status;
2073
2074 while (ImportModuleDirectoryCurrent >= ImportModuleDirectory)
2075 {
2076 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2077
2078 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2079 if (NT_SUCCESS(Status) && Module != ImportedModule)
2080 {
2081 Status = LdrpUnloadModule(ImportedModule, FALSE);
2082 if (!NT_SUCCESS(Status)) DPRINT1("unable to unload %s\n", ImportedName);
2083 }
2084 ImportModuleDirectoryCurrent--;
2085 }
2086 return errorStatus;
2087 }
2088 }
2089
2090 if (TlsDirectory && TlsSize > 0)
2091 {
2092 LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
2093 }
2094
2095 if (Module->EntryPointActivationContext) RtlDeactivateActivationContext( 0, cookie );
2096
2097 return STATUS_SUCCESS;
2098 }
2099
2100
2101 /**********************************************************************
2102 * NAME
2103 * LdrPEStartup
2104 *
2105 * DESCRIPTION
2106 * 1. Relocate, if needed the EXE.
2107 * 2. Fixup any imported symbol.
2108 * 3. Compute the EXE's entry point.
2109 *
2110 * ARGUMENTS
2111 * ImageBase
2112 * Address at which the EXE's image
2113 * is loaded.
2114 *
2115 * SectionHandle
2116 * Handle of the section that contains
2117 * the EXE's image.
2118 *
2119 * RETURN VALUE
2120 * NULL on error; otherwise the entry point
2121 * to call for initializing the DLL.
2122 *
2123 * REVISIONS
2124 *
2125 * NOTE
2126 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
2127 * Currently the function is only used for the exe.
2128 */
2129 PEPFUNC LdrPEStartup (PVOID ImageBase,
2130 HANDLE SectionHandle,
2131 PLDR_DATA_TABLE_ENTRY* Module,
2132 PWSTR FullDosName)
2133 {
2134 NTSTATUS Status;
2135 PEPFUNC EntryPoint = NULL;
2136 PIMAGE_DOS_HEADER DosHeader;
2137 PIMAGE_NT_HEADERS NTHeaders;
2138 PLDR_DATA_TABLE_ENTRY tmpModule;
2139 PVOID ActivationContextStack;
2140
2141 DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
2142 ImageBase, SectionHandle);
2143
2144 /*
2145 * Overlay DOS and WNT headers structures
2146 * to the DLL's image.
2147 */
2148 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
2149 NTHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR)ImageBase + DosHeader->e_lfanew);
2150
2151 /*
2152 * If the base address is different from the
2153 * one the DLL is actually loaded, perform any
2154 * relocation.
2155 */
2156 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2157 {
2158 DPRINT("LDR: Performing relocations\n");
2159 Status = LdrPerformRelocations(NTHeaders, ImageBase);
2160 if (!NT_SUCCESS(Status))
2161 {
2162 DPRINT1("LdrPerformRelocations() failed\n");
2163 return NULL;
2164 }
2165 }
2166
2167 if (Module != NULL)
2168 {
2169 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
2170 (*Module)->SectionPointer = SectionHandle;
2171 }
2172 else
2173 {
2174 Module = &tmpModule;
2175 Status = LdrFindEntryForAddress(ImageBase, Module);
2176 if (!NT_SUCCESS(Status))
2177 {
2178 return NULL;
2179 }
2180 }
2181
2182 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2183 {
2184 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2185 }
2186
2187 /* Allocate memory for the ActivationContextStack */
2188 /* FIXME: Verify RtlAllocateActivationContextStack behavior */
2189 Status = RtlAllocateActivationContextStack(&ActivationContextStack);
2190 if (NT_SUCCESS(Status))
2191 {
2192 DPRINT("ActivationContextStack %x\n",ActivationContextStack);
2193 DPRINT("ActiveFrame %x\n", ((PACTIVATION_CONTEXT_STACK)ActivationContextStack)->ActiveFrame);
2194 NtCurrentTeb()->ActivationContextStackPointer = ActivationContextStack;
2195 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL;
2196 }
2197 else
2198 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
2199
2200 /*
2201 * If the DLL's imports symbols from other
2202 * modules, fixup the imported calls entry points.
2203 */
2204 DPRINT("About to fixup imports\n");
2205 Status = LdrFixupImports(NULL, *Module);
2206 if (!NT_SUCCESS(Status))
2207 {
2208 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName);
2209 return NULL;
2210 }
2211 DPRINT("Fixup done\n");
2212 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2213 Status = LdrpInitializeTlsForProccess();
2214 if (NT_SUCCESS(Status))
2215 {
2216 Status = LdrpAttachProcess();
2217 }
2218 if (NT_SUCCESS(Status))
2219 {
2220 LdrpTlsCallback(*Module, DLL_PROCESS_ATTACH);
2221 }
2222
2223
2224 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
2225 if (!NT_SUCCESS(Status))
2226 {
2227 return NULL;
2228 }
2229
2230 /*
2231 * Compute the DLL's entry point's address.
2232 */
2233 DPRINT("ImageBase = %p\n", ImageBase);
2234 DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
2235 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
2236 {
2237 EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase
2238 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
2239 }
2240 DPRINT("LdrPEStartup() = %p\n",EntryPoint);
2241 return EntryPoint;
2242 }
2243
2244 static NTSTATUS
2245 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
2246 IN ULONG LoadFlags,
2247 IN PUNICODE_STRING Name,
2248 PLDR_DATA_TABLE_ENTRY *Module,
2249 PVOID *BaseAddress OPTIONAL)
2250 {
2251 UNICODE_STRING AdjustedName;
2252 UNICODE_STRING FullDosName;
2253 NTSTATUS Status;
2254 PLDR_DATA_TABLE_ENTRY tmpModule;
2255 HANDLE SectionHandle;
2256 SIZE_T ViewSize;
2257 PVOID ImageBase;
2258 PIMAGE_NT_HEADERS NtHeaders;
2259 BOOLEAN MappedAsDataFile;
2260 PVOID ArbitraryUserPointer;
2261
2262 if (Module == NULL)
2263 {
2264 Module = &tmpModule;
2265 }
2266 /* adjust the full dll name */
2267 LdrAdjustDllName(&AdjustedName, Name, FALSE);
2268
2269 DPRINT("%wZ\n", &AdjustedName);
2270
2271 MappedAsDataFile = FALSE;
2272 /* Test if dll is already loaded */
2273 Status = LdrFindEntryForName(&AdjustedName, Module, TRUE);
2274 if (NT_SUCCESS(Status))
2275 {
2276 RtlFreeUnicodeString(&AdjustedName);
2277 if (NULL != BaseAddress)
2278 {
2279 *BaseAddress = (*Module)->DllBase;
2280 }
2281 }
2282 else
2283 {
2284 /* Open or create dll image section */
2285 Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle);
2286 if (!NT_SUCCESS(Status))
2287 {
2288 MappedAsDataFile = (0 != (LoadFlags & LOAD_LIBRARY_AS_DATAFILE));
2289 Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName,
2290 MappedAsDataFile, &SectionHandle);
2291 }
2292 if (!NT_SUCCESS(Status))
2293 {
2294 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName, Status);
2295 RtlFreeUnicodeString(&AdjustedName);
2296 return Status;
2297 }
2298 RtlFreeUnicodeString(&AdjustedName);
2299 /* Map the dll into the process */
2300 ViewSize = 0;
2301 ImageBase = 0;
2302 ArbitraryUserPointer = NtCurrentTeb()->Tib.ArbitraryUserPointer;
2303 NtCurrentTeb()->Tib.ArbitraryUserPointer = FullDosName.Buffer;
2304 Status = NtMapViewOfSection(SectionHandle,
2305 NtCurrentProcess(),
2306 &ImageBase,
2307 0,
2308 0,
2309 NULL,
2310 &ViewSize,
2311 ViewShare,
2312 0,
2313 PAGE_READONLY);
2314 NtCurrentTeb()->Tib.ArbitraryUserPointer = ArbitraryUserPointer;
2315 if (!NT_SUCCESS(Status))
2316 {
2317 DPRINT1("map view of section failed (Status 0x%08lx)\n", Status);
2318 RtlFreeUnicodeString(&FullDosName);
2319 NtClose(SectionHandle);
2320 return(Status);
2321 }
2322 if (NULL != BaseAddress)
2323 {
2324 *BaseAddress = ImageBase;
2325 }
2326 if (!MappedAsDataFile)
2327 {
2328 /* Get and check the NT headers */
2329 NtHeaders = RtlImageNtHeader(ImageBase);
2330 if (NtHeaders == NULL)
2331 {
2332 DPRINT1("RtlImageNtHeaders() failed\n");
2333 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2334 NtClose (SectionHandle);
2335 RtlFreeUnicodeString(&FullDosName);
2336 return STATUS_UNSUCCESSFUL;
2337 }
2338 }
2339 DPRINT("Mapped %wZ at %x\n", &FullDosName, ImageBase);
2340 if (MappedAsDataFile)
2341 {
2342 ASSERT(NULL != BaseAddress);
2343 if (NULL != BaseAddress)
2344 {
2345 *BaseAddress = (PVOID) ((char *) *BaseAddress + 1);
2346 }
2347 *Module = NULL;
2348 RtlFreeUnicodeString(&FullDosName);
2349 NtClose(SectionHandle);
2350 return STATUS_SUCCESS;
2351 }
2352 /* If the base address is different from the
2353 * one the DLL is actually loaded, perform any
2354 * relocation. */
2355 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2356 {
2357 DPRINT1("Relocating (%lx -> %p) %wZ\n",
2358 NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
2359 Status = LdrPerformRelocations(NtHeaders, ImageBase);
2360 if (!NT_SUCCESS(Status))
2361 {
2362 DPRINT1("LdrPerformRelocations() failed\n");
2363 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2364 NtClose (SectionHandle);
2365 RtlFreeUnicodeString(&FullDosName);
2366 return STATUS_UNSUCCESSFUL;
2367 }
2368 }
2369 *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer);
2370 (*Module)->SectionPointer = SectionHandle;
2371 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2372 {
2373 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2374 }
2375 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
2376 {
2377 (*Module)->Flags |= LDRP_IMAGE_DLL;
2378 }
2379 /* fixup the imported calls entry points */
2380 Status = LdrFixupImports(SearchPath, *Module);
2381 if (!NT_SUCCESS(Status))
2382 {
2383 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
2384 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2385 NtClose (SectionHandle);
2386 RtlFreeUnicodeString (&FullDosName);
2387 RtlFreeUnicodeString (&(*Module)->FullDllName);
2388 RtlFreeUnicodeString (&(*Module)->BaseDllName);
2389 RemoveEntryList (&(*Module)->InLoadOrderLinks);
2390 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2391 return Status;
2392 }
2393
2394 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2395 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
2396 &(*Module)->InInitializationOrderModuleList);
2397 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2398 }
2399 return STATUS_SUCCESS;
2400 }
2401
2402 static NTSTATUS
2403 LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
2404 BOOLEAN Unload)
2405 {
2406 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
2407 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
2408 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
2409 PCHAR ImportedName;
2410 PLDR_DATA_TABLE_ENTRY ImportedModule;
2411 NTSTATUS Status = 0;
2412 LONG LoadCount;
2413 ULONG Size;
2414
2415 if (Unload)
2416 {
2417 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2418 }
2419
2420 LoadCount = LdrpDecrementLoadCount(Module, Unload);
2421
2422 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
2423
2424 if (LoadCount == 0)
2425 {
2426 /* ?????????????????? */
2427 }
2428 else if (!(Module->Flags & LDRP_STATIC_LINK) && LoadCount == 1)
2429 {
2430 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
2431 RtlImageDirectoryEntryToData(Module->DllBase,
2432 TRUE,
2433 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
2434 &Size);
2435 if (BoundImportDescriptor)
2436 {
2437 /* dereferencing all imported modules, use the bound import descriptor */
2438 BoundImportDescriptorCurrent = BoundImportDescriptor;
2439 while (BoundImportDescriptorCurrent->OffsetModuleName)
2440 {
2441 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
2442 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2443 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2444 if (!NT_SUCCESS(Status))
2445 {
2446 DPRINT1("unable to found imported modul %s\n", ImportedName);
2447 }
2448 else
2449 {
2450 if (Module != ImportedModule)
2451 {
2452 Status = LdrpUnloadModule(ImportedModule, FALSE);
2453 if (!NT_SUCCESS(Status))
2454 {
2455 DPRINT1("unable to unload %s\n", ImportedName);
2456 }
2457 }
2458 }
2459 BoundImportDescriptorCurrent++;
2460 }
2461 }
2462 else
2463 {
2464 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
2465 RtlImageDirectoryEntryToData(Module->DllBase,
2466 TRUE,
2467 IMAGE_DIRECTORY_ENTRY_IMPORT,
2468 &Size);
2469 if (ImportModuleDirectory)
2470 {
2471 /* dereferencing all imported modules, use the import descriptor */
2472 while (ImportModuleDirectory->Name)
2473 {
2474 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
2475 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2476 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2477 if (!NT_SUCCESS(Status))
2478 {
2479 DPRINT1("unable to found imported modul %s\n", ImportedName);
2480 }
2481 else
2482 {
2483 if (Module != ImportedModule)
2484 {
2485 Status = LdrpUnloadModule(ImportedModule, FALSE);
2486 if (!NT_SUCCESS(Status))
2487 {
2488 DPRINT1("unable to unload %s\n", ImportedName);
2489 }
2490 }
2491 }
2492 ImportModuleDirectory++;
2493 }
2494 }
2495 }
2496 }
2497
2498 if (Unload)
2499 {
2500 if (!(Module->Flags & LDRP_STATIC_LINK))
2501 {
2502 LdrpDetachProcess(FALSE);
2503 }
2504
2505 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2506 }
2507 return STATUS_SUCCESS;
2508
2509 }
2510
2511 /*
2512 * @implemented
2513 */
2514 NTSTATUS NTAPI
2515 LdrUnloadDll (IN PVOID BaseAddress)
2516 {
2517 PLDR_DATA_TABLE_ENTRY Module;
2518 NTSTATUS Status;
2519
2520 if (BaseAddress == NULL)
2521 return STATUS_SUCCESS;
2522
2523 if (LdrMappedAsDataFile(&BaseAddress))
2524 {
2525 Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
2526 }
2527 else
2528 {
2529 Status = LdrFindEntryForAddress(BaseAddress, &Module);
2530 if (NT_SUCCESS(Status))
2531 {
2532 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
2533 Status = LdrpUnloadModule(Module, TRUE);
2534 }
2535 }
2536
2537 return Status;
2538 }
2539
2540 /*
2541 * @implemented
2542 */
2543 NTSTATUS NTAPI
2544 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
2545 {
2546 PLIST_ENTRY ModuleListHead;
2547 PLIST_ENTRY Entry;
2548 PLDR_DATA_TABLE_ENTRY Module;
2549 NTSTATUS Status;
2550
2551 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
2552
2553 Status = STATUS_DLL_NOT_FOUND;
2554 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2555 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2556 Entry = ModuleListHead->Flink;
2557 while (Entry != ModuleListHead)
2558 {
2559 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2560
2561 DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module->BaseDllName, Module->DllBase);
2562
2563 if (Module->DllBase == BaseAddress)
2564 {
2565 if (Module->TlsIndex == 0xFFFF)
2566 {
2567 Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
2568 Status = STATUS_SUCCESS;
2569 }
2570 break;
2571 }
2572 Entry = Entry->Flink;
2573 }
2574 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2575 return Status;
2576 }
2577
2578 /*
2579 * @implemented
2580 */
2581 NTSTATUS NTAPI
2582 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
2583 IN PULONG DllCharacteristics,
2584 IN PUNICODE_STRING DllName,
2585 OUT PVOID *DllHandle)
2586 {
2587 PLDR_DATA_TABLE_ENTRY Module;
2588 NTSTATUS Status;
2589
2590 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
2591 DllName, DllPath ? DllPath : L"");
2592
2593 /* NULL is the current executable */
2594 if (DllName == NULL)
2595 {
2596 *DllHandle = ExeModule->DllBase;
2597 DPRINT("BaseAddress 0x%lx\n", *DllHandle);
2598 return STATUS_SUCCESS;
2599 }
2600
2601 Status = LdrFindEntryForName(DllName, &Module, FALSE);
2602 if (NT_SUCCESS(Status))
2603 {
2604 *DllHandle = Module->DllBase;
2605 return STATUS_SUCCESS;
2606 }
2607
2608 DPRINT("Failed to find dll %wZ\n", DllName);
2609 *DllHandle = NULL;
2610 return STATUS_DLL_NOT_FOUND;
2611 }
2612
2613 /*
2614 * @implemented
2615 */
2616 NTSTATUS NTAPI
2617 LdrAddRefDll(IN ULONG Flags,
2618 IN PVOID BaseAddress)
2619 {
2620 PLIST_ENTRY ModuleListHead;
2621 PLIST_ENTRY Entry;
2622 PLDR_DATA_TABLE_ENTRY Module;
2623 NTSTATUS Status;
2624
2625 if (Flags & ~(LDR_PIN_MODULE))
2626 {
2627 return STATUS_INVALID_PARAMETER;
2628 }
2629
2630 Status = STATUS_DLL_NOT_FOUND;
2631 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2632 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2633 Entry = ModuleListHead->Flink;
2634 while (Entry != ModuleListHead)
2635 {
2636 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2637
2638 if (Module->DllBase == BaseAddress)
2639 {
2640 if (Flags & LDR_PIN_MODULE)
2641 {
2642 Module->Flags |= LDRP_STATIC_LINK;
2643 }
2644 else
2645 {
2646 LdrpIncrementLoadCount(Module,
2647 FALSE);
2648 }
2649 Status = STATUS_SUCCESS;
2650 break;
2651 }
2652 Entry = Entry->Flink;
2653 }
2654 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2655 return Status;
2656 }
2657
2658 /*
2659 * @implemented
2660 */
2661 PVOID NTAPI
2662 RtlPcToFileHeader(IN PVOID PcValue,
2663 PVOID* BaseOfImage)
2664 {
2665 PLIST_ENTRY ModuleListHead;
2666 PLIST_ENTRY Entry;
2667 PLDR_DATA_TABLE_ENTRY Module;
2668 PVOID ImageBase = NULL;
2669
2670 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2671 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2672 Entry = ModuleListHead->Flink;
2673 while (Entry != ModuleListHead)
2674 {
2675 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2676
2677 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
2678 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
2679 {
2680 ImageBase = Module->DllBase;
2681 break;
2682 }
2683 Entry = Entry->Flink;
2684 }
2685 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2686
2687 *BaseOfImage = ImageBase;
2688 return ImageBase;
2689 }
2690
2691 /*
2692 * @implemented
2693 */
2694 NTSTATUS NTAPI
2695 LdrGetProcedureAddress (IN PVOID BaseAddress,
2696 IN PANSI_STRING Name,
2697 IN ULONG Ordinal,
2698 OUT PVOID *ProcedureAddress)
2699 {
2700 NTSTATUS Status = STATUS_PROCEDURE_NOT_FOUND;
2701 if (Name && Name->Length)
2702 {
2703 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
2704 }
2705 else
2706 {
2707 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
2708 }
2709
2710 DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
2711 BaseAddress, Name, Ordinal, ProcedureAddress);
2712
2713 _SEH2_TRY
2714 {
2715 if (Name && Name->Length)
2716 {
2717 /* by name */
2718 *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
2719 if (*ProcedureAddress != NULL)
2720 {
2721 Status = STATUS_SUCCESS;
2722 }
2723 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
2724 }
2725 else
2726 {
2727 /* by ordinal */
2728 Ordinal &= 0x0000FFFF;
2729 *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
2730 if (*ProcedureAddress)
2731 {
2732 Status = STATUS_SUCCESS;
2733 }
2734 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal);
2735 }
2736 }
2737 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2738 {
2739 Status = STATUS_DLL_NOT_FOUND;
2740 }
2741 _SEH2_END;
2742
2743 return Status;
2744 }
2745
2746 /**********************************************************************
2747 * NAME LOCAL
2748 * LdrpDetachProcess
2749 *
2750 * DESCRIPTION
2751 * Unload dll's which are no longer referenced from others dll's
2752 *
2753 * ARGUMENTS
2754 * none
2755 *
2756 * RETURN VALUE
2757 * none
2758 *
2759 * REVISIONS
2760 *
2761 * NOTE
2762 * The loader lock must be held on enty.
2763 */
2764 static VOID
2765 LdrpDetachProcess(BOOLEAN UnloadAll)
2766 {
2767 PLIST_ENTRY ModuleListHead;
2768 PLIST_ENTRY Entry;
2769 PLDR_DATA_TABLE_ENTRY Module;
2770 static ULONG CallingCount = 0;
2771
2772 DPRINT("LdrpDetachProcess() called for %wZ\n",
2773 &ExeModule->BaseDllName);
2774
2775 if (UnloadAll)
2776 LdrpDllShutdownInProgress = TRUE;
2777
2778 CallingCount++;
2779
2780 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2781 Entry = ModuleListHead->Blink;
2782 while (Entry != ModuleListHead)
2783 {
2784 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2785 if (((UnloadAll && Module->LoadCount == LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0) &&
2786 Module->Flags & LDRP_ENTRY_PROCESSED &&
2787 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2788 {
2789 Module->Flags |= LDRP_UNLOAD_IN_PROGRESS;
2790 if (Module == LdrpLastModule)
2791 {
2792 LdrpLastModule = NULL;
2793 }
2794 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED)
2795 {
2796 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2797 &Module->BaseDllName, Module->EntryPoint);
2798 LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2799 }
2800 else
2801 {
2802 TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
2803 }
2804 Entry = ModuleListHead->Blink;
2805 }
2806 else
2807 {
2808 Entry = Entry->Blink;
2809 }
2810 }
2811
2812 if (CallingCount == 1)
2813 {
2814 Entry = ModuleListHead->Blink;
2815 while (Entry != ModuleListHead)
2816 {
2817 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2818 Entry = Entry->Blink;
2819 if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
2820 ((UnloadAll && Module->LoadCount != LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0))
2821 {
2822 /* remove the module entry from the list */
2823 RemoveEntryList (&Module->InLoadOrderLinks);
2824 RemoveEntryList (&Module->InInitializationOrderModuleList);
2825
2826 NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase);
2827 NtClose (Module->SectionPointer);
2828
2829 TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
2830
2831 RtlFreeUnicodeString (&Module->FullDllName);
2832 RtlFreeUnicodeString (&Module->BaseDllName);
2833
2834 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2835 }
2836 }
2837 }
2838 CallingCount--;
2839 DPRINT("LdrpDetachProcess() done\n");
2840 }
2841
2842 /**********************************************************************
2843 * NAME LOCAL
2844 * LdrpAttachProcess
2845 *
2846 * DESCRIPTION
2847 * Initialize all dll's which are prepered for loading
2848 *
2849 * ARGUMENTS
2850 * none
2851 *
2852 * RETURN VALUE
2853 * status
2854 *
2855 * REVISIONS
2856 *
2857 * NOTE
2858 * The loader lock must be held on entry.
2859 *
2860 */
2861 static NTSTATUS
2862 LdrpAttachProcess(VOID)
2863 {
2864 PLIST_ENTRY ModuleListHead;
2865 PLIST_ENTRY Entry;
2866 PLDR_DATA_TABLE_ENTRY Module;
2867 BOOLEAN Result;
2868 NTSTATUS Status = STATUS_SUCCESS;
2869
2870 DPRINT("LdrpAttachProcess() called for %wZ\n",
2871 &ExeModule->BaseDllName);
2872
2873 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2874 Entry = ModuleListHead->Flink;
2875 while (Entry != ModuleListHead)
2876 {
2877 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2878 if (!(Module->Flags & (LDRP_LOAD_IN_PROGRESS|LDRP_UNLOAD_IN_PROGRESS|LDRP_ENTRY_PROCESSED)))
2879 {
2880 Module->Flags |= LDRP_LOAD_IN_PROGRESS;
2881 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2882 &Module->BaseDllName, Module->EntryPoint);
2883 Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2884 if (!Result)
2885 {
2886 Status = STATUS_DLL_INIT_FAILED;
2887 break;
2888 }
2889 if (Module->Flags & LDRP_IMAGE_DLL && Module->EntryPoint != 0)
2890 {
2891 Module->Flags |= LDRP_PROCESS_ATTACH_CALLED|LDRP_ENTRY_PROCESSED;
2892 }
2893 else
2894 {
2895 Module->Flags |= LDRP_ENTRY_PROCESSED;
2896 }
2897 Module->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2898 }
2899 Entry = Entry->Flink;
2900 }
2901
2902 DPRINT("LdrpAttachProcess() done\n");
2903
2904 return Status;
2905 }
2906
2907 /*
2908 * @implemented
2909 */
2910 BOOLEAN NTAPI
2911 RtlDllShutdownInProgress (VOID)
2912 {
2913 return LdrpDllShutdownInProgress;
2914 }
2915
2916 /*
2917 * @implemented
2918 */
2919 NTSTATUS NTAPI
2920 LdrShutdownProcess (VOID)
2921 {
2922 LdrpDetachProcess(TRUE);
2923 return STATUS_SUCCESS;
2924 }
2925
2926 /*
2927 * @implemented
2928 */
2929
2930 NTSTATUS
2931 LdrpAttachThread (VOID)
2932 {
2933 PLIST_ENTRY ModuleListHead;
2934 PLIST_ENTRY Entry;
2935 PLDR_DATA_TABLE_ENTRY Module;
2936 NTSTATUS Status;
2937
2938 DPRINT("LdrpAttachThread() called for %wZ\n",
2939 &ExeModule->BaseDllName);
2940
2941 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2942
2943 Status = LdrpInitializeTlsForThread();
2944
2945 if (NT_SUCCESS(Status))
2946 {
2947 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2948 Entry = ModuleListHead->Flink;
2949
2950 while (Entry != ModuleListHead)
2951 {
2952 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2953 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2954 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2955 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2956 {
2957 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2958 &Module->BaseDllName, Module->EntryPoint);
2959 LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);
2960 }
2961 Entry = Entry->Flink;
2962 }
2963
2964 Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
2965 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2966 LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
2967 }
2968
2969 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2970
2971 DPRINT("LdrpAttachThread() done\n");
2972
2973 return Status;
2974 }
2975
2976
2977 /*
2978 * @implemented
2979 */
2980 NTSTATUS NTAPI
2981 LdrShutdownThread (VOID)
2982 {
2983 PLIST_ENTRY ModuleListHead;
2984 PLIST_ENTRY Entry;
2985 PLDR_DATA_TABLE_ENTRY Module;
2986
2987 DPRINT("LdrShutdownThread() called for %wZ\n",
2988 &ExeModule->BaseDllName);
2989
2990 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2991
2992 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2993 Entry = ModuleListHead->Blink;
2994 while (Entry != ModuleListHead)
2995 {
2996 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2997
2998 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2999 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
3000 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
3001 {
3002 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
3003 &Module->BaseDllName, Module->EntryPoint);
3004 LdrpCallDllEntry(Module, DLL_THREAD_DETACH, NULL);
3005 }
3006 Entry = Entry->Blink;
3007 }
3008
3009 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3010
3011 if (LdrpTlsArray)
3012 {
3013 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer);
3014 }
3015
3016 DPRINT("LdrShutdownThread() done\n");
3017
3018 return STATUS_SUCCESS;
3019 }
3020
3021
3022 /***************************************************************************
3023 * NAME EXPORTED
3024 * LdrQueryProcessModuleInformation
3025 *
3026 * DESCRIPTION
3027 *
3028 * ARGUMENTS
3029 *
3030 * RETURN VALUE
3031 *
3032 * REVISIONS
3033 *
3034 * NOTE
3035 *
3036 * @implemented
3037 */
3038 NTSTATUS NTAPI
3039 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
3040 IN ULONG Size OPTIONAL,
3041 OUT PULONG ReturnedSize)
3042 {
3043 PLIST_ENTRY ModuleListHead;
3044 PLIST_ENTRY Entry;
3045 PLDR_DATA_TABLE_ENTRY Module;
3046 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
3047 NTSTATUS Status = STATUS_SUCCESS;
3048 ULONG UsedSize = sizeof(ULONG);
3049 ANSI_STRING AnsiString;
3050 PCHAR p;
3051
3052 DPRINT("LdrQueryProcessModuleInformation() called\n");
3053 // FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c
3054 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
3055
3056 if (ModuleInformation == NULL || Size == 0)
3057 {
3058 Status = STATUS_INFO_LENGTH_MISMATCH;
3059 }
3060 else
3061 {
3062 ModuleInformation->NumberOfModules = 0;
3063 ModulePtr = &ModuleInformation->Modules[0];
3064 Status = STATUS_SUCCESS;
3065 }
3066
3067 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
3068 Entry = ModuleListHead->Flink;
3069
3070 while (Entry != ModuleListHead)
3071 {
3072 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3073
3074 DPRINT(" Module %wZ\n",
3075 &Module->FullDllName);
3076
3077 if (UsedSize > Size)
3078 {
3079 Status = STATUS_INFO_LENGTH_MISMATCH;
3080 }
3081 else if (ModuleInformation != NULL)
3082 {
3083 ModulePtr->Section = 0;
3084 ModulePtr->MappedBase = NULL; // FIXME: ??
3085 ModulePtr->ImageBase = Module->DllBase;
3086 ModulePtr->ImageSize = Module->SizeOfImage;
3087 ModulePtr->Flags = Module->Flags;
3088 ModulePtr->LoadOrderIndex = 0; // FIXME: ??
3089 ModulePtr->InitOrderIndex = 0; // FIXME: ??
3090 ModulePtr->LoadCount = Module->LoadCount;
3091
3092 AnsiString.Length = 0;
3093 AnsiString.MaximumLength = 256;
3094 AnsiString.Buffer = ModulePtr->FullPathName;
3095 RtlUnicodeStringToAnsiString(&AnsiString,
3096 &Module->FullDllName,
3097 FALSE);
3098
3099 p = strrchr(ModulePtr->FullPathName, '\\');
3100 if (p != NULL)
3101 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
3102 else
3103 ModulePtr->OffsetToFileName = 0;
3104
3105 ModulePtr++;
3106 ModuleInformation->NumberOfModules++;
3107 }
3108 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
3109
3110 Entry = Entry->Flink;
3111 }
3112
3113 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3114
3115 if (ReturnedSize != 0)
3116 *ReturnedSize = UsedSize;
3117
3118 DPRINT("LdrQueryProcessModuleInformation() done\n");
3119
3120 return(Status);
3121 }
3122
3123
3124 static BOOLEAN
3125 LdrpCheckImageChecksum (IN PVOID BaseAddress,
3126 IN ULONG ImageSize)
3127 {
3128 PIMAGE_NT_HEADERS Header;
3129 PUSHORT Ptr;
3130 ULONG Sum;
3131 ULONG CalcSum;
3132 ULONG HeaderSum;
3133 ULONG i;
3134
3135 Header = RtlImageNtHeader (BaseAddress);
3136 if (Header == NULL)
3137 return FALSE;
3138
3139 HeaderSum = Header->OptionalHeader.CheckSum;
3140 if (HeaderSum == 0)
3141 return TRUE;
3142
3143 Sum = 0;
3144 Ptr = (PUSHORT) BaseAddress;
3145 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
3146 {
3147 Sum += (ULONG)*Ptr;
3148 if (HIWORD(Sum) != 0)
3149 {
3150 Sum = LOWORD(Sum) + HIWORD(Sum);
3151 }
3152 Ptr++;
3153 }
3154
3155 if (ImageSize & 1)
3156 {
3157 Sum += (ULONG)*((PUCHAR)Ptr);
3158 if (HIWORD(Sum) != 0)
3159 {
3160 Sum = LOWORD(Sum) + HIWORD(Sum);
3161 }
3162 }
3163
3164 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
3165
3166 /* Subtract image checksum from calculated checksum. */
3167 /* fix low word of checksum */
3168 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
3169 {
3170 CalcSum -= LOWORD(HeaderSum);
3171 }
3172 else
3173 {
3174 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
3175 }
3176
3177 /* fix high word of checksum */
3178 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
3179 {
3180 CalcSum -= HIWORD(HeaderSum);
3181 }
3182 else
3183 {
3184 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
3185 }
3186
3187 /* add file length */
3188 CalcSum += ImageSize;
3189
3190 return (BOOLEAN)(CalcSum == HeaderSum);
3191 }
3192
3193 /*
3194 * Compute size of an image as it is actually present in virt memory
3195 * (i.e. excluding NEVER_LOAD sections)
3196 */
3197 ULONG
3198 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders)
3199 {
3200 PIMAGE_SECTION_HEADER SectionHeader;
3201 unsigned SectionIndex;
3202 ULONG ResidentSize;
3203
3204 SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader
3205 + NTHeaders->FileHeader.SizeOfOptionalHeader);
3206 ResidentSize = 0;
3207 for (SectionIndex = 0; SectionIndex < NTHeaders->FileHeader.NumberOfSections; SectionIndex++)
3208 {
3209 if (0 == (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE)
3210 && ResidentSize < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)
3211 {
3212 ResidentSize = SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize;
3213 }
3214 SectionHeader++;
3215 }
3216
3217 return ResidentSize;
3218 }
3219
3220
3221 /***************************************************************************
3222 * NAME EXPORTED
3223 * LdrVerifyImageMatchesChecksum
3224 *
3225 * DESCRIPTION
3226 *
3227 * ARGUMENTS
3228 *
3229 * RETURN VALUE
3230 *
3231 * REVISIONS
3232 *
3233 * NOTE
3234 *
3235 * @implemented
3236 */
3237 NTSTATUS NTAPI
3238 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
3239 ULONG Unknown1,
3240 ULONG Unknown2,
3241 ULONG Unknown3)
3242 {
3243 FILE_STANDARD_INFORMATION FileInfo;
3244 IO_STATUS_BLOCK IoStatusBlock;
3245 HANDLE SectionHandle;
3246 SIZE_T ViewSize;
3247 PVOID BaseAddress;
3248 BOOLEAN Result;
3249 NTSTATUS Status;
3250
3251 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
3252
3253 Status = NtCreateSection (&SectionHandle,
3254 SECTION_MAP_READ,
3255 NULL,
3256 NULL,
3257 PAGE_READONLY,
3258 SEC_COMMIT,
3259 FileHandle);
3260 if (!NT_SUCCESS(Status))
3261 {
3262 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
3263 return Status;
3264 }
3265
3266 ViewSize = 0;
3267 BaseAddress = NULL;
3268 Status = NtMapViewOfSection (SectionHandle,
3269 NtCurrentProcess (),
3270 &BaseAddress,
3271 0,
3272 0,
3273 NULL,
3274 &ViewSize,
3275 ViewShare,
3276 0,
3277 PAGE_READONLY);
3278 if (!NT_SUCCESS(Status))
3279 {
3280 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3281 NtClose (SectionHandle);
3282 return Status;
3283 }
3284
3285 Status = NtQueryInformationFile (FileHandle,
3286 &IoStatusBlock,
3287 &FileInfo,
3288 sizeof (FILE_STANDARD_INFORMATION),
3289 FileStandardInformation);
3290 if (!NT_SUCCESS(Status))
3291 {
3292 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3293 NtUnmapViewOfSection (NtCurrentProcess (),
3294 BaseAddress);
3295 NtClose (SectionHandle);
3296 return Status;
3297 }
3298
3299 Result = LdrpCheckImageChecksum (BaseAddress,
3300 FileInfo.EndOfFile.u.LowPart);
3301 if (Result == FALSE)
3302 {
3303 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
3304 }
3305
3306 NtUnmapViewOfSection (NtCurrentProcess (),
3307 BaseAddress);
3308
3309 NtClose (SectionHandle);
3310
3311 return Status;
3312 }
3313
3314
3315 /***************************************************************************
3316 * NAME EXPORTED
3317 * LdrQueryImageFileExecutionOptions
3318 *
3319 * DESCRIPTION
3320 *
3321 * ARGUMENTS
3322 *
3323 * RETURN VALUE
3324 *
3325 * REVISIONS
3326 *
3327 * NOTE
3328 *
3329 * @implemented
3330 */
3331 NTSTATUS NTAPI
3332 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
3333 IN PCWSTR ValueName,
3334 IN ULONG Type,
3335 OUT PVOID Buffer,
3336 IN ULONG BufferSize,
3337 OUT PULONG ReturnedLength OPTIONAL)
3338 {
3339 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
3340 OBJECT_ATTRIBUTES ObjectAttributes;
3341 UNICODE_STRING ValueNameString;
3342 UNICODE_STRING KeyName;
3343 WCHAR NameBuffer[256];
3344 HANDLE KeyHandle;
3345 ULONG KeyInfoSize;
3346 ULONG ResultSize;
3347 PWCHAR Ptr;
3348 NTSTATUS Status;
3349
3350 wcscpy (NameBuffer,
3351 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
3352 Ptr = wcsrchr (SubKey->Buffer, L'\\');
3353 if (Ptr == NULL)
3354 {
3355 Ptr = SubKey->Buffer;
3356 }
3357 else
3358 {
3359 Ptr++;
3360 }
3361 wcscat (NameBuffer, Ptr);
3362 RtlInitUnicodeString (&KeyName,
3363 NameBuffer);
3364
3365 InitializeObjectAttributes (&ObjectAttributes,
3366 &KeyName,
3367 OBJ_CASE_INSENSITIVE,
3368 NULL,
3369 NULL);
3370
3371 Status = NtOpenKey (&KeyHandle,
3372 KEY_READ,
3373 &ObjectAttributes);
3374 if (!NT_SUCCESS(Status))
3375 {
3376 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
3377 return Status;
3378 }
3379
3380 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
3381 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3382 HEAP_ZERO_MEMORY,
3383 KeyInfoSize);
3384 if (KeyInfo == NULL)
3385 {
3386 NtClose (KeyHandle);
3387 return STATUS_INSUFFICIENT_RESOURCES;
3388 }
3389
3390 RtlInitUnicodeString (&ValueNameString,
3391 (PWSTR)ValueName);
3392 Status = NtQueryValueKey (KeyHandle,
3393 &ValueNameString,
3394 KeyValuePartialInformation,
3395 KeyInfo,
3396 KeyInfoSize,
3397 &ResultSize);
3398 if (Status == STATUS_BUFFER_OVERFLOW)
3399 {
3400 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
3401 RtlFreeHeap (RtlGetProcessHeap(),
3402 0,
3403 KeyInfo);
3404 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3405 HEAP_ZERO_MEMORY,
3406 KeyInfoSize);
3407 if (KeyInfo == NULL)
3408 {
3409 NtClose (KeyHandle);
3410 return STATUS_INSUFFICIENT_RESOURCES;
3411 }
3412
3413 Status = NtQueryValueKey (KeyHandle,
3414 &ValueNameString,
3415 KeyValuePartialInformation,
3416 KeyInfo,
3417 KeyInfoSize,
3418 &ResultSize);
3419 }
3420 NtClose (KeyHandle);
3421
3422 if (!NT_SUCCESS(Status))
3423 {
3424 if (KeyInfo != NULL)
3425 {
3426 RtlFreeHeap (RtlGetProcessHeap(),
3427 0,
3428 KeyInfo);
3429 }
3430 return Status;
3431 }
3432
3433 if (KeyInfo->Type != Type)
3434 {
3435 RtlFreeHeap (RtlGetProcessHeap(),
3436 0,
3437 KeyInfo);
3438 return STATUS_OBJECT_TYPE_MISMATCH;
3439 }
3440
3441 ResultSize = BufferSize;
3442 if (ResultSize < KeyInfo->DataLength)
3443 {
3444 Status = STATUS_BUFFER_OVERFLOW;
3445 }
3446 else
3447 {
3448 ResultSize = KeyInfo->DataLength;
3449 }
3450 RtlCopyMemory (Buffer,
3451 &KeyInfo->Data,
3452 ResultSize);
3453
3454 RtlFreeHeap (RtlGetProcessHeap(),
3455 0,
3456 KeyInfo);
3457
3458 if (ReturnedLength != NULL)
3459 {
3460 *ReturnedLength = ResultSize;
3461 }
3462
3463 return Status;
3464 }
3465
3466
3467 PIMAGE_BASE_RELOCATION NTAPI
3468 LdrProcessRelocationBlock(IN ULONG_PTR Address,
3469 IN ULONG Count,
3470 IN PUSHORT TypeOffset,
3471 IN LONG_PTR Delta)
3472 {
3473 SHORT Offset;
3474 USHORT Type;
3475 USHORT i;
3476 PUSHORT ShortPtr;
3477 PULONG LongPtr;
3478
3479 for (i = 0; i < Count; i++)
3480 {
3481 Offset = *TypeOffset & 0xFFF;
3482 Type = *TypeOffset >> 12;
3483
3484 switch (Type)
3485 {
3486 case IMAGE_REL_BASED_ABSOLUTE:
3487 break;
3488
3489 case IMAGE_REL_BASED_HIGH:
3490 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3491 *ShortPtr += HIWORD(Delta);
3492 break;
3493
3494 case IMAGE_REL_BASED_LOW:
3495 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3496 *ShortPtr += LOWORD(Delta);
3497 break;
3498
3499 case IMAGE_REL_BASED_HIGHLOW:
3500 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3501 *LongPtr += Delta;
3502 break;
3503
3504 case IMAGE_REL_BASED_HIGHADJ:
3505 case IMAGE_REL_BASED_MIPS_JMPADDR:
3506 default:
3507 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
3508 return NULL;
3509 }
3510
3511 TypeOffset++;
3512 }
3513
3514 return (PIMAGE_BASE_RELOCATION)TypeOffset;
3515 }
3516
3517 NTSTATUS
3518 NTAPI
3519 LdrLockLoaderLock(IN ULONG Flags,
3520 OUT PULONG Disposition OPTIONAL,
3521 OUT PULONG Cookie OPTIONAL)
3522 {
3523 NTSTATUS Status;
3524 BOOLEAN Ret;
3525 BOOLEAN CookieSet = FALSE;
3526
3527 if ((Flags != 0x01) && (Flags != 0x02))
3528 return STATUS_INVALID_PARAMETER_1;
3529
3530 if (!Cookie) return STATUS_INVALID_PARAMETER_3;
3531
3532 /* Set some defaults for failure while verifying params */
3533 _SEH2_TRY
3534 {
3535 *Cookie = 0;
3536 CookieSet = TRUE;
3537 if (Disposition) *Disposition = 0;
3538 }
3539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3540 {
3541 if (CookieSet)
3542 Status = STATUS_INVALID_PARAMETER_3;
3543 else
3544 Status = STATUS_INVALID_PARAMETER_2;
3545 }
3546 _SEH2_END;
3547
3548 if (Flags == 0x01)
3549 {
3550 DPRINT1("Warning: Reporting errors with exception not supported yet!\n");
3551 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3552 Status = STATUS_SUCCESS;
3553
3554 }
3555 else
3556 {
3557 if (!Disposition) return STATUS_INVALID_PARAMETER_2;
3558
3559 Ret = RtlTryEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3560
3561 if (Ret)
3562 *Disposition = 0x01;
3563 else
3564 *Disposition = 0x02;
3565
3566 Status = STATUS_SUCCESS;
3567 }
3568
3569 /* FIXME: Cookie is based on part of the thread id */
3570 *Cookie = (ULONG)NtCurrentTeb()->RealClientId.UniqueThread;
3571 return Status;
3572 }
3573
3574 NTSTATUS
3575 NTAPI
3576 LdrUnlockLoaderLock(IN ULONG Flags,
3577 IN ULONG Cookie OPTIONAL)
3578 {
3579 if (Flags != 0x01)
3580 return STATUS_INVALID_PARAMETER_1;
3581
3582 if (Cookie != (ULONG)NtCurrentTeb()->RealClientId.UniqueThread)
3583 return STATUS_INVALID_PARAMETER_2;
3584
3585 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
3586
3587 return STATUS_SUCCESS;
3588 }
3589
3590 BOOLEAN
3591 NTAPI
3592 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
3593 {
3594 UNIMPLEMENTED;
3595 return FALSE;
3596 }