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