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