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