Implemented LdrQueryImageFileExecutionOptions().
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.69 2003/07/27 11:39:18 ekohl 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 */
10
11 /*
12 * TODO:
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
15 * - any more ??
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
22 #include <windows.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27
28
29 #ifdef DBG_NTDLL_LDR_UTILS
30 #define NDEBUG
31 #endif
32 #include <ntdll/ntdll.h>
33
34 /* GLOBALS *******************************************************************/
35
36 static HANDLE LdrpKnownDllsDirHandle = NULL;
37 static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
38
39
40 /* PROTOTYPES ****************************************************************/
41
42 static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_MODULE *Module);
43 static PVOID LdrFixupForward(PCHAR ForwardName);
44 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
45
46
47 /* FUNCTIONS *****************************************************************/
48
49
50 #ifdef DBG
51
52 VOID
53 LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
54 {
55 NtSystemDebugControl(
56 DebugDbgLoadSymbols,
57 (PVOID)LdrModule,
58 0,
59 NULL,
60 0,
61 NULL);
62 }
63
64 #endif /* DBG */
65
66
67 VOID
68 LdrpInitLoader(VOID)
69 {
70 OBJECT_ATTRIBUTES ObjectAttributes;
71 UNICODE_STRING LinkTarget;
72 UNICODE_STRING Name;
73 HANDLE LinkHandle;
74 ULONG Length;
75 NTSTATUS Status;
76
77 DPRINT("LdrpInitLoader() called\n");
78
79 /* Get handle to the 'KnownDlls' directory */
80 RtlInitUnicodeString(&Name,
81 L"\\KnownDlls");
82 InitializeObjectAttributes(&ObjectAttributes,
83 &Name,
84 OBJ_CASE_INSENSITIVE,
85 NULL,
86 NULL);
87 Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
88 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
89 &ObjectAttributes);
90 if (!NT_SUCCESS(Status))
91 {
92 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
93 LdrpKnownDllsDirHandle = NULL;
94 return;
95 }
96
97 /* Allocate target name string */
98 LinkTarget.Length = 0;
99 LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
100 LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
101 0,
102 MAX_PATH * sizeof(WCHAR));
103 if (LinkTarget.Buffer == NULL)
104 {
105 NtClose(LdrpKnownDllsDirHandle);
106 LdrpKnownDllsDirHandle = NULL;
107 return;
108 }
109
110 RtlInitUnicodeString(&Name,
111 L"KnownDllPath");
112 InitializeObjectAttributes(&ObjectAttributes,
113 &Name,
114 OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
115 LdrpKnownDllsDirHandle,
116 NULL);
117 Status = NtOpenSymbolicLinkObject(&LinkHandle,
118 SYMBOLIC_LINK_ALL_ACCESS,
119 &ObjectAttributes);
120 if (!NT_SUCCESS(Status))
121 {
122 RtlFreeUnicodeString(&LinkTarget);
123 NtClose(LdrpKnownDllsDirHandle);
124 LdrpKnownDllsDirHandle = NULL;
125 return;
126 }
127
128 Status = NtQuerySymbolicLinkObject(LinkHandle,
129 &LinkTarget,
130 &Length);
131 NtClose(LinkHandle);
132 if (!NT_SUCCESS(Status))
133 {
134 RtlFreeUnicodeString(&LinkTarget);
135 NtClose(LdrpKnownDllsDirHandle);
136 LdrpKnownDllsDirHandle = NULL;
137 }
138
139 RtlCreateUnicodeString(&LdrpKnownDllPath,
140 LinkTarget.Buffer);
141
142 RtlFreeUnicodeString(&LinkTarget);
143
144 DPRINT("LdrpInitLoader() done\n");
145 }
146
147
148 /***************************************************************************
149 * NAME LOCAL
150 * LdrAdjustDllName
151 *
152 * DESCRIPTION
153 * Adjusts the name of a dll to a fully qualified name.
154 *
155 * ARGUMENTS
156 * FullDllName: Pointer to caller supplied storage for the fully
157 * qualified dll name.
158 * DllName: Pointer to the dll name.
159 * BaseName: TRUE: Only the file name is passed to FullDllName
160 * FALSE: The full path is preserved in FullDllName
161 *
162 * RETURN VALUE
163 * None
164 *
165 * REVISIONS
166 *
167 * NOTE
168 * A given path is not affected by the adjustment, but the file
169 * name only:
170 * ntdll --> ntdll.dll
171 * ntdll. --> ntdll
172 * ntdll.xyz --> ntdll.xyz
173 */
174
175 static VOID
176 LdrAdjustDllName (PUNICODE_STRING FullDllName,
177 PUNICODE_STRING DllName,
178 BOOLEAN BaseName)
179 {
180 WCHAR Buffer[MAX_PATH];
181 ULONG Length;
182 PWCHAR Extension;
183 PWCHAR Pointer;
184
185 Length = DllName->Length / sizeof(WCHAR);
186
187 if (BaseName == TRUE)
188 {
189 /* get the base dll name */
190 Pointer = DllName->Buffer + Length;
191 Extension = Pointer;
192
193 do
194 {
195 --Pointer;
196 }
197 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
198
199 Pointer++;
200 Length = Extension - Pointer;
201 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
202 Buffer[Length] = L'\0';
203 }
204 else
205 {
206 /* get the full dll name */
207 memmove (Buffer, DllName->Buffer, DllName->Length);
208 Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
209 }
210
211 /* Build the DLL's absolute name */
212 Extension = wcsrchr (Buffer, L'.');
213 if ((Extension != NULL) && (*Extension == L'.'))
214 {
215 /* with extension - remove dot if it's the last character */
216 if (Buffer[Length - 1] == L'.')
217 Length--;
218 Buffer[Length] = 0;
219 }
220 else
221 {
222 /* name without extension - assume that it is .dll */
223 memmove (Buffer + Length, L".dll", 10);
224 }
225
226 RtlCreateUnicodeString(FullDllName, Buffer);
227 }
228
229 PLDR_MODULE
230 LdrAddModuleEntry(PVOID ImageBase,
231 PIMAGE_NT_HEADERS NTHeaders,
232 PWSTR FullDosName)
233 {
234 PLDR_MODULE Module;
235 Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE));
236 assert(Module);
237 Module->BaseAddress = (PVOID)ImageBase;
238 Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
239 if (Module->EntryPoint != 0)
240 Module->EntryPoint += (ULONG)Module->BaseAddress;
241 Module->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
242 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
243 {
244 /* loading while app is running */
245 Module->LoadCount = 1;
246 } else {
247 /*
248 * loading while app is initializing
249 * dll must not be unloaded
250 */
251 Module->LoadCount = -1;
252 }
253
254 Module->TlsIndex = 0;
255 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
256 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
257
258 RtlCreateUnicodeString (&Module->FullDllName,
259 FullDosName);
260 RtlCreateUnicodeString (&Module->BaseDllName,
261 wcsrchr(FullDosName, L'\\') + 1);
262 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
263
264 /* FIXME: aquire loader lock */
265 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
266 &Module->InLoadOrderModuleList);
267 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
268 &Module->InInitializationOrderModuleList);
269 /* FIXME: release loader lock */
270
271 return(Module);
272 }
273
274
275 static NTSTATUS
276 LdrpMapKnownDll(IN PUNICODE_STRING DllName,
277 OUT PUNICODE_STRING FullDosName,
278 OUT PHANDLE SectionHandle)
279 {
280 OBJECT_ATTRIBUTES ObjectAttributes;
281 UNICODE_STRING ObjectDirName;
282 NTSTATUS Status;
283
284 DPRINT("LdrpMapKnownDll() called\n");
285
286 if (LdrpKnownDllsDirHandle == NULL)
287 {
288 DPRINT("Invalid 'KnownDlls' directory\n");
289 return STATUS_UNSUCCESSFUL;
290 }
291
292 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath);
293
294 InitializeObjectAttributes(&ObjectAttributes,
295 DllName,
296 OBJ_CASE_INSENSITIVE,
297 LdrpKnownDllsDirHandle,
298 NULL);
299 Status = NtOpenSection(SectionHandle,
300 SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
301 &ObjectAttributes);
302 if (!NT_SUCCESS(Status))
303 {
304 DPRINT("NtOpenSection() failed for '%wZ' (Status %lx)\n", DllName, Status);
305 return Status;
306 }
307
308 FullDosName->Length = LdrpKnownDllPath.Length + DllName->Length + sizeof(WCHAR);
309 FullDosName->MaximumLength = FullDosName->Length + sizeof(WCHAR);
310 FullDosName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
311 0,
312 FullDosName->MaximumLength);
313 if (FullDosName->Buffer == NULL)
314 {
315 FullDosName->Length = 0;
316 FullDosName->MaximumLength = 0;
317 return STATUS_SUCCESS;
318 }
319
320 wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer);
321 wcscat(FullDosName->Buffer, L"\\");
322 wcscat(FullDosName->Buffer, DllName->Buffer);
323
324 DPRINT("FullDosName '%wZ'\n", FullDosName);
325
326 DPRINT("LdrpMapKnownDll() done\n");
327
328 return STATUS_SUCCESS;
329 }
330
331
332 static NTSTATUS
333 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
334 IN PUNICODE_STRING DllName,
335 OUT PUNICODE_STRING FullDosName,
336 OUT PHANDLE SectionHandle)
337 {
338 WCHAR SearchPathBuffer[MAX_PATH];
339 WCHAR DosName[MAX_PATH];
340 UNICODE_STRING FullNtFileName;
341 OBJECT_ATTRIBUTES FileObjectAttributes;
342 HANDLE FileHandle;
343 char BlockBuffer [1024];
344 PIMAGE_DOS_HEADER DosHeader;
345 PIMAGE_NT_HEADERS NTHeaders;
346 PVOID ImageBase;
347 ULONG ImageSize;
348 NTSTATUS Status;
349
350 DPRINT("LdrpMapDllImageFile() called\n");
351
352 if (SearchPath == NULL)
353 {
354 SearchPath = SearchPathBuffer;
355 wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
356 wcscat (SearchPathBuffer, L"\\system32;");
357 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
358 wcscat (SearchPathBuffer, L";.");
359 }
360
361 DPRINT("SearchPath %S\n", SearchPath);
362
363 if (RtlDosSearchPath_U (SearchPath,
364 DllName->Buffer,
365 NULL,
366 MAX_PATH,
367 DosName,
368 NULL) == 0)
369 return STATUS_DLL_NOT_FOUND;
370
371 DPRINT("DosName %S\n", DosName);
372
373 if (!RtlDosPathNameToNtPathName_U (DosName,
374 &FullNtFileName,
375 NULL,
376 NULL))
377 return STATUS_DLL_NOT_FOUND;
378
379 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
380
381 InitializeObjectAttributes(&FileObjectAttributes,
382 &FullNtFileName,
383 0,
384 NULL,
385 NULL);
386
387 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
388
389 Status = ZwOpenFile(&FileHandle,
390 FILE_ALL_ACCESS,
391 &FileObjectAttributes,
392 NULL,
393 0,
394 0);
395 if (!NT_SUCCESS(Status))
396 {
397 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
398 &FullNtFileName, Status);
399 RtlFreeUnicodeString (&FullNtFileName);
400 return Status;
401 }
402 RtlFreeUnicodeString (&FullNtFileName);
403
404 Status = ZwReadFile(FileHandle,
405 0,
406 0,
407 0,
408 0,
409 BlockBuffer,
410 sizeof(BlockBuffer),
411 0,
412 0);
413 if (!NT_SUCCESS(Status))
414 {
415 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
416 ZwClose(FileHandle);
417 return Status;
418 }
419 /*
420 * Overlay DOS and NT headers structures to the
421 * buffer with DLL's header raw data.
422 */
423 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
424 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
425 /*
426 * Check it is a PE image file.
427 */
428 if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
429 || (DosHeader->e_lfanew == 0L)
430 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
431 {
432 DPRINT("NTDLL format invalid\n");
433 ZwClose(FileHandle);
434
435 return STATUS_UNSUCCESSFUL;
436 }
437
438 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
439 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
440
441 DPRINT("ImageBase 0x%08x\n", ImageBase);
442
443 /*
444 * Create a section for dll.
445 */
446 Status = ZwCreateSection(SectionHandle,
447 SECTION_ALL_ACCESS,
448 NULL,
449 NULL,
450 PAGE_READWRITE,
451 SEC_COMMIT | SEC_IMAGE,
452 FileHandle);
453 ZwClose(FileHandle);
454
455 if (!NT_SUCCESS(Status))
456 {
457 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
458 return Status;
459 }
460
461 RtlCreateUnicodeString(FullDosName,
462 DosName);
463
464 return Status;
465 }
466
467
468
469 /***************************************************************************
470 * NAME EXPORTED
471 * LdrLoadDll
472 *
473 * DESCRIPTION
474 *
475 * ARGUMENTS
476 *
477 * RETURN VALUE
478 *
479 * REVISIONS
480 *
481 * NOTE
482 *
483 * @implemented
484 */
485
486 NTSTATUS STDCALL
487 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
488 IN ULONG LoadFlags,
489 IN PUNICODE_STRING Name,
490 OUT PVOID *BaseAddress OPTIONAL)
491 {
492 UNICODE_STRING FullDosName;
493 UNICODE_STRING AdjustedName;
494 NTSTATUS Status;
495 PIMAGE_NT_HEADERS NTHeaders;
496 ULONG ViewSize;
497 PVOID ImageBase;
498 HANDLE SectionHandle;
499 PDLLMAIN_FUNC Entrypoint = NULL;
500 PLDR_MODULE Module;
501
502
503 if (Name == NULL)
504 {
505 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
506 return STATUS_SUCCESS;
507 }
508
509 *BaseAddress = NULL;
510
511 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
512 Name, BaseAddress);
513
514 /* adjust the full dll name */
515 LdrAdjustDllName (&AdjustedName,
516 Name,
517 FALSE);
518 DPRINT("AdjustedName: %wZ\n", &AdjustedName);
519
520 /*
521 * Test if dll is already loaded.
522 */
523 if (LdrFindEntryForName(&AdjustedName, &Module) == STATUS_SUCCESS)
524 {
525 DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
526 if (Module->LoadCount != -1)
527 Module->LoadCount++;
528 *BaseAddress = Module->BaseAddress;
529 return STATUS_SUCCESS;
530 }
531 DPRINT("Loading \"%wZ\"\n", Name);
532
533 /* Open or create dll image section */
534 Status = LdrpMapKnownDll(&AdjustedName,
535 &FullDosName,
536 &SectionHandle);
537 if (!NT_SUCCESS(Status))
538 {
539 Status = LdrpMapDllImageFile(SearchPath,
540 &AdjustedName,
541 &FullDosName,
542 &SectionHandle);
543 }
544
545 RtlFreeUnicodeString(&AdjustedName);
546
547 if (!NT_SUCCESS(Status))
548 {
549 DPRINT1("Failed to create or open dll section (Status %lx)\n", Status);
550 return Status;
551 }
552
553 /*
554 * Map the dll into the process.
555 */
556 ViewSize = 0;
557 ImageBase = 0;
558 Status = NtMapViewOfSection(SectionHandle,
559 NtCurrentProcess(),
560 &ImageBase,
561 0,
562 0,
563 NULL,
564 &ViewSize,
565 0,
566 MEM_COMMIT,
567 PAGE_READWRITE);
568 if (!NT_SUCCESS(Status))
569 {
570 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n", Status);
571 RtlFreeUnicodeString(&FullDosName);
572 NtClose(SectionHandle);
573 return(Status);
574 }
575
576 /* Get and check the NT headers */
577 NTHeaders = RtlImageNtHeader(ImageBase);
578 if (NTHeaders == NULL)
579 {
580 DPRINT1("RtlImageNtHeaders() failed\n");
581 RtlFreeUnicodeString(&FullDosName);
582 return STATUS_UNSUCCESSFUL;
583 }
584
585 /* relocate dll and fixup import table */
586 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
587 IMAGE_FILE_DLL)
588 {
589 Entrypoint =
590 (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle, &Module,
591 FullDosName.Buffer);
592 if (Entrypoint == NULL)
593 {
594 RtlFreeUnicodeString(&FullDosName);
595 return(STATUS_UNSUCCESSFUL);
596 }
597 }
598
599 RtlFreeUnicodeString(&FullDosName);
600
601 #ifdef DBG
602
603 LdrpLoadUserModuleSymbols(Module);
604
605 #endif /* DBG */
606
607 /* initialize dll */
608 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
609 IMAGE_FILE_DLL)
610 {
611 if (Module->EntryPoint != 0)
612 {
613 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
614
615 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
616 if (FALSE == Entrypoint(Module->BaseAddress,
617 DLL_PROCESS_ATTACH,
618 NULL))
619 {
620 /* Do this as a DPRINT1 for now, until clean up and fail implemented */
621 DPRINT1("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
622 &Module->BaseDllName);
623 /* FIXME: should clean up and fail */
624 }
625 else
626 {
627 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
628 &Module->BaseDllName);
629 }
630 }
631 else
632 {
633 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
634 &Module->BaseDllName);
635 }
636 }
637
638 *BaseAddress = Module->BaseAddress;
639 return STATUS_SUCCESS;
640 }
641
642
643 /***************************************************************************
644 * NAME EXPORTED
645 * LdrFindEntryForAddress
646 *
647 * DESCRIPTION
648 *
649 * ARGUMENTS
650 *
651 * RETURN VALUE
652 *
653 * REVISIONS
654 *
655 * NOTE
656 *
657 * @implemented
658 */
659 NTSTATUS STDCALL
660 LdrFindEntryForAddress(PVOID Address,
661 PLDR_MODULE *Module)
662 {
663 PLIST_ENTRY ModuleListHead;
664 PLIST_ENTRY Entry;
665 PLDR_MODULE ModulePtr;
666
667 DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address);
668
669 if (NtCurrentPeb()->Ldr == NULL)
670 return(STATUS_NO_MORE_ENTRIES);
671
672 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
673 Entry = ModuleListHead->Flink;
674 if (Entry == ModuleListHead)
675 return(STATUS_NO_MORE_ENTRIES);
676
677 while (Entry != ModuleListHead)
678 {
679 ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
680
681 DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->BaseAddress);
682
683 if ((Address >= ModulePtr->BaseAddress) &&
684 (Address <= (ModulePtr->BaseAddress + ModulePtr->SizeOfImage)))
685 {
686 *Module = ModulePtr;
687 return(STATUS_SUCCESS);
688 }
689
690 Entry = Entry->Flink;
691 }
692
693 DPRINT("Failed to find module entry.\n");
694
695 return(STATUS_NO_MORE_ENTRIES);
696 }
697
698
699 /***************************************************************************
700 * NAME LOCAL
701 * LdrFindEntryForName
702 *
703 * DESCRIPTION
704 *
705 * ARGUMENTS
706 *
707 * RETURN VALUE
708 *
709 * REVISIONS
710 *
711 * NOTE
712 *
713 */
714 static NTSTATUS
715 LdrFindEntryForName(PUNICODE_STRING Name,
716 PLDR_MODULE *Module)
717 {
718 PLIST_ENTRY ModuleListHead;
719 PLIST_ENTRY Entry;
720 PLDR_MODULE ModulePtr;
721 BOOLEAN ContainsPath;
722 unsigned i;
723
724 DPRINT("NTDLL.LdrFindEntryForName(Name %wZ)\n", Name);
725
726 if (NtCurrentPeb()->Ldr == NULL)
727 return(STATUS_NO_MORE_ENTRIES);
728
729 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
730 Entry = ModuleListHead->Flink;
731 if (Entry == ModuleListHead)
732 return(STATUS_NO_MORE_ENTRIES);
733
734 // NULL is the current process
735 if (Name == NULL)
736 {
737 *Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
738 return(STATUS_SUCCESS);
739 }
740
741 ContainsPath = (Name->Length >= 2 * sizeof(WCHAR) && L':' == Name->Buffer[1]);
742 for (i = 0; ! ContainsPath && i < Name->Length / sizeof(WCHAR); i++)
743 {
744 ContainsPath = L'\\' == Name->Buffer[i] ||
745 L'/' == Name->Buffer[i];
746 }
747 while (Entry != ModuleListHead)
748 {
749 ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
750
751 DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, Name);
752
753 if ((! ContainsPath &&
754 0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, Name, TRUE)) ||
755 (ContainsPath &&
756 0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, Name, TRUE)))
757 {
758 *Module = ModulePtr;
759 return(STATUS_SUCCESS);
760 }
761
762 Entry = Entry->Flink;
763 }
764
765 DPRINT("Failed to find dll %wZ\n", Name);
766
767 return(STATUS_NO_MORE_ENTRIES);
768 }
769
770 /**********************************************************************
771 * NAME LOCAL
772 * LdrFixupForward
773 *
774 * DESCRIPTION
775 *
776 * ARGUMENTS
777 *
778 * RETURN VALUE
779 *
780 * REVISIONS
781 *
782 * NOTE
783 *
784 */
785 static PVOID
786 LdrFixupForward(PCHAR ForwardName)
787 {
788 CHAR NameBuffer[128];
789 UNICODE_STRING DllName;
790 UNICODE_STRING FunctionName;
791 NTSTATUS Status;
792 PCHAR p;
793 PVOID BaseAddress;
794
795 strcpy(NameBuffer, ForwardName);
796 p = strchr(NameBuffer, '.');
797 if (p != NULL)
798 {
799 *p = 0;
800
801 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
802 RtlCreateUnicodeStringFromAsciiz (&DllName,
803 NameBuffer);
804
805 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
806 if (!NT_SUCCESS(Status))
807 {
808 Status = LdrLoadDll(NULL,
809 0,
810 &DllName,
811 &BaseAddress);
812 if (!NT_SUCCESS(Status))
813 {
814 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
815 RtlFreeUnicodeString (&DllName);
816 return NULL;
817 }
818 }
819
820 RtlFreeUnicodeString (&DllName);
821 DPRINT("BaseAddress: %p\n", BaseAddress);
822
823 return LdrGetExportByName(BaseAddress, p+1, -1);
824 }
825
826 return NULL;
827 }
828
829
830 /**********************************************************************
831 * NAME LOCAL
832 * LdrGetExportByOrdinal
833 *
834 * DESCRIPTION
835 *
836 * ARGUMENTS
837 *
838 * RETURN VALUE
839 *
840 * REVISIONS
841 *
842 * NOTE
843 *
844 */
845 static PVOID
846 LdrGetExportByOrdinal (
847 PVOID BaseAddress,
848 ULONG Ordinal
849 )
850 {
851 PIMAGE_EXPORT_DIRECTORY ExportDir;
852 PDWORD * ExFunctions;
853 USHORT * ExOrdinals;
854
855 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
856 RtlImageDirectoryEntryToData (BaseAddress,
857 TRUE,
858 IMAGE_DIRECTORY_ENTRY_EXPORT,
859 NULL);
860
861
862 ExOrdinals = (USHORT *)
863 RVA(
864 BaseAddress,
865 ExportDir->AddressOfNameOrdinals
866 );
867 ExFunctions = (PDWORD *)
868 RVA(
869 BaseAddress,
870 ExportDir->AddressOfFunctions
871 );
872 DbgPrint(
873 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
874 Ordinal,
875 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
876 );
877 return(RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] ));
878 }
879
880
881 /**********************************************************************
882 * NAME LOCAL
883 * LdrGetExportByName
884 *
885 * DESCRIPTION
886 *
887 * ARGUMENTS
888 *
889 * RETURN VALUE
890 *
891 * REVISIONS
892 *
893 * NOTE
894 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
895 * both with NumberOfNames entries.
896 *
897 */
898 static PVOID
899 LdrGetExportByName(PVOID BaseAddress,
900 PUCHAR SymbolName,
901 WORD Hint)
902 {
903 PIMAGE_EXPORT_DIRECTORY ExportDir;
904 PDWORD * ExFunctions;
905 PDWORD * ExNames;
906 USHORT * ExOrdinals;
907 ULONG i;
908 PVOID ExName;
909 ULONG Ordinal;
910 PVOID Function;
911 ULONG minn, maxn;
912 ULONG ExportDirSize;
913
914 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
915
916 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
917 RtlImageDirectoryEntryToData(BaseAddress,
918 TRUE,
919 IMAGE_DIRECTORY_ENTRY_EXPORT,
920 &ExportDirSize);
921 if (ExportDir == NULL)
922 {
923 DbgPrint("LdrGetExportByName(): no export directory!\n");
924 return NULL;
925 }
926
927
928 //The symbol names may be missing entirely
929 if (ExportDir->AddressOfNames == 0)
930 {
931 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
932 return NULL;
933 }
934
935 /*
936 * Get header pointers
937 */
938 ExNames = (PDWORD *)RVA(BaseAddress,
939 ExportDir->AddressOfNames);
940 ExOrdinals = (USHORT *)RVA(BaseAddress,
941 ExportDir->AddressOfNameOrdinals);
942 ExFunctions = (PDWORD *)RVA(BaseAddress,
943 ExportDir->AddressOfFunctions);
944
945 /*
946 * Check the hint first
947 */
948 if (Hint < ExportDir->NumberOfNames)
949 {
950 ExName = RVA(BaseAddress, ExNames[Hint]);
951 if (strcmp(ExName, SymbolName) == 0)
952 {
953 Ordinal = ExOrdinals[Hint];
954 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
955 if (((ULONG)Function >= (ULONG)ExportDir) &&
956 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
957 {
958 DPRINT("Forward: %s\n", (PCHAR)Function);
959 Function = LdrFixupForward((PCHAR)Function);
960 }
961 if (Function != NULL)
962 return Function;
963 }
964 }
965
966 /*
967 * Try a binary search first
968 */
969 minn = 0;
970 maxn = ExportDir->NumberOfNames;
971 while (minn <= maxn)
972 {
973 ULONG mid;
974 LONG res;
975
976 mid = (minn + maxn) / 2;
977
978 ExName = RVA(BaseAddress, ExNames[mid]);
979 res = strcmp(ExName, SymbolName);
980 if (res == 0)
981 {
982 Ordinal = ExOrdinals[mid];
983 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
984 if (((ULONG)Function >= (ULONG)ExportDir) &&
985 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
986 {
987 DPRINT("Forward: %s\n", (PCHAR)Function);
988 Function = LdrFixupForward((PCHAR)Function);
989 }
990 if (Function != NULL)
991 return Function;
992 }
993 else if (minn == maxn)
994 {
995 DPRINT("LdrGetExportByName(): binary search failed\n");
996 break;
997 }
998 else if (res > 0)
999 {
1000 maxn = mid - 1;
1001 }
1002 else
1003 {
1004 minn = mid + 1;
1005 }
1006 }
1007
1008 /*
1009 * Fall back on a linear search
1010 */
1011 DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1012 for (i = 0; i < ExportDir->NumberOfNames; i++)
1013 {
1014 ExName = RVA(BaseAddress, ExNames[i]);
1015 if (strcmp(ExName,SymbolName) == 0)
1016 {
1017 Ordinal = ExOrdinals[i];
1018 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1019 DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
1020 if (((ULONG)Function >= (ULONG)ExportDir) &&
1021 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
1022 {
1023 DPRINT("Forward: %s\n", (PCHAR)Function);
1024 Function = LdrFixupForward((PCHAR)Function);
1025 }
1026 return Function;
1027 }
1028 }
1029 DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
1030 return NULL;
1031 }
1032
1033
1034 /**********************************************************************
1035 * NAME LOCAL
1036 * LdrPerformRelocations
1037 *
1038 * DESCRIPTION
1039 * Relocate a DLL's memory image.
1040 *
1041 * ARGUMENTS
1042 *
1043 * RETURN VALUE
1044 *
1045 * REVISIONS
1046 *
1047 * NOTE
1048 *
1049 */
1050 static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders,
1051 PVOID ImageBase)
1052 {
1053 USHORT NumberOfEntries;
1054 PUSHORT pValue16;
1055 ULONG RelocationRVA;
1056 ULONG Delta32;
1057 ULONG Offset;
1058 PULONG pValue32;
1059 PRELOCATION_DIRECTORY RelocationDir;
1060 PRELOCATION_ENTRY RelocationBlock;
1061 int i;
1062 PIMAGE_DATA_DIRECTORY RelocationDDir;
1063 ULONG OldProtect;
1064 ULONG OldProtect2;
1065 NTSTATUS Status;
1066 PIMAGE_SECTION_HEADER Sections;
1067 ULONG MaxExtend;
1068 ULONG LastOffset;
1069
1070 Sections =
1071 (PIMAGE_SECTION_HEADER)((PVOID)NTHeaders + sizeof(IMAGE_NT_HEADERS));
1072 MaxExtend = 0;
1073 for (i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++)
1074 {
1075 if (!(Sections[i].Characteristics & IMAGE_SECTION_NOLOAD))
1076 {
1077 ULONG Extend;
1078 Extend =
1079 (ULONG)(Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize);
1080 MaxExtend = max(MaxExtend, Extend);
1081 }
1082 }
1083
1084 RelocationDDir =
1085 &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1086 RelocationRVA = RelocationDDir->VirtualAddress;
1087
1088 if (RelocationRVA)
1089 {
1090 RelocationDir =
1091 (PRELOCATION_DIRECTORY)((PCHAR)ImageBase + RelocationRVA);
1092
1093 while (RelocationDir->SizeOfBlock)
1094 {
1095 if (RelocationDir->VirtualAddress > MaxExtend)
1096 {
1097 RelocationRVA += RelocationDir->SizeOfBlock;
1098 RelocationDir =
1099 (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
1100 continue;
1101 }
1102
1103 Delta32 = (ULONG)(ImageBase - NTHeaders->OptionalHeader.ImageBase);
1104 RelocationBlock =
1105 (PRELOCATION_ENTRY) (RelocationRVA + ImageBase +
1106 sizeof (RELOCATION_DIRECTORY));
1107 NumberOfEntries =
1108 RelocationDir->SizeOfBlock - sizeof (RELOCATION_DIRECTORY);
1109 NumberOfEntries = NumberOfEntries / sizeof (RELOCATION_ENTRY);
1110
1111 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1112 ImageBase +
1113 RelocationDir->VirtualAddress,
1114 PAGE_SIZE,
1115 PAGE_READWRITE,
1116 &OldProtect);
1117 if (!NT_SUCCESS(Status))
1118 {
1119 DPRINT1("Failed to unprotect relocation target.\n");
1120 return(Status);
1121 }
1122
1123 if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
1124 {
1125 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1126 ImageBase +
1127 RelocationDir->VirtualAddress + PAGE_SIZE,
1128 PAGE_SIZE,
1129 PAGE_READWRITE,
1130 &OldProtect2);
1131 if (!NT_SUCCESS(Status))
1132 {
1133 DPRINT1("Failed to unprotect relocation target (2).\n");
1134 NtProtectVirtualMemory(NtCurrentProcess(),
1135 ImageBase +
1136 RelocationDir->VirtualAddress,
1137 PAGE_SIZE,
1138 OldProtect,
1139 &OldProtect);
1140 return(Status);
1141 }
1142 }
1143
1144 for (i = 0; i < NumberOfEntries; i++)
1145 {
1146 Offset = (RelocationBlock[i].TypeOffset & 0xfff);
1147 Offset += (ULONG)(RelocationDir->VirtualAddress + ImageBase);
1148
1149 /*
1150 * What kind of relocations should we perform
1151 * for the current entry?
1152 */
1153 switch (RelocationBlock[i].TypeOffset >> 12)
1154 {
1155 case TYPE_RELOC_ABSOLUTE:
1156 break;
1157
1158 case TYPE_RELOC_HIGH:
1159 pValue16 = (PUSHORT)Offset;
1160 *pValue16 += Delta32 >> 16;
1161 break;
1162
1163 case TYPE_RELOC_LOW:
1164 pValue16 = (PUSHORT)Offset;
1165 *pValue16 += Delta32 & 0xffff;
1166 break;
1167
1168 case TYPE_RELOC_HIGHLOW:
1169 pValue32 = (PULONG)Offset;
1170 *pValue32 += Delta32;
1171 break;
1172
1173 case TYPE_RELOC_HIGHADJ:
1174 /* FIXME: do the highadjust fixup */
1175 DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
1176 return(STATUS_UNSUCCESSFUL);
1177
1178 default:
1179 DPRINT("unexpected fixup type\n");
1180 return STATUS_UNSUCCESSFUL;
1181 }
1182 }
1183
1184 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1185 ImageBase +
1186 RelocationDir->VirtualAddress,
1187 PAGE_SIZE,
1188 OldProtect,
1189 &OldProtect);
1190 if (!NT_SUCCESS(Status))
1191 {
1192 DPRINT1("Failed to protect relocation target.\n");
1193 return(Status);
1194 }
1195
1196 if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
1197 {
1198 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1199 ImageBase +
1200 RelocationDir->VirtualAddress + PAGE_SIZE,
1201 PAGE_SIZE,
1202 OldProtect2,
1203 &OldProtect2);
1204 if (!NT_SUCCESS(Status))
1205 {
1206 DPRINT1("Failed to protect relocation target2.\n");
1207 return(Status);
1208 }
1209 }
1210
1211 RelocationRVA += RelocationDir->SizeOfBlock;
1212 RelocationDir =
1213 (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
1214 }
1215 }
1216 return STATUS_SUCCESS;
1217 }
1218
1219
1220 /**********************************************************************
1221 * NAME LOCAL
1222 * LdrFixupImports
1223 *
1224 * DESCRIPTION
1225 * Compute the entry point for every symbol the DLL imports
1226 * from other modules.
1227 *
1228 * ARGUMENTS
1229 *
1230 * RETURN VALUE
1231 *
1232 * REVISIONS
1233 *
1234 * NOTE
1235 *
1236 */
1237 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
1238 PVOID ImageBase)
1239 {
1240 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1241 ULONG Ordinal;
1242 PVOID BaseAddress;
1243 NTSTATUS Status;
1244 ULONG IATSize;
1245
1246 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
1247 ImageBase);
1248
1249 /*
1250 * Process each import module.
1251 */
1252 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
1253 ImageBase + NTHeaders->OptionalHeader
1254 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1255 .VirtualAddress);
1256 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
1257
1258 while (ImportModuleDirectory->dwRVAModuleName)
1259 {
1260 PVOID * ImportAddressList;
1261 PULONG FunctionNameList;
1262 UNICODE_STRING DllName;
1263 DWORD pName;
1264 WORD pHint;
1265 PVOID IATBase;
1266 ULONG OldProtect;
1267
1268 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
1269 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1270
1271 RtlCreateUnicodeStringFromAsciiz (&DllName,
1272 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1273
1274 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
1275 if (!NT_SUCCESS(Status))
1276 {
1277 Status = LdrLoadDll(NULL,
1278 0,
1279 &DllName,
1280 &BaseAddress);
1281 RtlFreeUnicodeString (&DllName);
1282 if (!NT_SUCCESS(Status))
1283 {
1284 DbgPrint("LdrFixupImports:failed to load %s\n"
1285 ,(PCHAR)(ImageBase
1286 + ImportModuleDirectory->dwRVAModuleName));
1287
1288 return Status;
1289 }
1290 }
1291
1292 /*
1293 * Get the import address list.
1294 */
1295 ImportAddressList = (PVOID *)(ImageBase
1296 + ImportModuleDirectory->dwRVAFunctionAddressList);
1297
1298 /*
1299 * Get the list of functions to import.
1300 */
1301 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1302 {
1303 FunctionNameList = (PULONG) (
1304 ImageBase
1305 + ImportModuleDirectory->dwRVAFunctionNameList
1306 );
1307 }
1308 else
1309 {
1310 FunctionNameList =
1311 (PULONG)(ImageBase
1312 + ImportModuleDirectory->dwRVAFunctionAddressList);
1313 }
1314
1315 /*
1316 * Get the size of IAT.
1317 */
1318 IATSize = 0;
1319 while (FunctionNameList[IATSize] != 0L)
1320 {
1321 IATSize++;
1322 }
1323
1324 /*
1325 * Unprotect the region we are about to write into.
1326 */
1327 IATBase = (PVOID)ImportAddressList;
1328 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1329 IATBase,
1330 IATSize * sizeof(PVOID*),
1331 PAGE_READWRITE,
1332 &OldProtect);
1333 if (!NT_SUCCESS(Status))
1334 {
1335 DbgPrint("LDR: Failed to unprotect IAT.\n");
1336 return(Status);
1337 }
1338
1339 /*
1340 * Walk through function list and fixup addresses.
1341 */
1342 while (*FunctionNameList != 0L)
1343 {
1344 if ((*FunctionNameList) & 0x80000000)
1345 {
1346 Ordinal = (*FunctionNameList) & 0x7fffffff;
1347 *ImportAddressList =
1348 LdrGetExportByOrdinal(BaseAddress,
1349 Ordinal);
1350 }
1351 else
1352 {
1353 pName = (DWORD) (ImageBase + *FunctionNameList + 2);
1354 pHint = *(PWORD)(ImageBase + *FunctionNameList);
1355
1356 *ImportAddressList =
1357 LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
1358 if ((*ImportAddressList) == NULL)
1359 {
1360 DbgPrint("Failed to import %s\n", pName);
1361 return STATUS_UNSUCCESSFUL;
1362 }
1363 }
1364 ImportAddressList++;
1365 FunctionNameList++;
1366 }
1367
1368 /*
1369 * Protect the region we are about to write into.
1370 */
1371 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1372 IATBase,
1373 IATSize * sizeof(PVOID*),
1374 OldProtect,
1375 &OldProtect);
1376 if (!NT_SUCCESS(Status))
1377 {
1378 DbgPrint("LDR: Failed to protect IAT.\n");
1379 return(Status);
1380 }
1381
1382 ImportModuleDirectory++;
1383 }
1384 return STATUS_SUCCESS;
1385 }
1386
1387
1388 /**********************************************************************
1389 * NAME
1390 * LdrPEStartup
1391 *
1392 * DESCRIPTION
1393 * 1. Map the DLL's sections into memory.
1394 * 2. Relocate, if needed the DLL.
1395 * 3. Fixup any imported symbol.
1396 * 4. Compute the DLL's entry point.
1397 *
1398 * ARGUMENTS
1399 * ImageBase
1400 * Address at which the DLL's image
1401 * is loaded.
1402 *
1403 * SectionHandle
1404 * Handle of the section that contains
1405 * the DLL's image.
1406 *
1407 * RETURN VALUE
1408 * NULL on error; otherwise the entry point
1409 * to call for initializing the DLL.
1410 *
1411 * REVISIONS
1412 *
1413 * NOTE
1414 *
1415 */
1416 PEPFUNC LdrPEStartup (PVOID ImageBase,
1417 HANDLE SectionHandle,
1418 PLDR_MODULE* Module,
1419 PWSTR FullDosName)
1420 {
1421 NTSTATUS Status;
1422 PEPFUNC EntryPoint = NULL;
1423 PIMAGE_DOS_HEADER DosHeader;
1424 PIMAGE_NT_HEADERS NTHeaders;
1425
1426 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1427 ImageBase, (ULONG)SectionHandle);
1428
1429 /*
1430 * Overlay DOS and WNT headers structures
1431 * to the DLL's image.
1432 */
1433 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1434 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
1435
1436 /*
1437 * If the base address is different from the
1438 * one the DLL is actually loaded, perform any
1439 * relocation.
1440 */
1441 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1442 {
1443 DbgPrint("LDR: Performing relocations\n");
1444 Status = LdrPerformRelocations(NTHeaders, ImageBase);
1445 if (!NT_SUCCESS(Status))
1446 {
1447 DbgPrint("LdrPerformRelocations() failed\n");
1448 return NULL;
1449 }
1450 }
1451
1452 if (Module != NULL)
1453 {
1454 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
1455 (*Module)->SectionHandle = SectionHandle;
1456 }
1457
1458 /*
1459 * If the DLL's imports symbols from other
1460 * modules, fixup the imported calls entry points.
1461 */
1462 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1463 .VirtualAddress != 0)
1464 {
1465 DPRINT("About to fixup imports\n");
1466 Status = LdrFixupImports(NTHeaders, ImageBase);
1467 if (!NT_SUCCESS(Status))
1468 {
1469 DbgPrint("LdrFixupImports() failed\n");
1470 return NULL;
1471 }
1472 DPRINT("Fixup done\n");
1473 }
1474
1475 /*
1476 * Compute the DLL's entry point's address.
1477 */
1478 DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
1479 DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
1480 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
1481 {
1482 EntryPoint = (PEPFUNC) (ImageBase
1483 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
1484 }
1485 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
1486 return EntryPoint;
1487 }
1488
1489
1490 /*
1491 * @implemented
1492 */
1493 NTSTATUS STDCALL
1494 LdrUnloadDll (IN PVOID BaseAddress)
1495 {
1496 PIMAGE_NT_HEADERS NtHeaders;
1497 PDLLMAIN_FUNC Entrypoint;
1498 PLIST_ENTRY ModuleListHead;
1499 PLIST_ENTRY Entry;
1500 PLDR_MODULE Module;
1501 NTSTATUS Status;
1502
1503 if (BaseAddress == NULL)
1504 return STATUS_SUCCESS;
1505
1506 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1507 Entry = ModuleListHead->Flink;
1508
1509 while (Entry != ModuleListHead)
1510 {
1511 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1512 if (Module->BaseAddress == BaseAddress)
1513 {
1514 if (Module->LoadCount == -1)
1515 {
1516 /* never unload this dll */
1517 return STATUS_SUCCESS;
1518 }
1519 else if (Module->LoadCount > 1)
1520 {
1521 Module->LoadCount--;
1522 return STATUS_SUCCESS;
1523 }
1524
1525 NtHeaders = RtlImageNtHeader (Module->BaseAddress);
1526 if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
1527 {
1528 if (Module->EntryPoint != 0)
1529 {
1530 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1531 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1532 Entrypoint(Module->BaseAddress,
1533 DLL_PROCESS_DETACH,
1534 NULL);
1535 }
1536 else
1537 {
1538 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1539 }
1540 }
1541 Status = ZwUnmapViewOfSection (NtCurrentProcess (),
1542 Module->BaseAddress);
1543 ZwClose (Module->SectionHandle);
1544
1545 /* remove the module entry from the list */
1546 RtlFreeUnicodeString (&Module->FullDllName);
1547 RtlFreeUnicodeString (&Module->BaseDllName);
1548 RemoveEntryList (Entry);
1549 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
1550
1551 return Status;
1552 }
1553
1554 Entry = Entry->Flink;
1555 }
1556
1557 DPRINT("NTDLL.LDR: Dll not found\n")
1558
1559 return STATUS_UNSUCCESSFUL;
1560 }
1561
1562
1563 /*
1564 * @implemented
1565 */
1566 NTSTATUS STDCALL
1567 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
1568 {
1569 PLIST_ENTRY ModuleListHead;
1570 PLIST_ENTRY Entry;
1571 PLDR_MODULE Module;
1572 NTSTATUS Status;
1573
1574 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress);
1575
1576 Status = STATUS_DLL_NOT_FOUND;
1577 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1578 Entry = ModuleListHead->Flink;
1579 while (Entry != ModuleListHead) {
1580 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1581
1582 DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module->BaseDllName, Module->BaseAddress);
1583
1584 if (Module->BaseAddress == BaseAddress) {
1585 if (Module->TlsIndex == 0) {
1586 Module->Flags |= 0x00040000;
1587 Status = STATUS_SUCCESS;
1588 }
1589 return Status;
1590 }
1591 Entry = Entry->Flink;
1592 }
1593 return Status;
1594 }
1595
1596
1597 /*
1598 * @implemented
1599 */
1600 NTSTATUS STDCALL
1601 LdrGetDllHandle(IN ULONG Unknown1,
1602 IN ULONG Unknown2,
1603 IN PUNICODE_STRING DllName,
1604 OUT PVOID* BaseAddress)
1605 {
1606 UNICODE_STRING FullDllName;
1607 PLIST_ENTRY ModuleListHead;
1608 PLIST_ENTRY Entry;
1609 PLDR_MODULE Module;
1610
1611 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1612 Unknown1, Unknown2, DllName, BaseAddress);
1613
1614 /* NULL is the current executable */
1615 if (DllName == NULL) {
1616 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
1617 DPRINT("BaseAddress %x\n", *BaseAddress);
1618 return STATUS_SUCCESS;
1619 }
1620 LdrAdjustDllName(&FullDllName, DllName, TRUE);
1621
1622 DPRINT("FullDllName %wZ\n", &FullDllName);
1623
1624 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1625 Entry = ModuleListHead->Flink;
1626 while (Entry != ModuleListHead) {
1627 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1628
1629 DPRINT("EntryPoint %x\n", Module->EntryPoint);
1630 DPRINT("Comparing %wZ and %wZ\n", &Module->BaseDllName, &FullDllName);
1631
1632 if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE)) {
1633 RtlFreeUnicodeString(&FullDllName);
1634 *BaseAddress = Module->BaseAddress;
1635 DPRINT("BaseAddress %x\n", *BaseAddress);
1636 return STATUS_SUCCESS;
1637 }
1638 Entry = Entry->Flink;
1639 }
1640
1641 DPRINT("Failed to find dll %wZ\n", &FullDllName);
1642
1643 RtlFreeUnicodeString(&FullDllName);
1644 *BaseAddress = NULL;
1645 return STATUS_DLL_NOT_FOUND;
1646 }
1647
1648
1649 /*
1650 * @implemented
1651 */
1652 NTSTATUS STDCALL
1653 LdrGetProcedureAddress (IN PVOID BaseAddress,
1654 IN PANSI_STRING Name,
1655 IN ULONG Ordinal,
1656 OUT PVOID *ProcedureAddress)
1657 {
1658 PIMAGE_EXPORT_DIRECTORY ExportDir;
1659 PUSHORT OrdinalPtr;
1660 PULONG NamePtr;
1661 PULONG AddressPtr;
1662 ULONG i = 0;
1663
1664 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1665 BaseAddress, Name, Ordinal, ProcedureAddress);
1666
1667 /* Get the pointer to the export directory */
1668 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1669 RtlImageDirectoryEntryToData (BaseAddress,
1670 TRUE,
1671 IMAGE_DIRECTORY_ENTRY_EXPORT,
1672 &i);
1673
1674 DPRINT("ExportDir %x i %lu\n", ExportDir, i);
1675
1676 if (!ExportDir || !i || !ProcedureAddress)
1677 {
1678 return STATUS_INVALID_PARAMETER;
1679 }
1680
1681 AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
1682 if (Name && Name->Length)
1683 {
1684 /* by name */
1685 OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
1686 NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
1687 for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
1688 {
1689 if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
1690 {
1691 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
1692 return STATUS_SUCCESS;
1693 }
1694 }
1695 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
1696 }
1697 else
1698 {
1699 /* by ordinal */
1700 Ordinal &= 0x0000FFFF;
1701 if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
1702 {
1703 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
1704 return STATUS_SUCCESS;
1705 }
1706 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
1707 }
1708
1709 return STATUS_PROCEDURE_NOT_FOUND;
1710 }
1711
1712
1713 /*
1714 * @implemented
1715 */
1716 NTSTATUS STDCALL
1717 LdrShutdownProcess (VOID)
1718 {
1719 PLIST_ENTRY ModuleListHead;
1720 PLIST_ENTRY Entry;
1721 PLDR_MODULE Module;
1722
1723 DPRINT("LdrShutdownProcess() called\n");
1724
1725 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1726
1727 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1728 Entry = ModuleListHead->Blink;
1729
1730 while (Entry != ModuleListHead)
1731 {
1732 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1733
1734 DPRINT(" Unloading %wZ\n",
1735 &Module->BaseDllName);
1736 // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1737 // they loaded dynamically, and when the last reference is gone, that lib will
1738 // be detached.
1739 if (Module->EntryPoint != 0 && Module->LoadCount == -1)
1740 {
1741 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1742
1743 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1744 Entrypoint (Module->BaseAddress,
1745 DLL_PROCESS_DETACH,
1746 NULL);
1747 }
1748
1749 Entry = Entry->Blink;
1750 }
1751
1752 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1753
1754 DPRINT("LdrShutdownProcess() done\n");
1755
1756 return STATUS_SUCCESS;
1757 }
1758
1759
1760 /*
1761 * @implemented
1762 */
1763 NTSTATUS STDCALL
1764 LdrShutdownThread (VOID)
1765 {
1766 PLIST_ENTRY ModuleListHead;
1767 PLIST_ENTRY Entry;
1768 PLDR_MODULE Module;
1769
1770 DPRINT("LdrShutdownThread() called\n");
1771
1772 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1773
1774 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1775 Entry = ModuleListHead->Blink;
1776
1777 while (Entry != ModuleListHead)
1778 {
1779 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1780
1781 DPRINT(" Unloading %wZ\n",
1782 &Module->BaseDllName);
1783
1784 if (Module->EntryPoint != 0)
1785 {
1786 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1787
1788 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1789 Entrypoint (Module->BaseAddress,
1790 DLL_THREAD_DETACH,
1791 NULL);
1792 }
1793
1794 Entry = Entry->Blink;
1795 }
1796
1797 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1798
1799 DPRINT("LdrShutdownThread() done\n");
1800
1801 return STATUS_SUCCESS;
1802 }
1803
1804
1805 /***************************************************************************
1806 * NAME EXPORTED
1807 * LdrQueryProcessModuleInformation
1808 *
1809 * DESCRIPTION
1810 *
1811 * ARGUMENTS
1812 *
1813 * RETURN VALUE
1814 *
1815 * REVISIONS
1816 *
1817 * NOTE
1818 *
1819 * @implemented
1820 */
1821 NTSTATUS STDCALL
1822 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
1823 IN ULONG Size OPTIONAL,
1824 OUT PULONG ReturnedSize)
1825 {
1826 PLIST_ENTRY ModuleListHead;
1827 PLIST_ENTRY Entry;
1828 PLDR_MODULE Module;
1829 PMODULE_ENTRY ModulePtr = NULL;
1830 NTSTATUS Status = STATUS_SUCCESS;
1831 ULONG UsedSize = sizeof(ULONG);
1832 ANSI_STRING AnsiString;
1833 PCHAR p;
1834
1835 DPRINT("LdrQueryProcessModuleInformation() called\n");
1836
1837 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1838
1839 if (ModuleInformation == NULL || Size == 0)
1840 {
1841 Status = STATUS_INFO_LENGTH_MISMATCH;
1842 }
1843 else
1844 {
1845 ModuleInformation->ModuleCount = 0;
1846 ModulePtr = &ModuleInformation->ModuleEntry[0];
1847 Status = STATUS_SUCCESS;
1848 }
1849
1850 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1851 Entry = ModuleListHead->Flink;
1852
1853 while (Entry != ModuleListHead)
1854 {
1855 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1856
1857 DPRINT(" Module %wZ\n",
1858 &Module->FullDllName);
1859
1860 if (UsedSize > Size)
1861 {
1862 Status = STATUS_INFO_LENGTH_MISMATCH;
1863 }
1864 else if (ModuleInformation != NULL)
1865 {
1866 ModulePtr->Unknown0 = 0; // FIXME: ??
1867 ModulePtr->Unknown1 = 0; // FIXME: ??
1868 ModulePtr->BaseAddress = Module->BaseAddress;
1869 ModulePtr->SizeOfImage = Module->SizeOfImage;
1870 ModulePtr->Flags = Module->Flags;
1871 ModulePtr->Unknown2 = 0; // FIXME: load order index ??
1872 ModulePtr->Unknown3 = 0; // FIXME: ??
1873 ModulePtr->LoadCount = Module->LoadCount;
1874
1875 AnsiString.Length = 0;
1876 AnsiString.MaximumLength = 256;
1877 AnsiString.Buffer = ModulePtr->ModuleName;
1878 RtlUnicodeStringToAnsiString(&AnsiString,
1879 &Module->FullDllName,
1880 FALSE);
1881 p = strrchr(ModulePtr->ModuleName, '\\');
1882 if (p != NULL)
1883 ModulePtr->PathLength = p - ModulePtr->ModuleName + 1;
1884 else
1885 ModulePtr->PathLength = 0;
1886
1887 ModulePtr++;
1888 ModuleInformation->ModuleCount++;
1889 }
1890 UsedSize += sizeof(MODULE_ENTRY);
1891
1892 Entry = Entry->Flink;
1893 }
1894
1895 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1896
1897 if (ReturnedSize != 0)
1898 *ReturnedSize = UsedSize;
1899
1900 DPRINT("LdrQueryProcessModuleInformation() done\n");
1901
1902 return(Status);
1903 }
1904
1905
1906 static BOOLEAN
1907 LdrpCheckImageChecksum (IN PVOID BaseAddress,
1908 IN ULONG ImageSize)
1909 {
1910 PIMAGE_NT_HEADERS Header;
1911 PUSHORT Ptr;
1912 ULONG Sum;
1913 ULONG CalcSum;
1914 ULONG HeaderSum;
1915 ULONG i;
1916
1917 Header = RtlImageNtHeader (BaseAddress);
1918 if (Header == NULL)
1919 return FALSE;
1920
1921 HeaderSum = Header->OptionalHeader.CheckSum;
1922 if (HeaderSum == 0)
1923 return TRUE;
1924
1925 Sum = 0;
1926 Ptr = (PUSHORT) BaseAddress;
1927 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
1928 {
1929 Sum += (ULONG)*Ptr;
1930 if (HIWORD(Sum) != 0)
1931 {
1932 Sum = LOWORD(Sum) + HIWORD(Sum);
1933 }
1934 Ptr++;
1935 }
1936
1937 if (ImageSize & 1)
1938 {
1939 Sum += (ULONG)*((PUCHAR)Ptr);
1940 if (HIWORD(Sum) != 0)
1941 {
1942 Sum = LOWORD(Sum) + HIWORD(Sum);
1943 }
1944 }
1945
1946 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
1947
1948 /* Subtract image checksum from calculated checksum. */
1949 /* fix low word of checksum */
1950 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
1951 {
1952 CalcSum -= LOWORD(HeaderSum);
1953 }
1954 else
1955 {
1956 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
1957 }
1958
1959 /* fix high word of checksum */
1960 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
1961 {
1962 CalcSum -= HIWORD(HeaderSum);
1963 }
1964 else
1965 {
1966 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
1967 }
1968
1969 /* add file length */
1970 CalcSum += ImageSize;
1971
1972 return (BOOLEAN)(CalcSum == HeaderSum);
1973 }
1974
1975
1976 /***************************************************************************
1977 * NAME EXPORTED
1978 * LdrVerifyImageMatchesChecksum
1979 *
1980 * DESCRIPTION
1981 *
1982 * ARGUMENTS
1983 *
1984 * RETURN VALUE
1985 *
1986 * REVISIONS
1987 *
1988 * NOTE
1989 *
1990 * @implemented
1991 */
1992 NTSTATUS STDCALL
1993 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
1994 ULONG Unknown1,
1995 ULONG Unknown2,
1996 ULONG Unknown3)
1997 {
1998 FILE_STANDARD_INFORMATION FileInfo;
1999 IO_STATUS_BLOCK IoStatusBlock;
2000 HANDLE SectionHandle;
2001 ULONG ViewSize;
2002 PVOID BaseAddress;
2003 BOOLEAN Result;
2004 NTSTATUS Status;
2005
2006 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2007
2008 Status = NtCreateSection (&SectionHandle,
2009 SECTION_MAP_EXECUTE,
2010 NULL,
2011 NULL,
2012 PAGE_EXECUTE,
2013 SEC_COMMIT,
2014 FileHandle);
2015 if (!NT_SUCCESS(Status))
2016 {
2017 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
2018 return Status;
2019 }
2020
2021 ViewSize = 0;
2022 BaseAddress = NULL;
2023 Status = NtMapViewOfSection (SectionHandle,
2024 NtCurrentProcess (),
2025 &BaseAddress,
2026 0,
2027 0,
2028 NULL,
2029 &ViewSize,
2030 ViewShare,
2031 0,
2032 PAGE_EXECUTE);
2033 if (!NT_SUCCESS(Status))
2034 {
2035 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
2036 NtClose (SectionHandle);
2037 return Status;
2038 }
2039
2040 Status = NtQueryInformationFile (FileHandle,
2041 &IoStatusBlock,
2042 &FileInfo,
2043 sizeof (FILE_STANDARD_INFORMATION),
2044 FileStandardInformation);
2045 if (!NT_SUCCESS(Status))
2046 {
2047 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
2048 NtUnmapViewOfSection (NtCurrentProcess (),
2049 BaseAddress);
2050 NtClose (SectionHandle);
2051 return Status;
2052 }
2053
2054 Result = LdrpCheckImageChecksum (BaseAddress,
2055 FileInfo.EndOfFile.u.LowPart);
2056 if (Result == FALSE)
2057 {
2058 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2059 }
2060
2061 NtUnmapViewOfSection (NtCurrentProcess (),
2062 BaseAddress);
2063
2064 NtClose (SectionHandle);
2065
2066 return Status;
2067 }
2068
2069
2070 /***************************************************************************
2071 * NAME EXPORTED
2072 * LdrQueryImageFileExecutionOptions
2073 *
2074 * DESCRIPTION
2075 *
2076 * ARGUMENTS
2077 *
2078 * RETURN VALUE
2079 *
2080 * REVISIONS
2081 *
2082 * NOTE
2083 *
2084 * @implemented
2085 */
2086 NTSTATUS STDCALL
2087 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
2088 IN PCWSTR ValueName,
2089 IN ULONG ValueSize,
2090 OUT PVOID Buffer,
2091 IN ULONG BufferSize,
2092 OUT PULONG ReturnedLength OPTIONAL)
2093 {
2094 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
2095 OBJECT_ATTRIBUTES ObjectAttributes;
2096 UNICODE_STRING ValueNameString;
2097 UNICODE_STRING ValueString;
2098 UNICODE_STRING KeyName;
2099 WCHAR NameBuffer[256];
2100 HANDLE KeyHandle;
2101 ULONG KeyInfoSize;
2102 ULONG ResultSize;
2103 PWCHAR Ptr;
2104 NTSTATUS Status;
2105
2106 wcscpy (NameBuffer,
2107 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2108 Ptr = wcsrchr (SubKey->Buffer, L'\\');
2109 if (Ptr == NULL)
2110 {
2111 Ptr = SubKey->Buffer;
2112 }
2113 else
2114 {
2115 Ptr++;
2116 }
2117 wcscat (NameBuffer, Ptr);
2118 RtlInitUnicodeString (&KeyName,
2119 NameBuffer);
2120
2121 InitializeObjectAttributes (&ObjectAttributes,
2122 &KeyName,
2123 OBJ_CASE_INSENSITIVE,
2124 NULL,
2125 NULL);
2126
2127 Status = NtOpenKey (&KeyHandle,
2128 KEY_READ,
2129 &ObjectAttributes);
2130 if (!NT_SUCCESS(Status))
2131 {
2132 DPRINT1 ("NtOpenKey() failed (Status %lx)\n", Status);
2133 return Status;
2134 }
2135
2136 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
2137 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
2138 HEAP_ZERO_MEMORY,
2139 KeyInfoSize);
2140
2141 RtlInitUnicodeString (&ValueNameString,
2142 (PWSTR)ValueName);
2143 Status = NtQueryValueKey (KeyHandle,
2144 &ValueNameString,
2145 KeyValuePartialInformation,
2146 KeyInfo,
2147 KeyInfoSize,
2148 &ResultSize);
2149 if (Status == STATUS_BUFFER_OVERFLOW)
2150 {
2151 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
2152 RtlFreeHeap (RtlGetProcessHeap(),
2153 0,
2154 KeyInfo);
2155 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
2156 HEAP_ZERO_MEMORY,
2157 KeyInfoSize);
2158 if (KeyInfo == NULL)
2159 {
2160 NtClose (KeyHandle);
2161 return Status;
2162 }
2163
2164 Status = NtQueryValueKey (KeyHandle,
2165 &ValueNameString,
2166 KeyValuePartialInformation,
2167 KeyInfo,
2168 KeyInfoSize,
2169 &ResultSize);
2170 }
2171 NtClose (KeyHandle);
2172
2173 if (!NT_SUCCESS(Status))
2174 {
2175 if (KeyInfo != NULL)
2176 {
2177 RtlFreeHeap (RtlGetProcessHeap(),
2178 0,
2179 KeyInfo);
2180 }
2181 return Status;
2182 }
2183
2184 if (KeyInfo->Type != REG_SZ)
2185 {
2186 RtlFreeHeap (RtlGetProcessHeap(),
2187 0,
2188 KeyInfo);
2189 return STATUS_OBJECT_TYPE_MISMATCH;
2190 }
2191
2192 if (ValueSize == sizeof(ULONG))
2193 {
2194 if (BufferSize != sizeof(ULONG))
2195 {
2196 ResultSize = 0;
2197 Status = STATUS_INFO_LENGTH_MISMATCH;
2198 }
2199 else
2200 {
2201 ResultSize = sizeof(ULONG);
2202 ValueString.Length = (USHORT)KeyInfo->DataLength - sizeof(WCHAR);
2203 ValueString.MaximumLength = (USHORT)KeyInfo->DataLength;
2204 ValueString.Buffer = (PWSTR)&KeyInfo->Data;
2205 Status = RtlUnicodeStringToInteger (&ValueString,
2206 0,
2207 Buffer);
2208 }
2209 }
2210 else
2211 {
2212 ResultSize = BufferSize;
2213 if (ResultSize < KeyInfo->DataLength)
2214 {
2215 Status = STATUS_BUFFER_OVERFLOW;
2216 }
2217 else
2218 {
2219 ResultSize = KeyInfo->DataLength;
2220 }
2221 RtlCopyMemory (Buffer,
2222 &KeyInfo->Data,
2223 ResultSize);
2224 }
2225
2226 RtlFreeHeap (RtlGetProcessHeap(),
2227 0,
2228 KeyInfo);
2229
2230 if (ReturnedLength != NULL)
2231 {
2232 *ReturnedLength = ResultSize;
2233 }
2234
2235 return Status;
2236 }
2237
2238 /* EOF */