change a few #ifdefs to allow loading of SYM files for user modules in DBG builds
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.102 2004/12/15 03:00:33 royce Exp $
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, 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, 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, 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,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 PUCHAR 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, 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 PUCHAR 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 RtlFreeUnicodeString(&FullDosName);
2021 return Status;
2022 }
2023 RtlFreeUnicodeString(&AdjustedName);
2024 /* Map the dll into the process */
2025 ViewSize = 0;
2026 ImageBase = 0;
2027 Status = NtMapViewOfSection(SectionHandle,
2028 NtCurrentProcess(),
2029 &ImageBase,
2030 0,
2031 0,
2032 NULL,
2033 &ViewSize,
2034 0,
2035 MEM_COMMIT,
2036 PAGE_READWRITE);
2037 if (!NT_SUCCESS(Status))
2038 {
2039 DPRINT1("map view of section failed (Status %x)\n", Status);
2040 RtlFreeUnicodeString(&FullDosName);
2041 NtClose(SectionHandle);
2042 return(Status);
2043 }
2044 /* Get and check the NT headers */
2045 NtHeaders = RtlImageNtHeader(ImageBase);
2046 if (NtHeaders == NULL)
2047 {
2048 DPRINT1("RtlImageNtHeaders() failed\n");
2049 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2050 NtClose (SectionHandle);
2051 RtlFreeUnicodeString(&FullDosName);
2052 return STATUS_UNSUCCESSFUL;
2053 }
2054 /* If the base address is different from the
2055 * one the DLL is actually loaded, perform any
2056 * relocation. */
2057 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2058 {
2059 DPRINT1("Relocating (%x -> %x) %wZ\n",
2060 NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
2061 Status = LdrPerformRelocations(NtHeaders, ImageBase);
2062 if (!NT_SUCCESS(Status))
2063 {
2064 DPRINT1("LdrPerformRelocations() failed\n");
2065 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2066 NtClose (SectionHandle);
2067 RtlFreeUnicodeString(&FullDosName);
2068 return STATUS_UNSUCCESSFUL;
2069 }
2070 }
2071 *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer);
2072 (*Module)->SectionHandle = SectionHandle;
2073 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2074 {
2075 (*Module)->Flags |= IMAGE_NOT_AT_BASE;
2076 }
2077 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
2078 {
2079 (*Module)->Flags |= IMAGE_DLL;
2080 }
2081 /* fixup the imported calls entry points */
2082 Status = LdrFixupImports(SearchPath, *Module);
2083 if (!NT_SUCCESS(Status))
2084 {
2085 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
2086 return Status;
2087 }
2088 #if defined(DBG) || defined(KDBG)
2089 LdrpLoadUserModuleSymbols(*Module);
2090 #endif /* DBG || KDBG */
2091 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2092 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
2093 &(*Module)->InInitializationOrderModuleList);
2094 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2095 }
2096 return STATUS_SUCCESS;
2097 }
2098
2099 static NTSTATUS
2100 LdrpUnloadModule(PLDR_MODULE Module,
2101 BOOL Unload)
2102 {
2103 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
2104 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
2105 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
2106 PCHAR ImportedName;
2107 PLDR_MODULE ImportedModule;
2108 NTSTATUS Status;
2109 LONG LoadCount;
2110
2111
2112 if (Unload)
2113 {
2114 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2115 }
2116
2117 LoadCount = LdrpDecrementLoadCount(Module, Unload);
2118
2119 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
2120
2121 if (LoadCount == 0)
2122 {
2123 /* ?????????????????? */
2124 CHECKPOINT1;
2125 }
2126 else if (LoadCount == 1)
2127 {
2128 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
2129 RtlImageDirectoryEntryToData(Module->BaseAddress,
2130 TRUE,
2131 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
2132 NULL);
2133 if (BoundImportDescriptor)
2134 {
2135 /* dereferencing all imported modules, use the bound import descriptor */
2136 BoundImportDescriptorCurrent = BoundImportDescriptor;
2137 while (BoundImportDescriptorCurrent->OffsetModuleName)
2138 {
2139 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
2140 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2141 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2142 if (!NT_SUCCESS(Status))
2143 {
2144 DPRINT1("unable to found imported modul %s\n", ImportedName);
2145 }
2146 else
2147 {
2148 if (Module != ImportedModule)
2149 {
2150 Status = LdrpUnloadModule(ImportedModule, FALSE);
2151 if (!NT_SUCCESS(Status))
2152 {
2153 DPRINT1("unable to unload %s\n", ImportedName);
2154 }
2155 }
2156 }
2157 BoundImportDescriptorCurrent++;
2158 }
2159 }
2160 else
2161 {
2162 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
2163 RtlImageDirectoryEntryToData(Module->BaseAddress,
2164 TRUE,
2165 IMAGE_DIRECTORY_ENTRY_IMPORT,
2166 NULL);
2167 if (ImportModuleDirectory)
2168 {
2169 /* dereferencing all imported modules, use the import descriptor */
2170 while (ImportModuleDirectory->dwRVAModuleName)
2171 {
2172 ImportedName = (PCHAR)Module->BaseAddress + ImportModuleDirectory->dwRVAModuleName;
2173 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2174 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2175 if (!NT_SUCCESS(Status))
2176 {
2177 DPRINT1("unable to found imported modul %s\n", ImportedName);
2178 }
2179 else
2180 {
2181 if (Module != ImportedModule)
2182 {
2183 Status = LdrpUnloadModule(ImportedModule, FALSE);
2184 if (!NT_SUCCESS(Status))
2185 {
2186 DPRINT1("unable to unload %s\n", ImportedName);
2187 }
2188 }
2189 }
2190 ImportModuleDirectory++;
2191 }
2192 }
2193 }
2194 }
2195
2196 if (Unload)
2197 {
2198 LdrpDetachProcess(FALSE);
2199 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2200 }
2201 return STATUS_SUCCESS;
2202
2203 }
2204
2205 /*
2206 * @implemented
2207 */
2208 NTSTATUS STDCALL
2209 LdrUnloadDll (IN PVOID BaseAddress)
2210 {
2211 PLDR_MODULE Module;
2212 NTSTATUS Status;
2213
2214 if (BaseAddress == NULL)
2215 return STATUS_SUCCESS;
2216
2217 Status = LdrFindEntryForAddress(BaseAddress, &Module);
2218 if (NT_SUCCESS(Status))
2219 {
2220 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
2221 Status = LdrpUnloadModule(Module, TRUE);
2222 }
2223 return Status;
2224 }
2225
2226 /*
2227 * @implemented
2228 */
2229 NTSTATUS STDCALL
2230 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
2231 {
2232 PLIST_ENTRY ModuleListHead;
2233 PLIST_ENTRY Entry;
2234 PLDR_MODULE Module;
2235 NTSTATUS Status;
2236
2237 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress);
2238
2239 Status = STATUS_DLL_NOT_FOUND;
2240 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2241 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2242 Entry = ModuleListHead->Flink;
2243 while (Entry != ModuleListHead)
2244 {
2245 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
2246
2247 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module->BaseDllName, Module->BaseAddress);
2248
2249 if (Module->BaseAddress == BaseAddress)
2250 {
2251 if (Module->TlsIndex == -1)
2252 {
2253 Module->Flags |= DONT_CALL_FOR_THREAD;
2254 Status = STATUS_SUCCESS;
2255 }
2256 break;
2257 }
2258 Entry = Entry->Flink;
2259 }
2260 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2261 return Status;
2262 }
2263
2264 /*
2265 * @implemented
2266 */
2267 NTSTATUS STDCALL
2268 LdrGetDllHandle(IN PWCHAR Path OPTIONAL,
2269 IN ULONG Unknown2,
2270 IN PUNICODE_STRING DllName,
2271 OUT PVOID* BaseAddress)
2272 {
2273 PLDR_MODULE Module;
2274 NTSTATUS Status;
2275
2276 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", DllName, Path ? Path : L"");
2277
2278 /* NULL is the current executable */
2279 if (DllName == NULL)
2280 {
2281 *BaseAddress = ExeModule->BaseAddress;
2282 DPRINT("BaseAddress %x\n", *BaseAddress);
2283 return STATUS_SUCCESS;
2284 }
2285
2286 Status = LdrFindEntryForName(DllName, &Module, FALSE);
2287 if (NT_SUCCESS(Status))
2288 {
2289 *BaseAddress = Module->BaseAddress;
2290 return STATUS_SUCCESS;
2291 }
2292
2293 DPRINT("Failed to find dll %wZ\n", DllName);
2294 *BaseAddress = NULL;
2295 return STATUS_DLL_NOT_FOUND;
2296 }
2297
2298
2299 /*
2300 * @implemented
2301 */
2302 NTSTATUS STDCALL
2303 LdrGetProcedureAddress (IN PVOID BaseAddress,
2304 IN PANSI_STRING Name,
2305 IN ULONG Ordinal,
2306 OUT PVOID *ProcedureAddress)
2307 {
2308 if (Name && Name->Length)
2309 {
2310 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
2311 }
2312 else
2313 {
2314 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
2315 }
2316
2317 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
2318 BaseAddress, Name, Ordinal, ProcedureAddress);
2319
2320 if (Name && Name->Length)
2321 {
2322 /* by name */
2323 *ProcedureAddress = LdrGetExportByName(BaseAddress, Name->Buffer, 0xffff);
2324 if (*ProcedureAddress != NULL)
2325 {
2326 return STATUS_SUCCESS;
2327 }
2328 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
2329 }
2330 else
2331 {
2332 /* by ordinal */
2333 Ordinal &= 0x0000FFFF;
2334 *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
2335 if (*ProcedureAddress)
2336 {
2337 return STATUS_SUCCESS;
2338 }
2339 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
2340 }
2341 return STATUS_PROCEDURE_NOT_FOUND;
2342 }
2343
2344 /**********************************************************************
2345 * NAME LOCAL
2346 * LdrpDetachProcess
2347 *
2348 * DESCRIPTION
2349 * Unload dll's which are no longer referenced from others dll's
2350 *
2351 * ARGUMENTS
2352 * none
2353 *
2354 * RETURN VALUE
2355 * none
2356 *
2357 * REVISIONS
2358 *
2359 * NOTE
2360 * The loader lock must be held on enty.
2361 */
2362 static VOID
2363 LdrpDetachProcess(BOOL UnloadAll)
2364 {
2365 PLIST_ENTRY ModuleListHead;
2366 PLIST_ENTRY Entry;
2367 PLDR_MODULE Module;
2368 static ULONG CallingCount = 0;
2369
2370 DPRINT("LdrpDetachProcess() called for %wZ\n",
2371 &ExeModule->BaseDllName);
2372
2373 CallingCount++;
2374
2375 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2376 Entry = ModuleListHead->Blink;
2377 while (Entry != ModuleListHead)
2378 {
2379 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
2380 if (((UnloadAll && Module->LoadCount <= 0) || Module->LoadCount == 0) &&
2381 Module->Flags & ENTRY_PROCESSED &&
2382 !(Module->Flags & UNLOAD_IN_PROGRESS))
2383 {
2384 Module->Flags |= UNLOAD_IN_PROGRESS;
2385 if (Module == LdrpLastModule)
2386 {
2387 LdrpLastModule = NULL;
2388 }
2389 if (Module->Flags & PROCESS_ATTACH_CALLED)
2390 {
2391 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2392 &Module->BaseDllName, Module->EntryPoint);
2393 LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(Module->LoadCount == -1 ? 1 : 0));
2394 }
2395 else
2396 {
2397 TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
2398 }
2399 Entry = ModuleListHead->Blink;
2400 }
2401 else
2402 {
2403 Entry = Entry->Blink;
2404 }
2405 }
2406
2407 if (CallingCount == 1)
2408 {
2409 Entry = ModuleListHead->Blink;
2410 while (Entry != ModuleListHead)
2411 {
2412 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
2413 Entry = Entry->Blink;
2414 if (Module->Flags & UNLOAD_IN_PROGRESS &&
2415 ((UnloadAll && Module->LoadCount >= 0) || Module->LoadCount == 0))
2416 {
2417 /* remove the module entry from the list */
2418 RemoveEntryList (&Module->InLoadOrderModuleList);
2419 RemoveEntryList (&Module->InInitializationOrderModuleList);
2420
2421 NtUnmapViewOfSection (NtCurrentProcess (), Module->BaseAddress);
2422 NtClose (Module->SectionHandle);
2423
2424 TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
2425
2426 RtlFreeUnicodeString (&Module->FullDllName);
2427 RtlFreeUnicodeString (&Module->BaseDllName);
2428
2429 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2430 }
2431 }
2432 }
2433 CallingCount--;
2434 DPRINT("LdrpDetachProcess() done\n");
2435 }
2436
2437 /**********************************************************************
2438 * NAME LOCAL
2439 * LdrpAttachProcess
2440 *
2441 * DESCRIPTION
2442 * Initialize all dll's which are prepered for loading
2443 *
2444 * ARGUMENTS
2445 * none
2446 *
2447 * RETURN VALUE
2448 * status
2449 *
2450 * REVISIONS
2451 *
2452 * NOTE
2453 * The loader lock must be held on entry.
2454 *
2455 */
2456 static NTSTATUS
2457 LdrpAttachProcess(VOID)
2458 {
2459 PLIST_ENTRY ModuleListHead;
2460 PLIST_ENTRY Entry;
2461 PLDR_MODULE Module;
2462 BOOL Result;
2463 NTSTATUS Status = STATUS_SUCCESS;
2464
2465 DPRINT("LdrpAttachProcess() called for %wZ\n",
2466 &ExeModule->BaseDllName);
2467
2468 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2469 Entry = ModuleListHead->Flink;
2470 while (Entry != ModuleListHead)
2471 {
2472 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
2473 if (!(Module->Flags & (LOAD_IN_PROGRESS|UNLOAD_IN_PROGRESS|ENTRY_PROCESSED)))
2474 {
2475 Module->Flags |= LOAD_IN_PROGRESS;
2476 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2477 &Module->BaseDllName, Module->EntryPoint);
2478 Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(Module->LoadCount == -1 ? 1 : 0));
2479 if (!Result)
2480 {
2481 Status = STATUS_DLL_INIT_FAILED;
2482 break;
2483 }
2484 if (Module->Flags & IMAGE_DLL && Module->EntryPoint != 0)
2485 {
2486 Module->Flags |= PROCESS_ATTACH_CALLED|ENTRY_PROCESSED;
2487 }
2488 else
2489 {
2490 Module->Flags |= ENTRY_PROCESSED;
2491 }
2492 Module->Flags &= ~LOAD_IN_PROGRESS;
2493 }
2494 Entry = Entry->Flink;
2495 }
2496
2497 DPRINT("LdrpAttachProcess() done\n");
2498
2499 return Status;
2500 }
2501
2502 /*
2503 * @implemented
2504 */
2505 NTSTATUS STDCALL
2506 LdrShutdownProcess (VOID)
2507 {
2508 LdrpDetachProcess(TRUE);
2509 return STATUS_SUCCESS;
2510 }
2511
2512 /*
2513 * @implemented
2514 */
2515
2516 NTSTATUS
2517 LdrpAttachThread (VOID)
2518 {
2519 PLIST_ENTRY ModuleListHead;
2520 PLIST_ENTRY Entry;
2521 PLDR_MODULE Module;
2522 NTSTATUS Status;
2523
2524 DPRINT("LdrpAttachThread() called for %wZ\n",
2525 &ExeModule->BaseDllName);
2526
2527 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2528
2529 Status = LdrpInitializeTlsForThread();
2530
2531 if (NT_SUCCESS(Status))
2532 {
2533 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2534 Entry = ModuleListHead->Flink;
2535
2536 while (Entry != ModuleListHead)
2537 {
2538 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
2539 if (Module->Flags & PROCESS_ATTACH_CALLED &&
2540 !(Module->Flags & DONT_CALL_FOR_THREAD) &&
2541 !(Module->Flags & UNLOAD_IN_PROGRESS))
2542 {
2543 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2544 &Module->BaseDllName, Module->EntryPoint);
2545 LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);
2546 }
2547 Entry = Entry->Flink;
2548 }
2549
2550 Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
2551 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
2552 LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
2553 }
2554
2555 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2556
2557 DPRINT("LdrpAttachThread() done\n");
2558
2559 return Status;
2560 }
2561
2562
2563 /*
2564 * @implemented
2565 */
2566 NTSTATUS STDCALL
2567 LdrShutdownThread (VOID)
2568 {
2569 PLIST_ENTRY ModuleListHead;
2570 PLIST_ENTRY Entry;
2571 PLDR_MODULE Module;
2572
2573 DPRINT("LdrShutdownThread() called for %wZ\n",
2574 &ExeModule->BaseDllName);
2575
2576 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2577
2578 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2579 Entry = ModuleListHead->Blink;
2580 while (Entry != ModuleListHead)
2581 {
2582 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
2583
2584 if (Module->Flags & PROCESS_ATTACH_CALLED &&
2585 !(Module->Flags & DONT_CALL_FOR_THREAD) &&
2586 !(Module->Flags & UNLOAD_IN_PROGRESS))
2587 {
2588 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2589 &Module->BaseDllName, Module->EntryPoint);
2590 LdrpCallDllEntry(Module, DLL_THREAD_DETACH, NULL);
2591 }
2592 Entry = Entry->Blink;
2593 }
2594
2595 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2596
2597 if (LdrpTlsArray)
2598 {
2599 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer);
2600 }
2601
2602 DPRINT("LdrShutdownThread() done\n");
2603
2604 return STATUS_SUCCESS;
2605 }
2606
2607
2608 /***************************************************************************
2609 * NAME EXPORTED
2610 * LdrQueryProcessModuleInformation
2611 *
2612 * DESCRIPTION
2613 *
2614 * ARGUMENTS
2615 *
2616 * RETURN VALUE
2617 *
2618 * REVISIONS
2619 *
2620 * NOTE
2621 *
2622 * @implemented
2623 */
2624 NTSTATUS STDCALL
2625 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
2626 IN ULONG Size OPTIONAL,
2627 OUT PULONG ReturnedSize)
2628 {
2629 PLIST_ENTRY ModuleListHead;
2630 PLIST_ENTRY Entry;
2631 PLDR_MODULE Module;
2632 PDEBUG_MODULE_INFORMATION ModulePtr = NULL;
2633 NTSTATUS Status = STATUS_SUCCESS;
2634 ULONG UsedSize = sizeof(ULONG);
2635 ANSI_STRING AnsiString;
2636 PCHAR p;
2637
2638 DPRINT("LdrQueryProcessModuleInformation() called\n");
2639
2640 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2641
2642 if (ModuleInformation == NULL || Size == 0)
2643 {
2644 Status = STATUS_INFO_LENGTH_MISMATCH;
2645 }
2646 else
2647 {
2648 ModuleInformation->ModuleCount = 0;
2649 ModulePtr = &ModuleInformation->ModuleEntry[0];
2650 Status = STATUS_SUCCESS;
2651 }
2652
2653 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2654 Entry = ModuleListHead->Flink;
2655
2656 while (Entry != ModuleListHead)
2657 {
2658 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
2659
2660 DPRINT(" Module %wZ\n",
2661 &Module->FullDllName);
2662
2663 if (UsedSize > Size)
2664 {
2665 Status = STATUS_INFO_LENGTH_MISMATCH;
2666 }
2667 else if (ModuleInformation != NULL)
2668 {
2669 ModulePtr->Reserved[0] = ModulePtr->Reserved[1] = 0; // FIXME: ??
2670 ModulePtr->Base = Module->BaseAddress;
2671 ModulePtr->Size = Module->SizeOfImage;
2672 ModulePtr->Flags = Module->Flags;
2673 ModulePtr->Index = 0; // FIXME: index ??
2674 ModulePtr->Unknown = 0; // FIXME: ??
2675 ModulePtr->LoadCount = Module->LoadCount;
2676
2677 AnsiString.Length = 0;
2678 AnsiString.MaximumLength = 256;
2679 AnsiString.Buffer = ModulePtr->ImageName;
2680 RtlUnicodeStringToAnsiString(&AnsiString,
2681 &Module->FullDllName,
2682 FALSE);
2683 p = strrchr(ModulePtr->ImageName, '\\');
2684 if (p != NULL)
2685 ModulePtr->ModuleNameOffset = p - ModulePtr->ImageName + 1;
2686 else
2687 ModulePtr->ModuleNameOffset = 0;
2688
2689 ModulePtr++;
2690 ModuleInformation->ModuleCount++;
2691 }
2692 UsedSize += sizeof(DEBUG_MODULE_INFORMATION);
2693
2694 Entry = Entry->Flink;
2695 }
2696
2697 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2698
2699 if (ReturnedSize != 0)
2700 *ReturnedSize = UsedSize;
2701
2702 DPRINT("LdrQueryProcessModuleInformation() done\n");
2703
2704 return(Status);
2705 }
2706
2707
2708 static BOOLEAN
2709 LdrpCheckImageChecksum (IN PVOID BaseAddress,
2710 IN ULONG ImageSize)
2711 {
2712 PIMAGE_NT_HEADERS Header;
2713 PUSHORT Ptr;
2714 ULONG Sum;
2715 ULONG CalcSum;
2716 ULONG HeaderSum;
2717 ULONG i;
2718
2719 Header = RtlImageNtHeader (BaseAddress);
2720 if (Header == NULL)
2721 return FALSE;
2722
2723 HeaderSum = Header->OptionalHeader.CheckSum;
2724 if (HeaderSum == 0)
2725 return TRUE;
2726
2727 Sum = 0;
2728 Ptr = (PUSHORT) BaseAddress;
2729 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
2730 {
2731 Sum += (ULONG)*Ptr;
2732 if (HIWORD(Sum) != 0)
2733 {
2734 Sum = LOWORD(Sum) + HIWORD(Sum);
2735 }
2736 Ptr++;
2737 }
2738
2739 if (ImageSize & 1)
2740 {
2741 Sum += (ULONG)*((PUCHAR)Ptr);
2742 if (HIWORD(Sum) != 0)
2743 {
2744 Sum = LOWORD(Sum) + HIWORD(Sum);
2745 }
2746 }
2747
2748 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
2749
2750 /* Subtract image checksum from calculated checksum. */
2751 /* fix low word of checksum */
2752 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
2753 {
2754 CalcSum -= LOWORD(HeaderSum);
2755 }
2756 else
2757 {
2758 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
2759 }
2760
2761 /* fix high word of checksum */
2762 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
2763 {
2764 CalcSum -= HIWORD(HeaderSum);
2765 }
2766 else
2767 {
2768 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
2769 }
2770
2771 /* add file length */
2772 CalcSum += ImageSize;
2773
2774 return (BOOLEAN)(CalcSum == HeaderSum);
2775 }
2776
2777
2778 /***************************************************************************
2779 * NAME EXPORTED
2780 * LdrVerifyImageMatchesChecksum
2781 *
2782 * DESCRIPTION
2783 *
2784 * ARGUMENTS
2785 *
2786 * RETURN VALUE
2787 *
2788 * REVISIONS
2789 *
2790 * NOTE
2791 *
2792 * @implemented
2793 */
2794 NTSTATUS STDCALL
2795 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
2796 ULONG Unknown1,
2797 ULONG Unknown2,
2798 ULONG Unknown3)
2799 {
2800 FILE_STANDARD_INFORMATION FileInfo;
2801 IO_STATUS_BLOCK IoStatusBlock;
2802 HANDLE SectionHandle;
2803 ULONG ViewSize;
2804 PVOID BaseAddress;
2805 BOOLEAN Result;
2806 NTSTATUS Status;
2807
2808 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2809
2810 Status = NtCreateSection (&SectionHandle,
2811 SECTION_MAP_EXECUTE,
2812 NULL,
2813 NULL,
2814 PAGE_EXECUTE,
2815 SEC_COMMIT,
2816 FileHandle);
2817 if (!NT_SUCCESS(Status))
2818 {
2819 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
2820 return Status;
2821 }
2822
2823 ViewSize = 0;
2824 BaseAddress = NULL;
2825 Status = NtMapViewOfSection (SectionHandle,
2826 NtCurrentProcess (),
2827 &BaseAddress,
2828 0,
2829 0,
2830 NULL,
2831 &ViewSize,
2832 ViewShare,
2833 0,
2834 PAGE_EXECUTE);
2835 if (!NT_SUCCESS(Status))
2836 {
2837 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
2838 NtClose (SectionHandle);
2839 return Status;
2840 }
2841
2842 Status = NtQueryInformationFile (FileHandle,
2843 &IoStatusBlock,
2844 &FileInfo,
2845 sizeof (FILE_STANDARD_INFORMATION),
2846 FileStandardInformation);
2847 if (!NT_SUCCESS(Status))
2848 {
2849 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
2850 NtUnmapViewOfSection (NtCurrentProcess (),
2851 BaseAddress);
2852 NtClose (SectionHandle);
2853 return Status;
2854 }
2855
2856 Result = LdrpCheckImageChecksum (BaseAddress,
2857 FileInfo.EndOfFile.u.LowPart);
2858 if (Result == FALSE)
2859 {
2860 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2861 }
2862
2863 NtUnmapViewOfSection (NtCurrentProcess (),
2864 BaseAddress);
2865
2866 NtClose (SectionHandle);
2867
2868 return Status;
2869 }
2870
2871
2872 /***************************************************************************
2873 * NAME EXPORTED
2874 * LdrQueryImageFileExecutionOptions
2875 *
2876 * DESCRIPTION
2877 *
2878 * ARGUMENTS
2879 *
2880 * RETURN VALUE
2881 *
2882 * REVISIONS
2883 *
2884 * NOTE
2885 *
2886 * @implemented
2887 */
2888 NTSTATUS STDCALL
2889 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
2890 IN PCWSTR ValueName,
2891 IN ULONG Type,
2892 OUT PVOID Buffer,
2893 IN ULONG BufferSize,
2894 OUT PULONG ReturnedLength OPTIONAL)
2895 {
2896 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
2897 OBJECT_ATTRIBUTES ObjectAttributes;
2898 UNICODE_STRING ValueNameString;
2899 UNICODE_STRING KeyName;
2900 WCHAR NameBuffer[256];
2901 HANDLE KeyHandle;
2902 ULONG KeyInfoSize;
2903 ULONG ResultSize;
2904 PWCHAR Ptr;
2905 NTSTATUS Status;
2906
2907 wcscpy (NameBuffer,
2908 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2909 Ptr = wcsrchr (SubKey->Buffer, L'\\');
2910 if (Ptr == NULL)
2911 {
2912 Ptr = SubKey->Buffer;
2913 }
2914 else
2915 {
2916 Ptr++;
2917 }
2918 wcscat (NameBuffer, Ptr);
2919 RtlInitUnicodeString (&KeyName,
2920 NameBuffer);
2921
2922 InitializeObjectAttributes (&ObjectAttributes,
2923 &KeyName,
2924 OBJ_CASE_INSENSITIVE,
2925 NULL,
2926 NULL);
2927
2928 Status = NtOpenKey (&KeyHandle,
2929 KEY_READ,
2930 &ObjectAttributes);
2931 if (!NT_SUCCESS(Status))
2932 {
2933 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
2934 return Status;
2935 }
2936
2937 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
2938 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
2939 HEAP_ZERO_MEMORY,
2940 KeyInfoSize);
2941
2942 RtlInitUnicodeString (&ValueNameString,
2943 (PWSTR)ValueName);
2944 Status = NtQueryValueKey (KeyHandle,
2945 &ValueNameString,
2946 KeyValuePartialInformation,
2947 KeyInfo,
2948 KeyInfoSize,
2949 &ResultSize);
2950 if (Status == STATUS_BUFFER_OVERFLOW)
2951 {
2952 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
2953 RtlFreeHeap (RtlGetProcessHeap(),
2954 0,
2955 KeyInfo);
2956 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
2957 HEAP_ZERO_MEMORY,
2958 KeyInfoSize);
2959 if (KeyInfo == NULL)
2960 {
2961 NtClose (KeyHandle);
2962 return Status;
2963 }
2964
2965 Status = NtQueryValueKey (KeyHandle,
2966 &ValueNameString,
2967 KeyValuePartialInformation,
2968 KeyInfo,
2969 KeyInfoSize,
2970 &ResultSize);
2971 }
2972 NtClose (KeyHandle);
2973
2974 if (!NT_SUCCESS(Status))
2975 {
2976 if (KeyInfo != NULL)
2977 {
2978 RtlFreeHeap (RtlGetProcessHeap(),
2979 0,
2980 KeyInfo);
2981 }
2982 return Status;
2983 }
2984
2985 if (KeyInfo->Type != Type)
2986 {
2987 RtlFreeHeap (RtlGetProcessHeap(),
2988 0,
2989 KeyInfo);
2990 return STATUS_OBJECT_TYPE_MISMATCH;
2991 }
2992
2993 ResultSize = BufferSize;
2994 if (ResultSize < KeyInfo->DataLength)
2995 {
2996 Status = STATUS_BUFFER_OVERFLOW;
2997 }
2998 else
2999 {
3000 ResultSize = KeyInfo->DataLength;
3001 }
3002 RtlCopyMemory (Buffer,
3003 &KeyInfo->Data,
3004 ResultSize);
3005
3006 RtlFreeHeap (RtlGetProcessHeap(),
3007 0,
3008 KeyInfo);
3009
3010 if (ReturnedLength != NULL)
3011 {
3012 *ReturnedLength = ResultSize;
3013 }
3014
3015 return Status;
3016 }
3017
3018
3019 PIMAGE_BASE_RELOCATION STDCALL
3020 LdrProcessRelocationBlock(IN PVOID Address,
3021 IN USHORT Count,
3022 IN PUSHORT TypeOffset,
3023 IN ULONG_PTR Delta)
3024 {
3025 SHORT Offset;
3026 USHORT Type;
3027 USHORT i;
3028 PUSHORT ShortPtr;
3029 PULONG LongPtr;
3030
3031 for (i = 0; i < Count; i++)
3032 {
3033 Offset = *TypeOffset & 0xFFF;
3034 Type = *TypeOffset >> 12;
3035
3036 switch (Type)
3037 {
3038 case IMAGE_REL_BASED_ABSOLUTE:
3039 break;
3040
3041 case IMAGE_REL_BASED_HIGH:
3042 ShortPtr = (PUSHORT)(Address + Offset);
3043 *ShortPtr += HIWORD(Delta);
3044 break;
3045
3046 case IMAGE_REL_BASED_LOW:
3047 ShortPtr = (PUSHORT)(Address + Offset);
3048 *ShortPtr += LOWORD(Delta);
3049 break;
3050
3051 case IMAGE_REL_BASED_HIGHLOW:
3052 LongPtr = (PULONG)(Address + Offset);
3053 *LongPtr += Delta;
3054 break;
3055
3056 case IMAGE_REL_BASED_HIGHADJ:
3057 case IMAGE_REL_BASED_MIPS_JMPADDR:
3058 default:
3059 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
3060 return NULL;
3061 }
3062
3063 TypeOffset++;
3064 }
3065
3066 return (PIMAGE_BASE_RELOCATION)TypeOffset;
3067 }
3068
3069 /* EOF */