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