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