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