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