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