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