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