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