2b77c3a84dde106f4a8fa3023cf0e26c6a29e30a
[reactos.git] / reactos / dll / ntdll / ldr / utils.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/ntdll/ldr/utils.c
5 * PURPOSE: Process startup for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
8 * Michael Martin
9 */
10
11 /*
12 * TODO:
13 * - Handle loading flags correctly
14 * - Handle errors correctly (unload dll's)
15 * - Implement a faster way to find modules (hash table)
16 * - any more ??
17 */
18
19 /* INCLUDES *****************************************************************/
20
21 #include <ntdll.h>
22 #define NDEBUG
23 #include <debug.h>
24
25 #define LDRP_PROCESS_CREATION_TIME 0xffff
26 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
27
28 /* GLOBALS *******************************************************************/
29
30 #ifdef NDEBUG
31 #define TRACE_LDR(...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
32 #endif
33
34 typedef struct _TLS_DATA
35 {
36 PVOID StartAddressOfRawData;
37 DWORD TlsDataSize;
38 DWORD TlsZeroSize;
39 PIMAGE_TLS_CALLBACK *TlsAddressOfCallBacks;
40 PLDR_DATA_TABLE_ENTRY Module;
41 } TLS_DATA, *PTLS_DATA;
42
43 static BOOLEAN LdrpDllShutdownInProgress = FALSE;
44 static PTLS_DATA LdrpTlsArray = NULL;
45 static ULONG LdrpTlsCount = 0;
46 static ULONG LdrpTlsSize = 0;
47 static HANDLE LdrpKnownDllsDirHandle = NULL;
48 static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
49 static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL;
50 extern PLDR_DATA_TABLE_ENTRY ExeModule;
51
52 /* PROTOTYPES ****************************************************************/
53
54 static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref);
55 static PVOID LdrFixupForward(PCHAR ForwardName);
56 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
57 static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
58 IN ULONG LoadFlags,
59 IN PUNICODE_STRING Name,
60 OUT PLDR_DATA_TABLE_ENTRY *Module,
61 OUT PVOID *BaseAddress OPTIONAL);
62 static NTSTATUS LdrpAttachProcess(VOID);
63 static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
64 static NTSTATUS LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Unload);
65
66 NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fulldosname );
67 NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module );
68
69 /* FUNCTIONS *****************************************************************/
70
71 BOOLEAN
72 LdrMappedAsDataFile(PVOID *BaseAddress)
73 {
74 if (0 != ((DWORD_PTR) *BaseAddress & (PAGE_SIZE - 1)))
75 {
76 *BaseAddress = (PVOID) ((DWORD_PTR) *BaseAddress & ~ ((DWORD_PTR) PAGE_SIZE - 1));
77 return TRUE;
78 }
79
80 return FALSE;
81 }
82
83 static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
84 {
85 LONG LoadCount;
86 if (!Locked)
87 {
88 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
89 }
90 LoadCount = Module->LoadCount;
91 if (Module->LoadCount > 0 && Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
92 {
93 Module->LoadCount--;
94 }
95 if (!Locked)
96 {
97 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
98 }
99 return LoadCount;
100 }
101
102 static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
103 {
104 LONG LoadCount;
105 if (!Locked)
106 {
107 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
108 }
109 LoadCount = Module->LoadCount;
110 if (Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
111 {
112 Module->LoadCount++;
113 }
114 if (!Locked)
115 {
116 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
117 }
118 return LoadCount;
119 }
120
121 static __inline VOID LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module, ULONG Size, BOOLEAN Locked)
122 {
123 if (!Locked)
124 {
125 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
126 }
127 Module->TlsIndex = (SHORT)LdrpTlsCount;
128 LdrpTlsCount++;
129 LdrpTlsSize += Size;
130 if (!Locked)
131 {
132 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
133 }
134 }
135
136 static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
137 {
138 PIMAGE_TLS_CALLBACK *TlsCallback;
139 if (Module->TlsIndex != 0xFFFF && Module->LoadCount == LDRP_PROCESS_CREATION_TIME)
140 {
141 TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
142 if (TlsCallback)
143 {
144 while (*TlsCallback)
145 {
146 TRACE_LDR("%wZ - Calling tls callback at %x\n",
147 &Module->BaseDllName, *TlsCallback);
148 (*TlsCallback)(Module->DllBase, dwReason, NULL);
149 TlsCallback++;
150 }
151 }
152 }
153 }
154
155 static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PVOID lpReserved)
156 {
157 if (!(Module->Flags & LDRP_IMAGE_DLL) ||
158 Module->EntryPoint == 0)
159 {
160 return TRUE;
161 }
162 LdrpTlsCallback(Module, dwReason);
163 return ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);
164 }
165
166 static PWSTR
167 LdrpQueryAppPaths(IN PCWSTR ImageName)
168 {
169 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
170 OBJECT_ATTRIBUTES ObjectAttributes;
171 WCHAR SearchPathBuffer[5*MAX_PATH];
172 UNICODE_STRING ValueNameString;
173 UNICODE_STRING KeyName;
174 WCHAR NameBuffer[MAX_PATH];
175 ULONG KeyInfoSize;
176 ULONG ResultSize;
177 PWCHAR Backslash;
178 HANDLE KeyHandle;
179 NTSTATUS Status;
180 PWSTR Path = NULL;
181
182 _snwprintf(NameBuffer,
183 sizeof(NameBuffer) / sizeof(WCHAR),
184 L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s",
185 ImageName);
186
187 RtlInitUnicodeString(&KeyName, NameBuffer);
188
189 InitializeObjectAttributes(&ObjectAttributes,
190 &KeyName,
191 OBJ_CASE_INSENSITIVE,
192 NULL,
193 NULL);
194
195 Status = NtOpenKey(&KeyHandle,
196 KEY_READ,
197 &ObjectAttributes);
198 if (!NT_SUCCESS(Status))
199 {
200 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
201 return NULL;
202 }
203
204 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR);
205
206 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize);
207 if (KeyInfo == NULL)
208 {
209 DPRINT("RtlAllocateHeap() failed\n");
210 NtClose(KeyHandle);
211 return NULL;
212 }
213
214 RtlInitUnicodeString(&ValueNameString,
215 L"Path");
216
217 Status = NtQueryValueKey(KeyHandle,
218 &ValueNameString,
219 KeyValuePartialInformation,
220 KeyInfo,
221 KeyInfoSize,
222 &ResultSize);
223
224 if (!NT_SUCCESS(Status))
225 {
226 NtClose(KeyHandle);
227 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
228 return NULL;
229 }
230
231 RtlCopyMemory(SearchPathBuffer,
232 &KeyInfo->Data,
233 KeyInfo->DataLength);
234
235 /* Free KeyInfo memory, we won't need it anymore */
236 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
237
238 /* Close the key handle */
239 NtClose(KeyHandle);
240
241 /* get application running path */
242 wcscat(SearchPathBuffer, L";");
243 wcscat(SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer); // FIXME: Don't rely on it being NULL-terminated!!!
244
245 /* Remove trailing backslash */
246 Backslash = wcsrchr(SearchPathBuffer, L'\\');
247 if (Backslash) Backslash = L'\0';
248
249 wcscat(SearchPathBuffer, L";");
250
251 wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
252 wcscat(SearchPathBuffer, L"\\system32;");
253 wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
254 wcscat(SearchPathBuffer, L";.");
255
256 /* Copy it to the heap allocd memory */
257 Path = RtlAllocateHeap(RtlGetProcessHeap(),
258 0,
259 wcslen(SearchPathBuffer) * sizeof(WCHAR));
260
261 if (!Path)
262 {
263 DPRINT1("RtlAllocateHeap() failed\n");
264 return NULL;
265 }
266
267 wcscpy(Path, SearchPathBuffer);
268
269 return Path;
270 }
271
272 static NTSTATUS
273 LdrpInitializeTlsForThread(VOID)
274 {
275 PVOID* TlsPointers;
276 PTLS_DATA TlsInfo;
277 PVOID TlsData;
278 ULONG i;
279 PTEB Teb = NtCurrentTeb();
280
281 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
282
283 Teb->StaticUnicodeString.Length = 0;
284 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
285 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
286
287 if (LdrpTlsCount > 0)
288 {
289 TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),
290 0,
291 LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);
292 if (TlsPointers == NULL)
293 {
294 DPRINT1("failed to allocate thread tls data\n");
295 return STATUS_NO_MEMORY;
296 }
297
298 TlsData = (PVOID)((ULONG_PTR)TlsPointers + LdrpTlsCount * sizeof(PVOID));
299 Teb->ThreadLocalStoragePointer = TlsPointers;
300
301 TlsInfo = LdrpTlsArray;
302 for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)
303 {
304 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo->Module->BaseDllName);
305 TlsPointers[i] = TlsData;
306 if (TlsInfo->TlsDataSize)
307 {
308 memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);
309 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsDataSize);
310 }
311 if (TlsInfo->TlsZeroSize)
312 {
313 memset(TlsData, 0, TlsInfo->TlsZeroSize);
314 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsZeroSize);
315 }
316 }
317 }
318
319 DPRINT("LdrpInitializeTlsForThread() done\n");
320 return STATUS_SUCCESS;
321 }
322
323 static NTSTATUS
324 LdrpInitializeTlsForProccess(VOID)
325 {
326 PLIST_ENTRY ModuleListHead;
327 PLIST_ENTRY Entry;
328 PLDR_DATA_TABLE_ENTRY Module;
329 PIMAGE_TLS_DIRECTORY TlsDirectory;
330 PTLS_DATA TlsData;
331 ULONG Size;
332
333 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule->BaseDllName);
334
335 if (LdrpTlsCount > 0)
336 {
337 LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
338 0,
339 LdrpTlsCount * sizeof(TLS_DATA));
340 if (LdrpTlsArray == NULL)
341 {
342 DPRINT1("Failed to allocate global tls data\n");
343 return STATUS_NO_MEMORY;
344 }
345
346 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
347 Entry = ModuleListHead->Flink;
348 while (Entry != ModuleListHead)
349 {
350 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
351 if (Module->LoadCount == LDRP_PROCESS_CREATION_TIME &&
352 Module->TlsIndex != 0xFFFF)
353 {
354 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
355 RtlImageDirectoryEntryToData(Module->DllBase,
356 TRUE,
357 IMAGE_DIRECTORY_ENTRY_TLS,
358 &Size);
359 ASSERT(Module->TlsIndex < LdrpTlsCount);
360 TlsData = &LdrpTlsArray[Module->TlsIndex];
361 TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;
362 TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
363 TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
364 if (TlsDirectory->AddressOfCallBacks)
365 TlsData->TlsAddressOfCallBacks = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;
366 else
367 TlsData->TlsAddressOfCallBacks = NULL;
368 TlsData->Module = Module;
369 #if 0
370 DbgPrint("TLS directory for %wZ\n", &Module->BaseDllName);
371 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory->StartAddressOfRawData);
372 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory->EndAddressOfRawData);
373 DbgPrint("SizeOfRawData: %d\n", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);
374 DbgPrint("AddressOfIndex: %x\n", TlsDirectory->AddressOfIndex);
375 DbgPrint("AddressOfCallBacks: %x\n", TlsDirectory->AddressOfCallBacks);
376 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory->SizeOfZeroFill);
377 DbgPrint("Characteristics: %x\n", TlsDirectory->Characteristics);
378 #endif
379 /*
380 * FIXME:
381 * Is this region allways writable ?
382 */
383 *(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;
384 }
385 Entry = Entry->Flink;
386 }
387 }
388
389 DPRINT("LdrpInitializeTlsForProccess() done\n");
390 return STATUS_SUCCESS;
391 }
392
393 VOID
394 LdrpInitLoader(VOID)
395 {
396 OBJECT_ATTRIBUTES ObjectAttributes;
397 UNICODE_STRING LinkTarget;
398 UNICODE_STRING Name;
399 HANDLE LinkHandle;
400 ULONG Length;
401 NTSTATUS Status;
402
403 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule->BaseDllName);
404
405 /* Get handle to the 'KnownDlls' directory */
406 RtlInitUnicodeString(&Name,
407 L"\\KnownDlls");
408 InitializeObjectAttributes(&ObjectAttributes,
409 &Name,
410 OBJ_CASE_INSENSITIVE,
411 NULL,
412 NULL);
413 Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
414 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
415 &ObjectAttributes);
416 if (!NT_SUCCESS(Status))
417 {
418 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
419 LdrpKnownDllsDirHandle = NULL;
420 return;
421 }
422
423 /* Allocate target name string */
424 LinkTarget.Length = 0;
425 LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
426 LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
427 0,
428 MAX_PATH * sizeof(WCHAR));
429 if (LinkTarget.Buffer == NULL)
430 {
431 NtClose(LdrpKnownDllsDirHandle);
432 LdrpKnownDllsDirHandle = NULL;
433 return;
434 }
435
436 RtlInitUnicodeString(&Name,
437 L"KnownDllPath");
438 InitializeObjectAttributes(&ObjectAttributes,
439 &Name,
440 OBJ_CASE_INSENSITIVE,
441 LdrpKnownDllsDirHandle,
442 NULL);
443 Status = NtOpenSymbolicLinkObject(&LinkHandle,
444 SYMBOLIC_LINK_ALL_ACCESS,
445 &ObjectAttributes);
446 if (!NT_SUCCESS(Status))
447 {
448 RtlFreeUnicodeString(&LinkTarget);
449 NtClose(LdrpKnownDllsDirHandle);
450 LdrpKnownDllsDirHandle = NULL;
451 return;
452 }
453
454 Status = NtQuerySymbolicLinkObject(LinkHandle,
455 &LinkTarget,
456 &Length);
457 NtClose(LinkHandle);
458 if (!NT_SUCCESS(Status))
459 {
460 RtlFreeUnicodeString(&LinkTarget);
461 NtClose(LdrpKnownDllsDirHandle);
462 LdrpKnownDllsDirHandle = NULL;
463 }
464
465 RtlCreateUnicodeString(&LdrpKnownDllPath,
466 LinkTarget.Buffer);
467
468 RtlFreeUnicodeString(&LinkTarget);
469
470 DPRINT("LdrpInitLoader() done\n");
471 }
472
473
474 /***************************************************************************
475 * NAME LOCAL
476 * LdrAdjustDllName
477 *
478 * DESCRIPTION
479 * Adjusts the name of a dll to a fully qualified name.
480 *
481 * ARGUMENTS
482 * FullDllName: Pointer to caller supplied storage for the fully
483 * qualified dll name.
484 * DllName: Pointer to the dll name.
485 * BaseName: TRUE: Only the file name is passed to FullDllName
486 * FALSE: The full path is preserved in FullDllName
487 *
488 * RETURN VALUE
489 * None
490 *
491 * REVISIONS
492 *
493 * NOTE
494 * A given path is not affected by the adjustment, but the file
495 * name only:
496 * ntdll --> ntdll.dll
497 * ntdll. --> ntdll
498 * ntdll.xyz --> ntdll.xyz
499 */
500 static VOID
501 LdrAdjustDllName (PUNICODE_STRING FullDllName,
502 PUNICODE_STRING DllName,
503 BOOLEAN BaseName)
504 {
505 WCHAR Buffer[MAX_PATH];
506 ULONG Length;
507 PWCHAR Extension;
508 PWCHAR Pointer;
509
510 Length = DllName->Length / sizeof(WCHAR);
511
512 if (BaseName)
513 {
514 /* get the base dll name */
515 Pointer = DllName->Buffer + Length;
516 Extension = Pointer;
517
518 do
519 {
520 --Pointer;
521 }
522 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
523
524 Pointer++;
525 Length = Extension - Pointer;
526 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
527 Buffer[Length] = L'\0';
528 }
529 else
530 {
531 /* get the full dll name */
532 memmove (Buffer, DllName->Buffer, DllName->Length);
533 Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
534 }
535
536 /* Build the DLL's absolute name */
537 Extension = wcsrchr (Buffer, L'.');
538 if ((Extension != NULL) && (*Extension == L'.'))
539 {
540 /* with extension - remove dot if it's the last character */
541 if (Buffer[Length - 1] == L'.')
542 Length--;
543 Buffer[Length] = 0;
544 }
545 else
546 {
547 /* name without extension - assume that it is .dll */
548 memmove (Buffer + Length, L".dll", 10);
549 }
550
551 RtlCreateUnicodeString(FullDllName, Buffer);
552 }
553
554 PLDR_DATA_TABLE_ENTRY
555 LdrAddModuleEntry(PVOID ImageBase,
556 PIMAGE_NT_HEADERS NTHeaders,
557 PWSTR FullDosName)
558 {
559 PLDR_DATA_TABLE_ENTRY Module;
560
561 Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY));
562 ASSERT(Module);
563 memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY));
564 Module->DllBase = (PVOID)ImageBase;
565 Module->EntryPoint = (PVOID)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 /* Unprotect the region we are about to write into. */
1604 IATBase = (PVOID)ImportAddressList;
1605 IATSize *= sizeof(PVOID*);
1606 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1607 &IATBase,
1608 &IATSize,
1609 PAGE_READWRITE,
1610 &OldProtect);
1611 if (!NT_SUCCESS(Status))
1612 {
1613 DPRINT1("Failed to unprotect IAT.\n");
1614 return(Status);
1615 }
1616
1617 /* Walk through function list and fixup addresses. */
1618 while (*FunctionNameList != 0L)
1619 {
1620 if ((*FunctionNameList) & 0x80000000)
1621 {
1622 Ordinal = (*FunctionNameList) & 0x7fffffff;
1623 *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
1624 if ((*ImportAddressList) == NULL)
1625 {
1626 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
1627 RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName);
1628 return STATUS_ENTRYPOINT_NOT_FOUND;
1629 }
1630 }
1631 else
1632 {
1633 IMAGE_IMPORT_BY_NAME *pe_name;
1634 pe_name = RVA(Module->DllBase, *FunctionNameList);
1635 *ImportAddressList = LdrGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
1636 if ((*ImportAddressList) == NULL)
1637 {
1638 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
1639 RtlpRaiseImportNotFound((CHAR*)pe_name->Name, 0, &ImportedModule->FullDllName);
1640 return STATUS_ENTRYPOINT_NOT_FOUND;
1641 }
1642 }
1643 ImportAddressList++;
1644 FunctionNameList++;
1645 }
1646
1647 /* Protect the region we are about to write into. */
1648 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1649 &IATBase,
1650 &IATSize,
1651 OldProtect,
1652 &OldProtect);
1653 if (!NT_SUCCESS(Status))
1654 {
1655 DPRINT1("Failed to protect IAT.\n");
1656 return(Status);
1657 }
1658
1659 return STATUS_SUCCESS;
1660 }
1661
1662 static NTSTATUS
1663 LdrpProcessImportDirectory(
1664 PLDR_DATA_TABLE_ENTRY Module,
1665 PLDR_DATA_TABLE_ENTRY ImportedModule,
1666 PCHAR ImportedName)
1667 {
1668 NTSTATUS Status;
1669 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1670 PCHAR Name;
1671 ULONG Size;
1672
1673 DPRINT("LdrpProcessImportDirectory(%p '%wZ', '%s')\n",
1674 Module, &Module->BaseDllName, ImportedName);
1675
1676
1677 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1678 RtlImageDirectoryEntryToData(Module->DllBase,
1679 TRUE,
1680 IMAGE_DIRECTORY_ENTRY_IMPORT,
1681 &Size);
1682 if (ImportModuleDirectory == NULL)
1683 {
1684 return STATUS_UNSUCCESSFUL;
1685 }
1686
1687 while (ImportModuleDirectory->Name)
1688 {
1689 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1690 if (0 == _stricmp(Name, ImportedName))
1691 {
1692 Status = LdrpProcessImportDirectoryEntry(Module,
1693 ImportedModule,
1694 ImportModuleDirectory);
1695 if (!NT_SUCCESS(Status))
1696 {
1697 return Status;
1698 }
1699 }
1700 ImportModuleDirectory++;
1701 }
1702
1703
1704 return STATUS_SUCCESS;
1705 }
1706
1707
1708 static NTSTATUS
1709 LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
1710 PLDR_DATA_TABLE_ENTRY ImportedModule,
1711 PCHAR ImportedName)
1712 {
1713 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1714 NTSTATUS Status;
1715 PVOID* ImportAddressList;
1716 PVOID Start;
1717 PVOID End;
1718 PULONG FunctionNameList;
1719 PVOID IATBase;
1720 ULONG OldProtect;
1721 ULONG Offset;
1722 ULONG IATSize;
1723 PIMAGE_NT_HEADERS NTHeaders;
1724 PCHAR Name;
1725 ULONG Size;
1726
1727 DPRINT("LdrpAdjustImportDirectory(Module %p '%wZ', %p '%wZ', '%s')\n",
1728 Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
1729
1730 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1731 RtlImageDirectoryEntryToData(Module->DllBase,
1732 TRUE,
1733 IMAGE_DIRECTORY_ENTRY_IMPORT,
1734 &Size);
1735 if (ImportModuleDirectory == NULL)
1736 {
1737 return STATUS_UNSUCCESSFUL;
1738 }
1739
1740 while (ImportModuleDirectory->Name)
1741 {
1742 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1743 if (0 == _stricmp(Name, (PCHAR)ImportedName))
1744 {
1745
1746 /* Get the import address list. */
1747 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1748
1749 /* Get the list of functions to import. */
1750 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1751 {
1752 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1753 }
1754 else
1755 {
1756 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1757 }
1758
1759 /* Get the size of IAT. */
1760 IATSize = 0;
1761 while (FunctionNameList[IATSize] != 0L)
1762 {
1763 IATSize++;
1764 }
1765
1766 /* Unprotect the region we are about to write into. */
1767 IATBase = (PVOID)ImportAddressList;
1768 IATSize *= sizeof(PVOID*);
1769 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1770 &IATBase,
1771 &IATSize,
1772 PAGE_READWRITE,
1773 &OldProtect);
1774 if (!NT_SUCCESS(Status))
1775 {
1776 DPRINT1("Failed to unprotect IAT.\n");
1777 return(Status);
1778 }
1779
1780 NTHeaders = RtlImageNtHeader (ImportedModule->DllBase);
1781 Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
1782 End = (PVOID)((ULONG_PTR)Start + ImportedModule->SizeOfImage);
1783 Offset = (ULONG)((ULONG_PTR)ImportedModule->DllBase - (ULONG_PTR)Start);
1784
1785 /* Walk through function list and fixup addresses. */
1786 while (*FunctionNameList != 0L)
1787 {
1788 if (*ImportAddressList >= Start && *ImportAddressList < End)
1789 {
1790 (*ImportAddressList) = (PVOID)((ULONG_PTR)(*ImportAddressList) + Offset);
1791 }
1792 ImportAddressList++;
1793 FunctionNameList++;
1794 }
1795
1796 /* Protect the region we are about to write into. */
1797 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1798 &IATBase,
1799 &IATSize,
1800 OldProtect,
1801 &OldProtect);
1802 if (!NT_SUCCESS(Status))
1803 {
1804 DPRINT1("Failed to protect IAT.\n");
1805 return(Status);
1806 }
1807 }
1808 ImportModuleDirectory++;
1809 }
1810 return STATUS_SUCCESS;
1811 }
1812
1813
1814 /**********************************************************************
1815 * NAME LOCAL
1816 * LdrFixupImports
1817 *
1818 * DESCRIPTION
1819 * Compute the entry point for every symbol the DLL imports
1820 * from other modules.
1821 *
1822 * ARGUMENTS
1823 *
1824 * RETURN VALUE
1825 *
1826 * REVISIONS
1827 *
1828 * NOTE
1829 *
1830 */
1831 static NTSTATUS
1832 LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
1833 IN PLDR_DATA_TABLE_ENTRY Module)
1834 {
1835 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1836 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent;
1837 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
1838 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
1839 PIMAGE_TLS_DIRECTORY TlsDirectory;
1840 ULONG TlsSize = 0;
1841 NTSTATUS Status = STATUS_SUCCESS;
1842 PLDR_DATA_TABLE_ENTRY ImportedModule;
1843 PCHAR ImportedName;
1844 PWSTR ModulePath;
1845 ULONG Size;
1846 ULONG_PTR cookie;
1847
1848 DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
1849
1850 /* Check for tls data */
1851 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
1852 RtlImageDirectoryEntryToData(Module->DllBase,
1853 TRUE,
1854 IMAGE_DIRECTORY_ENTRY_TLS,
1855 &Size);
1856 if (TlsDirectory)
1857 {
1858 TlsSize = TlsDirectory->EndAddressOfRawData
1859 - TlsDirectory->StartAddressOfRawData
1860 + TlsDirectory->SizeOfZeroFill;
1861
1862 if (TlsSize > 0 && NtCurrentPeb()->Ldr->Initialized)
1863 {
1864 TRACE_LDR("Trying to dynamically load %wZ which contains a TLS directory\n",
1865 &Module->BaseDllName);
1866 TlsDirectory = NULL;
1867 }
1868 }
1869
1870 if (!create_module_activation_context( Module ))
1871 {
1872 if (Module->EntryPointActivationContext == NULL)
1873 {
1874 DPRINT("EntryPointActivationContext has not be allocated\n");
1875 DPRINT("Module->DllBaseName %wZ\n", Module->BaseDllName);
1876 }
1877 RtlActivateActivationContext( 0, Module->EntryPointActivationContext, &cookie );
1878 }
1879
1880 /*
1881 * Process each import module.
1882 */
1883 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1884 RtlImageDirectoryEntryToData(Module->DllBase,
1885 TRUE,
1886 IMAGE_DIRECTORY_ENTRY_IMPORT,
1887 &Size);
1888
1889 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
1890 RtlImageDirectoryEntryToData(Module->DllBase,
1891 TRUE,
1892 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
1893 &Size);
1894
1895 if (BoundImportDescriptor != NULL && ImportModuleDirectory == NULL)
1896 {
1897 DPRINT1("%wZ has only a bound import directory\n", &Module->BaseDllName);
1898 return STATUS_UNSUCCESSFUL;
1899 }
1900 if (BoundImportDescriptor)
1901 {
1902 DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor);
1903
1904 BoundImportDescriptorCurrent = BoundImportDescriptor;
1905 while (BoundImportDescriptorCurrent->OffsetModuleName)
1906 {
1907 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
1908 TRACE_LDR("%wZ bound to %s\n", &Module->BaseDllName, ImportedName);
1909 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
1910 if (!NT_SUCCESS(Status))
1911 {
1912 DPRINT1("failed to load %s\n", ImportedName);
1913 return Status;
1914 }
1915 if (Module == ImportedModule)
1916 {
1917 LdrpDecrementLoadCount(Module, FALSE);
1918 }
1919 if (ImportedModule->TimeDateStamp != BoundImportDescriptorCurrent->TimeDateStamp)
1920 {
1921 TRACE_LDR("%wZ has stale binding to %wZ\n",
1922 &Module->BaseDllName, &ImportedModule->BaseDllName);
1923 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1924 if (!NT_SUCCESS(Status))
1925 {
1926 DPRINT1("failed to import %s\n", ImportedName);
1927 return Status;
1928 }
1929 }
1930 else
1931 {
1932 BOOLEAN WrongForwarder;
1933 WrongForwarder = FALSE;
1934 if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1935 {
1936 TRACE_LDR("%wZ has stale binding to %s\n",
1937 &Module->BaseDllName, ImportedName);
1938 }
1939 else
1940 {
1941 TRACE_LDR("%wZ has correct binding to %wZ\n",
1942 &Module->BaseDllName, &ImportedModule->BaseDllName);
1943 }
1944 if (BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs)
1945 {
1946 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef;
1947 ULONG i;
1948 PLDR_DATA_TABLE_ENTRY ForwarderModule;
1949 PCHAR ForwarderName;
1950
1951 BoundForwarderRef = (PIMAGE_BOUND_FORWARDER_REF)(BoundImportDescriptorCurrent + 1);
1952 for (i = 0; i < BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs; i++, BoundForwarderRef++)
1953 {
1954 ForwarderName = (PCHAR)BoundImportDescriptor + BoundForwarderRef->OffsetModuleName;
1955 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1956 &Module->BaseDllName, ForwarderName, ImportedName);
1957 Status = LdrpGetOrLoadModule(SearchPath, ForwarderName, &ForwarderModule, TRUE);
1958 if (!NT_SUCCESS(Status))
1959 {
1960 DPRINT1("failed to load %s\n", ForwarderName);
1961 return Status;
1962 }
1963 if (Module == ImportedModule)
1964 {
1965 LdrpDecrementLoadCount(Module, FALSE);
1966 }
1967 if (ForwarderModule->TimeDateStamp != BoundForwarderRef->TimeDateStamp ||
1968 ForwarderModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1969 {
1970 TRACE_LDR("%wZ has stale binding to %s\n",
1971 &Module->BaseDllName, ForwarderName);
1972 WrongForwarder = TRUE;
1973 }
1974 else
1975 {
1976 TRACE_LDR("%wZ has correct binding to %s\n",
1977 &Module->BaseDllName, ForwarderName);
1978 }
1979 }
1980 }
1981 if (WrongForwarder ||
1982 ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1983 {
1984 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1985 if (!NT_SUCCESS(Status))
1986 {
1987 DPRINT1("failed to import %s\n", ImportedName);
1988 return Status;
1989 }
1990 }
1991 else if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1992 {
1993 TRACE_LDR("Adjust imports for %s from %wZ\n",
1994 ImportedName, &Module->BaseDllName);
1995 Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName);
1996 if (!NT_SUCCESS(Status))
1997 {
1998 DPRINT1("failed to adjust import entries for %s\n", ImportedName);
1999 return Status;
2000 }
2001 }
2002 else if (WrongForwarder)
2003 {
2004 /*
2005 * FIXME:
2006 * Update only forwarders
2007 */
2008 TRACE_LDR("Stale BIND %s from %wZ\n",
2009 ImportedName, &Module->BaseDllName);
2010 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
2011 if (!NT_SUCCESS(Status))
2012 {
2013 DPRINT1("faild to import %s\n", ImportedName);
2014 return Status;
2015 }
2016 }
2017 else
2018 {
2019 /* nothing to do */
2020 }
2021 }
2022 BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1;
2023 }
2024 }
2025 else if (ImportModuleDirectory)
2026 {
2027 DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory);
2028
2029 ImportModuleDirectoryCurrent = ImportModuleDirectory;
2030 while (ImportModuleDirectoryCurrent->Name)
2031 {
2032 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2033 TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName);
2034
2035 if (SearchPath == NULL)
2036 {
2037 ModulePath = LdrpQueryAppPaths(Module->BaseDllName.Buffer);
2038
2039 Status = LdrpGetOrLoadModule(ModulePath, ImportedName, &ImportedModule, TRUE);
2040 if (ModulePath != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, ModulePath);
2041 if (NT_SUCCESS(Status)) goto Success;
2042 }
2043
2044 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
2045 if (!NT_SUCCESS(Status))
2046 {
2047 DPRINT1("failed to load %s\n", ImportedName);
2048 break;
2049 }
2050 Success:
2051 if (Module == ImportedModule)
2052 {
2053 LdrpDecrementLoadCount(Module, FALSE);
2054 }
2055
2056 TRACE_LDR("Initializing imports for %wZ from %s\n",
2057 &Module->BaseDllName, ImportedName);
2058 Status = LdrpProcessImportDirectoryEntry(Module, ImportedModule, ImportModuleDirectoryCurrent);
2059 if (!NT_SUCCESS(Status))
2060 {
2061 DPRINT1("failed to import %s\n", ImportedName);
2062 break;
2063 }
2064 ImportModuleDirectoryCurrent++;
2065 }
2066 if(!NT_SUCCESS(Status))
2067 {
2068 NTSTATUS errorStatus = Status;
2069
2070 while(ImportModuleDirectoryCurrent-- >= ImportModuleDirectory)
2071 {
2072 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
2073
2074 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2075 if(NT_SUCCESS(Status) && Module != ImportedModule)
2076 {
2077 Status = LdrpUnloadModule(ImportedModule, FALSE);
2078 if (!NT_SUCCESS(Status)) DPRINT1("unable to unload %s\n", ImportedName);
2079 }
2080 }
2081 return errorStatus;
2082 }
2083
2084 }
2085
2086 if (TlsDirectory && TlsSize > 0)
2087 {
2088 LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
2089 }
2090
2091 if (Module->EntryPointActivationContext) RtlDeactivateActivationContext( 0, cookie );
2092
2093 return STATUS_SUCCESS;
2094 }
2095
2096
2097 /**********************************************************************
2098 * NAME
2099 * LdrPEStartup
2100 *
2101 * DESCRIPTION
2102 * 1. Relocate, if needed the EXE.
2103 * 2. Fixup any imported symbol.
2104 * 3. Compute the EXE's entry point.
2105 *
2106 * ARGUMENTS
2107 * ImageBase
2108 * Address at which the EXE's image
2109 * is loaded.
2110 *
2111 * SectionHandle
2112 * Handle of the section that contains
2113 * the EXE's image.
2114 *
2115 * RETURN VALUE
2116 * NULL on error; otherwise the entry point
2117 * to call for initializing the DLL.
2118 *
2119 * REVISIONS
2120 *
2121 * NOTE
2122 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
2123 * Currently the function is only used for the exe.
2124 */
2125 PEPFUNC LdrPEStartup (PVOID ImageBase,
2126 HANDLE SectionHandle,
2127 PLDR_DATA_TABLE_ENTRY* Module,
2128 PWSTR FullDosName)
2129 {
2130 NTSTATUS Status;
2131 PEPFUNC EntryPoint = NULL;
2132 PIMAGE_DOS_HEADER DosHeader;
2133 PIMAGE_NT_HEADERS NTHeaders;
2134 PLDR_DATA_TABLE_ENTRY tmpModule;
2135 PVOID ActivationContextStack;
2136
2137 DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
2138 ImageBase, SectionHandle);
2139
2140 /*
2141 * Overlay DOS and WNT headers structures
2142 * to the DLL's image.
2143 */
2144 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
2145 NTHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR)ImageBase + DosHeader->e_lfanew);
2146
2147 /*
2148 * If the base address is different from the
2149 * one the DLL is actually loaded, perform any
2150 * relocation.
2151 */
2152 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2153 {
2154 DPRINT("LDR: Performing relocations\n");
2155 Status = LdrPerformRelocations(NTHeaders, ImageBase);
2156 if (!NT_SUCCESS(Status))
2157 {
2158 DPRINT1("LdrPerformRelocations() failed\n");
2159 return NULL;
2160 }
2161 }
2162
2163 if (Module != NULL)
2164 {
2165 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
2166 (*Module)->SectionPointer = SectionHandle;
2167 }
2168 else
2169 {
2170 Module = &tmpModule;
2171 Status = LdrFindEntryForAddress(ImageBase, Module);
2172 if (!NT_SUCCESS(Status))
2173 {
2174 return NULL;
2175 }
2176 }
2177
2178 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
2179 {
2180 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2181 }
2182
2183 /* Allocate memory for the ActivationContextStack */
2184 /* FIXME: Verify RtlAllocateActivationContextStack behavior */
2185 Status = RtlAllocateActivationContextStack(&ActivationContextStack);
2186 if (NT_SUCCESS(Status))
2187 {
2188 DPRINT("ActivationContextStack %x\n",ActivationContextStack);
2189 DPRINT("ActiveFrame %x\n", ((PACTIVATION_CONTEXT_STACK)ActivationContextStack)->ActiveFrame);
2190 NtCurrentTeb()->ActivationContextStackPointer = ActivationContextStack;
2191 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL;
2192 }
2193 else
2194 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
2195
2196 /*
2197 * If the DLL's imports symbols from other
2198 * modules, fixup the imported calls entry points.
2199 */
2200 DPRINT("About to fixup imports\n");
2201 Status = LdrFixupImports(NULL, *Module);
2202 if (!NT_SUCCESS(Status))
2203 {
2204 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName);
2205 return NULL;
2206 }
2207 DPRINT("Fixup done\n");
2208 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2209 Status = LdrpInitializeTlsForProccess();
2210 if (NT_SUCCESS(Status))
2211 {
2212 Status = LdrpAttachProcess();
2213 }
2214 if (NT_SUCCESS(Status))
2215 {
2216 LdrpTlsCallback(*Module, DLL_PROCESS_ATTACH);
2217 }
2218
2219
2220 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
2221 if (!NT_SUCCESS(Status))
2222 {
2223 return NULL;
2224 }
2225
2226 /*
2227 * Compute the DLL's entry point's address.
2228 */
2229 DPRINT("ImageBase = %p\n", ImageBase);
2230 DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
2231 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
2232 {
2233 EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase
2234 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
2235 }
2236 DPRINT("LdrPEStartup() = %p\n",EntryPoint);
2237 return EntryPoint;
2238 }
2239
2240 static NTSTATUS
2241 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
2242 IN ULONG LoadFlags,
2243 IN PUNICODE_STRING Name,
2244 PLDR_DATA_TABLE_ENTRY *Module,
2245 PVOID *BaseAddress OPTIONAL)
2246 {
2247 UNICODE_STRING AdjustedName;
2248 UNICODE_STRING FullDosName;
2249 NTSTATUS Status;
2250 PLDR_DATA_TABLE_ENTRY tmpModule;
2251 HANDLE SectionHandle;
2252 SIZE_T ViewSize;
2253 PVOID ImageBase;
2254 PIMAGE_NT_HEADERS NtHeaders;
2255 BOOLEAN MappedAsDataFile;
2256 PVOID ArbitraryUserPointer;
2257
2258 if (Module == NULL)
2259 {
2260 Module = &tmpModule;
2261 }
2262 /* adjust the full dll name */
2263 LdrAdjustDllName(&AdjustedName, Name, FALSE);
2264
2265 DPRINT("%wZ\n", &AdjustedName);
2266
2267 MappedAsDataFile = FALSE;
2268 /* Test if dll is already loaded */
2269 Status = LdrFindEntryForName(&AdjustedName, Module, TRUE);
2270 if (NT_SUCCESS(Status))
2271 {
2272 RtlFreeUnicodeString(&AdjustedName);
2273 if (NULL != BaseAddress)
2274 {
2275 *BaseAddress = (*Module)->DllBase;
2276 }
2277 }
2278 else
2279 {
2280 /* Open or create dll image section */
2281 Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle);
2282 if (!NT_SUCCESS(Status))
2283 {
2284 MappedAsDataFile = (0 != (LoadFlags & LOAD_LIBRARY_AS_DATAFILE));
2285 Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName,
2286 MappedAsDataFile, &SectionHandle);
2287 }
2288 if (!NT_SUCCESS(Status))
2289 {
2290 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName, Status);
2291 RtlFreeUnicodeString(&AdjustedName);
2292 return Status;
2293 }
2294 RtlFreeUnicodeString(&AdjustedName);
2295 /* Map the dll into the process */
2296 ViewSize = 0;
2297 ImageBase = 0;
2298 ArbitraryUserPointer = NtCurrentTeb()->Tib.ArbitraryUserPointer;
2299 NtCurrentTeb()->Tib.ArbitraryUserPointer = FullDosName.Buffer;
2300 Status = NtMapViewOfSection(SectionHandle,
2301 NtCurrentProcess(),
2302 &ImageBase,
2303 0,
2304 0,
2305 NULL,
2306 &ViewSize,
2307 ViewShare,
2308 0,
2309 PAGE_READONLY);
2310 NtCurrentTeb()->Tib.ArbitraryUserPointer = ArbitraryUserPointer;
2311 if (!NT_SUCCESS(Status))
2312 {
2313 DPRINT1("map view of section failed (Status 0x%08lx)\n", Status);
2314 RtlFreeUnicodeString(&FullDosName);
2315 NtClose(SectionHandle);
2316 return(Status);
2317 }
2318 if (NULL != BaseAddress)
2319 {
2320 *BaseAddress = ImageBase;
2321 }
2322 if (!MappedAsDataFile)
2323 {
2324 /* Get and check the NT headers */
2325 NtHeaders = RtlImageNtHeader(ImageBase);
2326 if (NtHeaders == NULL)
2327 {
2328 DPRINT1("RtlImageNtHeaders() failed\n");
2329 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2330 NtClose (SectionHandle);
2331 RtlFreeUnicodeString(&FullDosName);
2332 return STATUS_UNSUCCESSFUL;
2333 }
2334 }
2335 DPRINT("Mapped %wZ at %x\n", &FullDosName, ImageBase);
2336 if (MappedAsDataFile)
2337 {
2338 ASSERT(NULL != BaseAddress);
2339 if (NULL != BaseAddress)
2340 {
2341 *BaseAddress = (PVOID) ((char *) *BaseAddress + 1);
2342 }
2343 *Module = NULL;
2344 RtlFreeUnicodeString(&FullDosName);
2345 NtClose(SectionHandle);
2346 return STATUS_SUCCESS;
2347 }
2348 /* If the base address is different from the
2349 * one the DLL is actually loaded, perform any
2350 * relocation. */
2351 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2352 {
2353 DPRINT1("Relocating (%lx -> %p) %wZ\n",
2354 NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
2355 Status = LdrPerformRelocations(NtHeaders, ImageBase);
2356 if (!NT_SUCCESS(Status))
2357 {
2358 DPRINT1("LdrPerformRelocations() failed\n");
2359 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2360 NtClose (SectionHandle);
2361 RtlFreeUnicodeString(&FullDosName);
2362 return STATUS_UNSUCCESSFUL;
2363 }
2364 }
2365 *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer);
2366 (*Module)->SectionPointer = SectionHandle;
2367 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2368 {
2369 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2370 }
2371 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
2372 {
2373 (*Module)->Flags |= LDRP_IMAGE_DLL;
2374 }
2375 /* fixup the imported calls entry points */
2376 Status = LdrFixupImports(SearchPath, *Module);
2377 if (!NT_SUCCESS(Status))
2378 {
2379 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
2380 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2381 NtClose (SectionHandle);
2382 RtlFreeUnicodeString (&FullDosName);
2383 RtlFreeUnicodeString (&(*Module)->FullDllName);
2384 RtlFreeUnicodeString (&(*Module)->BaseDllName);
2385 RemoveEntryList (&(*Module)->InLoadOrderLinks);
2386 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2387 return Status;
2388 }
2389
2390 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2391 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
2392 &(*Module)->InInitializationOrderModuleList);
2393 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2394 }
2395 return STATUS_SUCCESS;
2396 }
2397
2398 static NTSTATUS
2399 LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
2400 BOOLEAN Unload)
2401 {
2402 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
2403 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
2404 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
2405 PCHAR ImportedName;
2406 PLDR_DATA_TABLE_ENTRY ImportedModule;
2407 NTSTATUS Status = 0;
2408 LONG LoadCount;
2409 ULONG Size;
2410
2411 if (Unload)
2412 {
2413 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2414 }
2415
2416 LoadCount = LdrpDecrementLoadCount(Module, Unload);
2417
2418 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
2419
2420 if (LoadCount == 0)
2421 {
2422 /* ?????????????????? */
2423 }
2424 else if (!(Module->Flags & LDRP_STATIC_LINK) && LoadCount == 1)
2425 {
2426 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
2427 RtlImageDirectoryEntryToData(Module->DllBase,
2428 TRUE,
2429 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
2430 &Size);
2431 if (BoundImportDescriptor)
2432 {
2433 /* dereferencing all imported modules, use the bound import descriptor */
2434 BoundImportDescriptorCurrent = BoundImportDescriptor;
2435 while (BoundImportDescriptorCurrent->OffsetModuleName)
2436 {
2437 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
2438 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2439 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2440 if (!NT_SUCCESS(Status))
2441 {
2442 DPRINT1("unable to found imported modul %s\n", ImportedName);
2443 }
2444 else
2445 {
2446 if (Module != ImportedModule)
2447 {
2448 Status = LdrpUnloadModule(ImportedModule, FALSE);
2449 if (!NT_SUCCESS(Status))
2450 {
2451 DPRINT1("unable to unload %s\n", ImportedName);
2452 }
2453 }
2454 }
2455 BoundImportDescriptorCurrent++;
2456 }
2457 }
2458 else
2459 {
2460 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
2461 RtlImageDirectoryEntryToData(Module->DllBase,
2462 TRUE,
2463 IMAGE_DIRECTORY_ENTRY_IMPORT,
2464 &Size);
2465 if (ImportModuleDirectory)
2466 {
2467 /* dereferencing all imported modules, use the import descriptor */
2468 while (ImportModuleDirectory->Name)
2469 {
2470 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
2471 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2472 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2473 if (!NT_SUCCESS(Status))
2474 {
2475 DPRINT1("unable to found imported modul %s\n", ImportedName);
2476 }
2477 else
2478 {
2479 if (Module != ImportedModule)
2480 {
2481 Status = LdrpUnloadModule(ImportedModule, FALSE);
2482 if (!NT_SUCCESS(Status))
2483 {
2484 DPRINT1("unable to unload %s\n", ImportedName);
2485 }
2486 }
2487 }
2488 ImportModuleDirectory++;
2489 }
2490 }
2491 }
2492 }
2493
2494 if (Unload)
2495 {
2496 if (!(Module->Flags & LDRP_STATIC_LINK))
2497 {
2498 LdrpDetachProcess(FALSE);
2499 }
2500
2501 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2502 }
2503 return STATUS_SUCCESS;
2504
2505 }
2506
2507 /*
2508 * @implemented
2509 */
2510 NTSTATUS NTAPI
2511 LdrUnloadDll (IN PVOID BaseAddress)
2512 {
2513 PLDR_DATA_TABLE_ENTRY Module;
2514 NTSTATUS Status;
2515
2516 if (BaseAddress == NULL)
2517 return STATUS_SUCCESS;
2518
2519 if (LdrMappedAsDataFile(&BaseAddress))
2520 {
2521 Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
2522 }
2523 else
2524 {
2525 Status = LdrFindEntryForAddress(BaseAddress, &Module);
2526 if (NT_SUCCESS(Status))
2527 {
2528 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
2529 Status = LdrpUnloadModule(Module, TRUE);
2530 }
2531 }
2532
2533 return Status;
2534 }
2535
2536 /*
2537 * @implemented
2538 */
2539 NTSTATUS NTAPI
2540 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
2541 {
2542 PLIST_ENTRY ModuleListHead;
2543 PLIST_ENTRY Entry;
2544 PLDR_DATA_TABLE_ENTRY Module;
2545 NTSTATUS Status;
2546
2547 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
2548
2549 Status = STATUS_DLL_NOT_FOUND;
2550 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2551 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2552 Entry = ModuleListHead->Flink;
2553 while (Entry != ModuleListHead)
2554 {
2555 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2556
2557 DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module->BaseDllName, Module->DllBase);
2558
2559 if (Module->DllBase == BaseAddress)
2560 {
2561 if (Module->TlsIndex == 0xFFFF)
2562 {
2563 Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
2564 Status = STATUS_SUCCESS;
2565 }
2566 break;
2567 }
2568 Entry = Entry->Flink;
2569 }
2570 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2571 return Status;
2572 }
2573
2574 /*
2575 * @implemented
2576 */
2577 NTSTATUS NTAPI
2578 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
2579 IN PULONG DllCharacteristics,
2580 IN PUNICODE_STRING DllName,
2581 OUT PVOID *DllHandle)
2582 {
2583 PLDR_DATA_TABLE_ENTRY Module;
2584 NTSTATUS Status;
2585
2586 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
2587 DllName, DllPath ? DllPath : L"");
2588
2589 /* NULL is the current executable */
2590 if (DllName == NULL)
2591 {
2592 *DllHandle = ExeModule->DllBase;
2593 DPRINT("BaseAddress 0x%lx\n", *DllHandle);
2594 return STATUS_SUCCESS;
2595 }
2596
2597 Status = LdrFindEntryForName(DllName, &Module, FALSE);
2598 if (NT_SUCCESS(Status))
2599 {
2600 *DllHandle = Module->DllBase;
2601 return STATUS_SUCCESS;
2602 }
2603
2604 DPRINT("Failed to find dll %wZ\n", DllName);
2605 *DllHandle = NULL;
2606 return STATUS_DLL_NOT_FOUND;
2607 }
2608
2609 /*
2610 * @implemented
2611 */
2612 NTSTATUS NTAPI
2613 LdrAddRefDll(IN ULONG Flags,
2614 IN PVOID BaseAddress)
2615 {
2616 PLIST_ENTRY ModuleListHead;
2617 PLIST_ENTRY Entry;
2618 PLDR_DATA_TABLE_ENTRY Module;
2619 NTSTATUS Status;
2620
2621 if (Flags & ~(LDR_PIN_MODULE))
2622 {
2623 return STATUS_INVALID_PARAMETER;
2624 }
2625
2626 Status = STATUS_DLL_NOT_FOUND;
2627 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2628 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2629 Entry = ModuleListHead->Flink;
2630 while (Entry != ModuleListHead)
2631 {
2632 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2633
2634 if (Module->DllBase == BaseAddress)
2635 {
2636 if (Flags & LDR_PIN_MODULE)
2637 {
2638 Module->Flags |= LDRP_STATIC_LINK;
2639 }
2640 else
2641 {
2642 LdrpIncrementLoadCount(Module,
2643 FALSE);
2644 }
2645 Status = STATUS_SUCCESS;
2646 break;
2647 }
2648 Entry = Entry->Flink;
2649 }
2650 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2651 return Status;
2652 }
2653
2654 /*
2655 * @implemented
2656 */
2657 PVOID NTAPI
2658 RtlPcToFileHeader(IN PVOID PcValue,
2659 PVOID* BaseOfImage)
2660 {
2661 PLIST_ENTRY ModuleListHead;
2662 PLIST_ENTRY Entry;
2663 PLDR_DATA_TABLE_ENTRY Module;
2664 PVOID ImageBase = NULL;
2665
2666 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2667 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2668 Entry = ModuleListHead->Flink;
2669 while (Entry != ModuleListHead)
2670 {
2671 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2672
2673 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
2674 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
2675 {
2676 ImageBase = Module->DllBase;
2677 break;
2678 }
2679 Entry = Entry->Flink;
2680 }
2681 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2682
2683 *BaseOfImage = ImageBase;
2684 return ImageBase;
2685 }
2686
2687 /*
2688 * @implemented
2689 */
2690 NTSTATUS NTAPI
2691 LdrGetProcedureAddress (IN PVOID BaseAddress,
2692 IN PANSI_STRING Name,
2693 IN ULONG Ordinal,
2694 OUT PVOID *ProcedureAddress)
2695 {
2696 NTSTATUS Status = STATUS_PROCEDURE_NOT_FOUND;
2697 if (Name && Name->Length)
2698 {
2699 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
2700 }
2701 else
2702 {
2703 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
2704 }
2705
2706 DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
2707 BaseAddress, Name, Ordinal, ProcedureAddress);
2708
2709 _SEH2_TRY
2710 {
2711 if (Name && Name->Length)
2712 {
2713 /* by name */
2714 *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
2715 if (*ProcedureAddress != NULL)
2716 {
2717 Status = STATUS_SUCCESS;
2718 }
2719 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
2720 }
2721 else
2722 {
2723 /* by ordinal */
2724 Ordinal &= 0x0000FFFF;
2725 *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
2726 if (*ProcedureAddress)
2727 {
2728 Status = STATUS_SUCCESS;
2729 }
2730 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal);
2731 }
2732 }
2733 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2734 {
2735 Status = STATUS_DLL_NOT_FOUND;
2736 }
2737 _SEH2_END;
2738
2739 return Status;
2740 }
2741
2742 /**********************************************************************
2743 * NAME LOCAL
2744 * LdrpDetachProcess
2745 *
2746 * DESCRIPTION
2747 * Unload dll's which are no longer referenced from others dll's
2748 *
2749 * ARGUMENTS
2750 * none
2751 *
2752 * RETURN VALUE
2753 * none
2754 *
2755 * REVISIONS
2756 *
2757 * NOTE
2758 * The loader lock must be held on enty.
2759 */
2760 static VOID
2761 LdrpDetachProcess(BOOLEAN UnloadAll)
2762 {
2763 PLIST_ENTRY ModuleListHead;
2764 PLIST_ENTRY Entry;
2765 PLDR_DATA_TABLE_ENTRY Module;
2766 static ULONG CallingCount = 0;
2767
2768 DPRINT("LdrpDetachProcess() called for %wZ\n",
2769 &ExeModule->BaseDllName);
2770
2771 if (UnloadAll)
2772 LdrpDllShutdownInProgress = TRUE;
2773
2774 CallingCount++;
2775
2776 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2777 Entry = ModuleListHead->Blink;
2778 while (Entry != ModuleListHead)
2779 {
2780 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2781 if (((UnloadAll && Module->LoadCount == LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0) &&
2782 Module->Flags & LDRP_ENTRY_PROCESSED &&
2783 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2784 {
2785 Module->Flags |= LDRP_UNLOAD_IN_PROGRESS;
2786 if (Module == LdrpLastModule)
2787 {
2788 LdrpLastModule = NULL;
2789 }
2790 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED)
2791 {
2792 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2793 &Module->BaseDllName, Module->EntryPoint);
2794 LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2795 }
2796 else
2797 {
2798 TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
2799 }
2800 Entry = ModuleListHead->Blink;
2801 }
2802 else
2803 {
2804 Entry = Entry->Blink;
2805 }
2806 }
2807
2808 if (CallingCount == 1)
2809 {
2810 Entry = ModuleListHead->Blink;
2811 while (Entry != ModuleListHead)
2812 {
2813 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2814 Entry = Entry->Blink;
2815 if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
2816 ((UnloadAll && Module->LoadCount != LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0))
2817 {
2818 /* remove the module entry from the list */
2819 RemoveEntryList (&Module->InLoadOrderLinks);
2820 RemoveEntryList (&Module->InInitializationOrderModuleList);
2821
2822 NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase);
2823 NtClose (Module->SectionPointer);
2824
2825 TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
2826
2827 RtlFreeUnicodeString (&Module->FullDllName);
2828 RtlFreeUnicodeString (&Module->BaseDllName);
2829
2830 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2831 }
2832 }
2833 }
2834 CallingCount--;
2835 DPRINT("LdrpDetachProcess() done\n");
2836 }
2837
2838 /**********************************************************************
2839 * NAME LOCAL
2840 * LdrpAttachProcess
2841 *
2842 * DESCRIPTION
2843 * Initialize all dll's which are prepered for loading
2844 *
2845 * ARGUMENTS
2846 * none
2847 *
2848 * RETURN VALUE
2849 * status
2850 *
2851 * REVISIONS
2852 *
2853 * NOTE
2854 * The loader lock must be held on entry.
2855 *
2856 */
2857 static NTSTATUS
2858 LdrpAttachProcess(VOID)
2859 {
2860 PLIST_ENTRY ModuleListHead;
2861 PLIST_ENTRY Entry;
2862 PLDR_DATA_TABLE_ENTRY Module;
2863 BOOLEAN Result;
2864 NTSTATUS Status = STATUS_SUCCESS;
2865
2866 DPRINT("LdrpAttachProcess() called for %wZ\n",
2867 &ExeModule->BaseDllName);
2868
2869 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2870 Entry = ModuleListHead->Flink;
2871 while (Entry != ModuleListHead)
2872 {
2873 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2874 if (!(Module->Flags & (LDRP_LOAD_IN_PROGRESS|LDRP_UNLOAD_IN_PROGRESS|LDRP_ENTRY_PROCESSED)))
2875 {
2876 Module->Flags |= LDRP_LOAD_IN_PROGRESS;
2877 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2878 &Module->BaseDllName, Module->EntryPoint);
2879 Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
2880 if (!Result)
2881 {
2882 Status = STATUS_DLL_INIT_FAILED;
2883 break;
2884 }
2885 if (Module->Flags & LDRP_IMAGE_DLL && Module->EntryPoint != 0)
2886 {
2887 Module->Flags |= LDRP_PROCESS_ATTACH_CALLED|LDRP_ENTRY_PROCESSED;
2888 }
2889 else
2890 {
2891 Module->Flags |= LDRP_ENTRY_PROCESSED;
2892 }
2893 Module->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2894 }
2895 Entry = Entry->Flink;
2896 }
2897
2898 DPRINT("LdrpAttachProcess() done\n");
2899
2900 return Status;
2901 }
2902
2903 /*
2904 * @implemented
2905 */
2906 BOOLEAN NTAPI
2907 RtlDllShutdownInProgress (VOID)
2908 {
2909 return LdrpDllShutdownInProgress;
2910 }
2911
2912 /*
2913 * @implemented
2914 */
2915 NTSTATUS NTAPI
2916 LdrShutdownProcess (VOID)
2917 {
2918 LdrpDetachProcess(TRUE);
2919 return STATUS_SUCCESS;
2920 }
2921
2922 /*
2923 * @implemented
2924 */
2925
2926 NTSTATUS
2927 LdrpAttachThread (VOID)
2928 {
2929 PLIST_ENTRY ModuleListHead;
2930 PLIST_ENTRY Entry;
2931 PLDR_DATA_TABLE_ENTRY Module;
2932 NTSTATUS Status;
2933
2934 DPRINT("LdrpAttachThread() called for %wZ\n",
2935 &ExeModule->BaseDllName);
2936
2937 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2938
2939 Status = LdrpInitializeTlsForThread();
2940
2941 if (NT_SUCCESS(Status))
2942 {
2943 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2944 Entry = ModuleListHead->Flink;
2945
2946 while (Entry != ModuleListHead)
2947 {
2948 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2949 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2950 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2951 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2952 {
2953 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2954 &Module->BaseDllName, Module->EntryPoint);
2955 LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);
2956 }
2957 Entry = Entry->Flink;
2958 }
2959
2960 Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
2961 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2962 LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
2963 }
2964
2965 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2966
2967 DPRINT("LdrpAttachThread() done\n");
2968
2969 return Status;
2970 }
2971
2972
2973 /*
2974 * @implemented
2975 */
2976 NTSTATUS NTAPI
2977 LdrShutdownThread (VOID)
2978 {
2979 PLIST_ENTRY ModuleListHead;
2980 PLIST_ENTRY Entry;
2981 PLDR_DATA_TABLE_ENTRY Module;
2982
2983 DPRINT("LdrShutdownThread() called for %wZ\n",
2984 &ExeModule->BaseDllName);
2985
2986 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2987
2988 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2989 Entry = ModuleListHead->Blink;
2990 while (Entry != ModuleListHead)
2991 {
2992 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2993
2994 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2995 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2996 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2997 {
2998 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2999 &Module->BaseDllName, Module->EntryPoint);
3000 LdrpCallDllEntry(Module, DLL_THREAD_DETACH, NULL);
3001 }
3002 Entry = Entry->Blink;
3003 }
3004
3005 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3006
3007 if (LdrpTlsArray)
3008 {
3009 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer);
3010 }
3011
3012 DPRINT("LdrShutdownThread() done\n");
3013
3014 return STATUS_SUCCESS;
3015 }
3016
3017
3018 /***************************************************************************
3019 * NAME EXPORTED
3020 * LdrQueryProcessModuleInformation
3021 *
3022 * DESCRIPTION
3023 *
3024 * ARGUMENTS
3025 *
3026 * RETURN VALUE
3027 *
3028 * REVISIONS
3029 *
3030 * NOTE
3031 *
3032 * @implemented
3033 */
3034 NTSTATUS NTAPI
3035 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
3036 IN ULONG Size OPTIONAL,
3037 OUT PULONG ReturnedSize)
3038 {
3039 PLIST_ENTRY ModuleListHead;
3040 PLIST_ENTRY Entry;
3041 PLDR_DATA_TABLE_ENTRY Module;
3042 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
3043 NTSTATUS Status = STATUS_SUCCESS;
3044 ULONG UsedSize = sizeof(ULONG);
3045 ANSI_STRING AnsiString;
3046 PCHAR p;
3047
3048 DPRINT("LdrQueryProcessModuleInformation() called\n");
3049 // FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c
3050 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
3051
3052 if (ModuleInformation == NULL || Size == 0)
3053 {
3054 Status = STATUS_INFO_LENGTH_MISMATCH;
3055 }
3056 else
3057 {
3058 ModuleInformation->NumberOfModules = 0;
3059 ModulePtr = &ModuleInformation->Modules[0];
3060 Status = STATUS_SUCCESS;
3061 }
3062
3063 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
3064 Entry = ModuleListHead->Flink;
3065
3066 while (Entry != ModuleListHead)
3067 {
3068 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3069
3070 DPRINT(" Module %wZ\n",
3071 &Module->FullDllName);
3072
3073 if (UsedSize > Size)
3074 {
3075 Status = STATUS_INFO_LENGTH_MISMATCH;
3076 }
3077 else if (ModuleInformation != NULL)
3078 {
3079 ModulePtr->Section = 0;
3080 ModulePtr->MappedBase = NULL; // FIXME: ??
3081 ModulePtr->ImageBase = Module->DllBase;
3082 ModulePtr->ImageSize = Module->SizeOfImage;
3083 ModulePtr->Flags = Module->Flags;
3084 ModulePtr->LoadOrderIndex = 0; // FIXME: ??
3085 ModulePtr->InitOrderIndex = 0; // FIXME: ??
3086 ModulePtr->LoadCount = Module->LoadCount;
3087
3088 AnsiString.Length = 0;
3089 AnsiString.MaximumLength = 256;
3090 AnsiString.Buffer = ModulePtr->FullPathName;
3091 RtlUnicodeStringToAnsiString(&AnsiString,
3092 &Module->FullDllName,
3093 FALSE);
3094
3095 p = strrchr(ModulePtr->FullPathName, '\\');
3096 if (p != NULL)
3097 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
3098 else
3099 ModulePtr->OffsetToFileName = 0;
3100
3101 ModulePtr++;
3102 ModuleInformation->NumberOfModules++;
3103 }
3104 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
3105
3106 Entry = Entry->Flink;
3107 }
3108
3109 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
3110
3111 if (ReturnedSize != 0)
3112 *ReturnedSize = UsedSize;
3113
3114 DPRINT("LdrQueryProcessModuleInformation() done\n");
3115
3116 return(Status);
3117 }
3118
3119
3120 static BOOLEAN
3121 LdrpCheckImageChecksum (IN PVOID BaseAddress,
3122 IN ULONG ImageSize)
3123 {
3124 PIMAGE_NT_HEADERS Header;
3125 PUSHORT Ptr;
3126 ULONG Sum;
3127 ULONG CalcSum;
3128 ULONG HeaderSum;
3129 ULONG i;
3130
3131 Header = RtlImageNtHeader (BaseAddress);
3132 if (Header == NULL)
3133 return FALSE;
3134
3135 HeaderSum = Header->OptionalHeader.CheckSum;
3136 if (HeaderSum == 0)
3137 return TRUE;
3138
3139 Sum = 0;
3140 Ptr = (PUSHORT) BaseAddress;
3141 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
3142 {
3143 Sum += (ULONG)*Ptr;
3144 if (HIWORD(Sum) != 0)
3145 {
3146 Sum = LOWORD(Sum) + HIWORD(Sum);
3147 }
3148 Ptr++;
3149 }
3150
3151 if (ImageSize & 1)
3152 {
3153 Sum += (ULONG)*((PUCHAR)Ptr);
3154 if (HIWORD(Sum) != 0)
3155 {
3156 Sum = LOWORD(Sum) + HIWORD(Sum);
3157 }
3158 }
3159
3160 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
3161
3162 /* Subtract image checksum from calculated checksum. */
3163 /* fix low word of checksum */
3164 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
3165 {
3166 CalcSum -= LOWORD(HeaderSum);
3167 }
3168 else
3169 {
3170 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
3171 }
3172
3173 /* fix high word of checksum */
3174 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
3175 {
3176 CalcSum -= HIWORD(HeaderSum);
3177 }
3178 else
3179 {
3180 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
3181 }
3182
3183 /* add file length */
3184 CalcSum += ImageSize;
3185
3186 return (BOOLEAN)(CalcSum == HeaderSum);
3187 }
3188
3189 /*
3190 * Compute size of an image as it is actually present in virt memory
3191 * (i.e. excluding NEVER_LOAD sections)
3192 */
3193 ULONG
3194 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders)
3195 {
3196 PIMAGE_SECTION_HEADER SectionHeader;
3197 unsigned SectionIndex;
3198 ULONG ResidentSize;
3199
3200 SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader
3201 + NTHeaders->FileHeader.SizeOfOptionalHeader);
3202 ResidentSize = 0;
3203 for (SectionIndex = 0; SectionIndex < NTHeaders->FileHeader.NumberOfSections; SectionIndex++)
3204 {
3205 if (0 == (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE)
3206 && ResidentSize < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)
3207 {
3208 ResidentSize = SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize;
3209 }
3210 SectionHeader++;
3211 }
3212
3213 return ResidentSize;
3214 }
3215
3216
3217 /***************************************************************************
3218 * NAME EXPORTED
3219 * LdrVerifyImageMatchesChecksum
3220 *
3221 * DESCRIPTION
3222 *
3223 * ARGUMENTS
3224 *
3225 * RETURN VALUE
3226 *
3227 * REVISIONS
3228 *
3229 * NOTE
3230 *
3231 * @implemented
3232 */
3233 NTSTATUS NTAPI
3234 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
3235 ULONG Unknown1,
3236 ULONG Unknown2,
3237 ULONG Unknown3)
3238 {
3239 FILE_STANDARD_INFORMATION FileInfo;
3240 IO_STATUS_BLOCK IoStatusBlock;
3241 HANDLE SectionHandle;
3242 SIZE_T ViewSize;
3243 PVOID BaseAddress;
3244 BOOLEAN Result;
3245 NTSTATUS Status;
3246
3247 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
3248
3249 Status = NtCreateSection (&SectionHandle,
3250 SECTION_MAP_READ,
3251 NULL,
3252 NULL,
3253 PAGE_READONLY,
3254 SEC_COMMIT,
3255 FileHandle);
3256 if (!NT_SUCCESS(Status))
3257 {
3258 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
3259 return Status;
3260 }
3261
3262 ViewSize = 0;
3263 BaseAddress = NULL;
3264 Status = NtMapViewOfSection (SectionHandle,
3265 NtCurrentProcess (),
3266 &BaseAddress,
3267 0,
3268 0,
3269 NULL,
3270 &ViewSize,
3271 ViewShare,
3272 0,
3273 PAGE_READONLY);
3274 if (!NT_SUCCESS(Status))
3275 {
3276 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3277 NtClose (SectionHandle);
3278 return Status;
3279 }
3280
3281 Status = NtQueryInformationFile (FileHandle,
3282 &IoStatusBlock,
3283 &FileInfo,
3284 sizeof (FILE_STANDARD_INFORMATION),
3285 FileStandardInformation);
3286 if (!NT_SUCCESS(Status))
3287 {
3288 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3289 NtUnmapViewOfSection (NtCurrentProcess (),
3290 BaseAddress);
3291 NtClose (SectionHandle);
3292 return Status;
3293 }
3294
3295 Result = LdrpCheckImageChecksum (BaseAddress,
3296 FileInfo.EndOfFile.u.LowPart);
3297 if (Result == FALSE)
3298 {
3299 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
3300 }
3301
3302 NtUnmapViewOfSection (NtCurrentProcess (),
3303 BaseAddress);
3304
3305 NtClose (SectionHandle);
3306
3307 return Status;
3308 }
3309
3310
3311 /***************************************************************************
3312 * NAME EXPORTED
3313 * LdrQueryImageFileExecutionOptions
3314 *
3315 * DESCRIPTION
3316 *
3317 * ARGUMENTS
3318 *
3319 * RETURN VALUE
3320 *
3321 * REVISIONS
3322 *
3323 * NOTE
3324 *
3325 * @implemented
3326 */
3327 NTSTATUS NTAPI
3328 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
3329 IN PCWSTR ValueName,
3330 IN ULONG Type,
3331 OUT PVOID Buffer,
3332 IN ULONG BufferSize,
3333 OUT PULONG ReturnedLength OPTIONAL)
3334 {
3335 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
3336 OBJECT_ATTRIBUTES ObjectAttributes;
3337 UNICODE_STRING ValueNameString;
3338 UNICODE_STRING KeyName;
3339 WCHAR NameBuffer[256];
3340 HANDLE KeyHandle;
3341 ULONG KeyInfoSize;
3342 ULONG ResultSize;
3343 PWCHAR Ptr;
3344 NTSTATUS Status;
3345
3346 wcscpy (NameBuffer,
3347 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
3348 Ptr = wcsrchr (SubKey->Buffer, L'\\');
3349 if (Ptr == NULL)
3350 {
3351 Ptr = SubKey->Buffer;
3352 }
3353 else
3354 {
3355 Ptr++;
3356 }
3357 wcscat (NameBuffer, Ptr);
3358 RtlInitUnicodeString (&KeyName,
3359 NameBuffer);
3360
3361 InitializeObjectAttributes (&ObjectAttributes,
3362 &KeyName,
3363 OBJ_CASE_INSENSITIVE,
3364 NULL,
3365 NULL);
3366
3367 Status = NtOpenKey (&KeyHandle,
3368 KEY_READ,
3369 &ObjectAttributes);
3370 if (!NT_SUCCESS(Status))
3371 {
3372 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
3373 return Status;
3374 }
3375
3376 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
3377 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3378 HEAP_ZERO_MEMORY,
3379 KeyInfoSize);
3380 if (KeyInfo == NULL)
3381 {
3382 NtClose (KeyHandle);
3383 return STATUS_INSUFFICIENT_RESOURCES;
3384 }
3385
3386 RtlInitUnicodeString (&ValueNameString,
3387 (PWSTR)ValueName);
3388 Status = NtQueryValueKey (KeyHandle,
3389 &ValueNameString,
3390 KeyValuePartialInformation,
3391 KeyInfo,
3392 KeyInfoSize,
3393 &ResultSize);
3394 if (Status == STATUS_BUFFER_OVERFLOW)
3395 {
3396 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
3397 RtlFreeHeap (RtlGetProcessHeap(),
3398 0,
3399 KeyInfo);
3400 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3401 HEAP_ZERO_MEMORY,
3402 KeyInfoSize);
3403 if (KeyInfo == NULL)
3404 {
3405 NtClose (KeyHandle);
3406 return STATUS_INSUFFICIENT_RESOURCES;
3407 }
3408
3409 Status = NtQueryValueKey (KeyHandle,
3410 &ValueNameString,
3411 KeyValuePartialInformation,
3412 KeyInfo,
3413 KeyInfoSize,
3414 &ResultSize);
3415 }
3416 NtClose (KeyHandle);
3417
3418 if (!NT_SUCCESS(Status))
3419 {
3420 if (KeyInfo != NULL)
3421 {
3422 RtlFreeHeap (RtlGetProcessHeap(),
3423 0,
3424 KeyInfo);
3425 }
3426 return Status;
3427 }
3428
3429 if (KeyInfo->Type != Type)
3430 {
3431 RtlFreeHeap (RtlGetProcessHeap(),
3432 0,
3433 KeyInfo);
3434 return STATUS_OBJECT_TYPE_MISMATCH;
3435 }
3436
3437 ResultSize = BufferSize;
3438 if (ResultSize < KeyInfo->DataLength)
3439 {
3440 Status = STATUS_BUFFER_OVERFLOW;
3441 }
3442 else
3443 {
3444 ResultSize = KeyInfo->DataLength;
3445 }
3446 RtlCopyMemory (Buffer,
3447 &KeyInfo->Data,
3448 ResultSize);
3449
3450 RtlFreeHeap (RtlGetProcessHeap(),
3451 0,
3452 KeyInfo);
3453
3454 if (ReturnedLength != NULL)
3455 {
3456 *ReturnedLength = ResultSize;
3457 }
3458
3459 return Status;
3460 }
3461
3462
3463 PIMAGE_BASE_RELOCATION NTAPI
3464 LdrProcessRelocationBlock(IN ULONG_PTR Address,
3465 IN ULONG Count,
3466 IN PUSHORT TypeOffset,
3467 IN LONG_PTR Delta)
3468 {
3469 SHORT Offset;
3470 USHORT Type;
3471 USHORT i;
3472 PUSHORT ShortPtr;
3473 PULONG LongPtr;
3474
3475 for (i = 0; i < Count; i++)
3476 {
3477 Offset = *TypeOffset & 0xFFF;
3478 Type = *TypeOffset >> 12;
3479
3480 switch (Type)
3481 {
3482 case IMAGE_REL_BASED_ABSOLUTE:
3483 break;
3484
3485 case IMAGE_REL_BASED_HIGH:
3486 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3487 *ShortPtr += HIWORD(Delta);
3488 break;
3489
3490 case IMAGE_REL_BASED_LOW:
3491 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3492 *ShortPtr += LOWORD(Delta);
3493 break;
3494
3495 case IMAGE_REL_BASED_HIGHLOW:
3496 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3497 *LongPtr += Delta;
3498 break;
3499
3500 case IMAGE_REL_BASED_HIGHADJ:
3501 case IMAGE_REL_BASED_MIPS_JMPADDR:
3502 default:
3503 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
3504 return NULL;
3505 }
3506
3507 TypeOffset++;
3508 }
3509
3510 return (PIMAGE_BASE_RELOCATION)TypeOffset;
3511 }
3512
3513 NTSTATUS
3514 NTAPI
3515 LdrLockLoaderLock(IN ULONG Flags,
3516 OUT PULONG Disposition OPTIONAL,
3517 OUT PULONG Cookie OPTIONAL)
3518 {
3519 NTSTATUS Status;
3520 BOOLEAN Ret;
3521 BOOLEAN CookieSet = FALSE;
3522
3523 if ((Flags != 0x01) && (Flags != 0x02))
3524 return STATUS_INVALID_PARAMETER_1;
3525
3526 if (!Cookie) return STATUS_INVALID_PARAMETER_3;
3527
3528 /* Set some defaults for failure while verifying params */
3529 _SEH2_TRY
3530 {
3531 *Cookie = 0;
3532 CookieSet = TRUE;
3533 if (Disposition) *Disposition = 0;
3534 }
3535 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3536 {
3537 if (CookieSet)
3538 Status = STATUS_INVALID_PARAMETER_3;
3539 else
3540 Status = STATUS_INVALID_PARAMETER_2;
3541 }
3542 _SEH2_END;
3543
3544 if (Flags == 0x01)
3545 {
3546 DPRINT1("Warning: Reporting errors with exception not supported yet!\n");
3547 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3548 Status = STATUS_SUCCESS;
3549
3550 }
3551 else
3552 {
3553 if (!Disposition) return STATUS_INVALID_PARAMETER_2;
3554
3555 Ret = RtlTryEnterCriticalSection(NtCurrentPeb()->LoaderLock);
3556
3557 if (Ret)
3558 *Disposition = 0x01;
3559 else
3560 *Disposition = 0x02;
3561
3562 Status = STATUS_SUCCESS;
3563 }
3564
3565 /* FIXME: Cookie is based on part of the thread id */
3566 *Cookie = (ULONG)NtCurrentTeb()->RealClientId.UniqueThread;
3567 return Status;
3568 }
3569
3570 NTSTATUS
3571 NTAPI
3572 LdrUnlockLoaderLock(IN ULONG Flags,
3573 IN ULONG Cookie OPTIONAL)
3574 {
3575 if (Flags != 0x01)
3576 return STATUS_INVALID_PARAMETER_1;
3577
3578 if (Cookie != (ULONG)NtCurrentTeb()->RealClientId.UniqueThread)
3579 return STATUS_INVALID_PARAMETER_2;
3580
3581 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
3582
3583 return STATUS_SUCCESS;
3584 }
3585
3586 BOOLEAN
3587 NTAPI
3588 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
3589 {
3590 UNIMPLEMENTED;
3591 return FALSE;
3592 }