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