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