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