update for HEAD-2003091401
[reactos.git] / lib / ntdll / ldr / utils.c
1 /* $Id$
2  * 
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            lib/ntdll/ldr/utils.c
6  * PURPOSE:         Process startup for PE executables
7  * PROGRAMMERS:     Jean Michault
8  *                  Rex Jolliff (rex@lvcablemodem.com)
9  */
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   memset(Module, 0, sizeof(LDR_MODULE));
238   Module->BaseAddress = (PVOID)ImageBase;
239   Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
240   if (Module->EntryPoint != 0)
241     Module->EntryPoint += (ULONG)Module->BaseAddress;
242   Module->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
243   if (NtCurrentPeb()->Ldr->Initialized == TRUE)
244     {
245       /* loading while app is running */
246       Module->LoadCount = 1;
247     } else {
248       /*
249        * loading while app is initializing
250        * dll must not be unloaded
251        */
252       Module->LoadCount = -1;
253     }
254
255   Module->TlsIndex = 0;
256   Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
257   Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
258
259   RtlCreateUnicodeString (&Module->FullDllName,
260                           FullDosName);
261   RtlCreateUnicodeString (&Module->BaseDllName,
262                           wcsrchr(FullDosName, L'\\') + 1);
263   DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
264   
265   RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
266   InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
267                  &Module->InLoadOrderModuleList);
268   InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
269                  &Module->InInitializationOrderModuleList);
270   RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
271
272   return(Module);
273 }
274
275
276 static NTSTATUS
277 LdrpMapKnownDll(IN PUNICODE_STRING DllName,
278                 OUT PUNICODE_STRING FullDosName,
279                 OUT PHANDLE SectionHandle)
280 {
281   OBJECT_ATTRIBUTES ObjectAttributes;
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       *BaseAddress = Module->BaseAddress;
527       return STATUS_SUCCESS;
528     }
529   DPRINT("Loading \"%wZ\"\n", Name);
530
531   /* Open or create dll image section */
532   Status = LdrpMapKnownDll(&AdjustedName,
533                            &FullDosName,
534                            &SectionHandle);
535   if (!NT_SUCCESS(Status))
536     {
537       Status = LdrpMapDllImageFile(SearchPath,
538                                    &AdjustedName,
539                                    &FullDosName,
540                                    &SectionHandle);
541     }
542
543   RtlFreeUnicodeString(&AdjustedName);
544
545   if (!NT_SUCCESS(Status))
546     {
547       DPRINT1("Failed to create or open dll section (Status %lx)\n", Status);
548       return Status;
549     }
550
551   /*
552    * Map the dll into the process.
553    */
554   ViewSize = 0;
555   ImageBase = 0;
556   Status = NtMapViewOfSection(SectionHandle,
557                               NtCurrentProcess(),
558                               &ImageBase,
559                               0,
560                               0,
561                               NULL,
562                               &ViewSize,
563                               0,
564                               MEM_COMMIT,
565                               PAGE_READWRITE);
566   if (!NT_SUCCESS(Status))
567     {
568       DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n", Status);
569       RtlFreeUnicodeString(&FullDosName);
570       NtClose(SectionHandle);
571       return(Status);
572     }
573
574   /* Get and check the NT headers */
575   NTHeaders = RtlImageNtHeader(ImageBase);
576   if (NTHeaders == NULL)
577     {
578       DPRINT1("RtlImageNtHeaders() failed\n");
579       RtlFreeUnicodeString(&FullDosName);
580       return STATUS_UNSUCCESSFUL;
581     }
582
583   /* relocate dll and fixup import table */
584   if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
585       IMAGE_FILE_DLL)
586     {
587       Entrypoint =
588         (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle, &Module,
589                                      FullDosName.Buffer);
590       if (Entrypoint == NULL)
591         {
592           RtlFreeUnicodeString(&FullDosName);
593           return(STATUS_UNSUCCESSFUL);
594         }
595     }
596
597   RtlFreeUnicodeString(&FullDosName);
598
599 #ifdef DBG
600
601   LdrpLoadUserModuleSymbols(Module);
602
603 #endif /* DBG */
604
605   /* initialize dll */
606   if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
607       IMAGE_FILE_DLL)
608     {
609       if (Module->EntryPoint != 0)
610         {
611           Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
612           
613           DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
614           if (FALSE == Entrypoint(Module->BaseAddress,
615                                   DLL_PROCESS_ATTACH,
616                                   NULL))
617             {
618               /* Do this as a DPRINT1 for now, until clean up and fail implemented */
619               DPRINT1("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
620                      &Module->BaseDllName);
621               /* FIXME: should clean up and fail */
622             }
623           else
624             {
625               DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
626                      &Module->BaseDllName);
627             }
628         }
629       else
630         {
631           DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
632                  &Module->BaseDllName);
633         }
634     }
635
636   *BaseAddress = Module->BaseAddress;
637   return STATUS_SUCCESS;
638 }
639
640
641 /***************************************************************************
642  * NAME                                                         EXPORTED
643  *      LdrFindEntryForAddress
644  *
645  * DESCRIPTION
646  *
647  * ARGUMENTS
648  *
649  * RETURN VALUE
650  *
651  * REVISIONS
652  *
653  * NOTE
654  *
655  * @implemented
656  */
657 NTSTATUS STDCALL
658 LdrFindEntryForAddress(PVOID Address,
659                        PLDR_MODULE *Module)
660 {
661   PLIST_ENTRY ModuleListHead;
662   PLIST_ENTRY Entry;
663   PLDR_MODULE ModulePtr;
664
665   DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address);
666
667   if (NtCurrentPeb()->Ldr == NULL)
668     return(STATUS_NO_MORE_ENTRIES);
669
670   RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
671   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
672   Entry = ModuleListHead->Flink;
673   if (Entry == ModuleListHead)
674     {
675       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
676       return(STATUS_NO_MORE_ENTRIES);
677     }
678
679   while (Entry != ModuleListHead)
680     {
681       ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
682
683       DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->BaseAddress);
684
685       if ((Address >= ModulePtr->BaseAddress) &&
686           (Address <= (ModulePtr->BaseAddress + ModulePtr->SizeOfImage)))
687         {
688           *Module = ModulePtr;
689           RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
690           return(STATUS_SUCCESS);
691         }
692
693       Entry = Entry->Flink;
694     }
695
696   DPRINT("Failed to find module entry.\n");
697
698   RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
699   return(STATUS_NO_MORE_ENTRIES);
700 }
701
702
703 /***************************************************************************
704  * NAME                                                         LOCAL
705  *      LdrFindEntryForName
706  *
707  * DESCRIPTION
708  *
709  * ARGUMENTS
710  *
711  * RETURN VALUE
712  *
713  * REVISIONS
714  *
715  * NOTE
716  *
717  */
718 static NTSTATUS
719 LdrFindEntryForName(PUNICODE_STRING Name,
720                     PLDR_MODULE *Module)
721 {
722   PLIST_ENTRY ModuleListHead;
723   PLIST_ENTRY Entry;
724   PLDR_MODULE ModulePtr;
725   BOOLEAN ContainsPath;
726   unsigned i;
727
728   DPRINT("NTDLL.LdrFindEntryForName(Name %wZ)\n", Name);
729
730   if (NtCurrentPeb()->Ldr == NULL)
731     return(STATUS_NO_MORE_ENTRIES);
732
733   RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
734   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
735   Entry = ModuleListHead->Flink;
736   if (Entry == ModuleListHead)
737     {
738       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
739       return(STATUS_NO_MORE_ENTRIES);
740     }
741
742   // NULL is the current process
743   if (Name == NULL)
744     {
745       *Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
746       if ((*Module)->LoadCount != -1)
747         (*Module)->LoadCount++;
748
749       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
750       return(STATUS_SUCCESS);
751     }
752
753   ContainsPath = (Name->Length >= 2 * sizeof(WCHAR) && L':' == Name->Buffer[1]);
754   for (i = 0; ! ContainsPath && i < Name->Length / sizeof(WCHAR); i++)
755     {
756     ContainsPath = L'\\' == Name->Buffer[i] ||
757                    L'/' == Name->Buffer[i];
758     }
759   while (Entry != ModuleListHead)
760     {
761       ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
762
763       DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, Name);
764
765       if ((! ContainsPath &&
766            0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, Name, TRUE)) ||
767           (ContainsPath &&
768            0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, Name, TRUE)))
769         {
770           *Module = ModulePtr;
771           if (ModulePtr->LoadCount != -1)
772             ModulePtr->LoadCount++;
773           RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
774           return(STATUS_SUCCESS);
775         }
776
777       Entry = Entry->Flink;
778     }
779
780   DPRINT("Failed to find dll %wZ\n", Name);
781   RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
782   return(STATUS_NO_MORE_ENTRIES);
783 }
784
785 /**********************************************************************
786  * NAME                                                         LOCAL
787  *      LdrFixupForward
788  *
789  * DESCRIPTION
790  *
791  * ARGUMENTS
792  *
793  * RETURN VALUE
794  *
795  * REVISIONS
796  *
797  * NOTE
798  *
799  */
800 static PVOID
801 LdrFixupForward(PCHAR ForwardName)
802 {
803    CHAR NameBuffer[128];
804    UNICODE_STRING DllName;
805    NTSTATUS Status;
806    PCHAR p;
807    PVOID BaseAddress;
808
809    strcpy(NameBuffer, ForwardName);
810    p = strchr(NameBuffer, '.');
811    if (p != NULL)
812      {
813         *p = 0;
814
815         DPRINT("Dll: %s  Function: %s\n", NameBuffer, p+1);
816         RtlCreateUnicodeStringFromAsciiz (&DllName,
817                                           NameBuffer);
818
819         Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
820         if (!NT_SUCCESS(Status))
821           {
822              Status = LdrLoadDll(NULL,
823                                  0,
824                                  &DllName,
825                                  &BaseAddress);
826              if (!NT_SUCCESS(Status))
827                {
828                   DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
829                   RtlFreeUnicodeString (&DllName);
830                   return NULL;
831                }
832           }
833
834         RtlFreeUnicodeString (&DllName);
835         DPRINT("BaseAddress: %p\n", BaseAddress);
836         
837         return LdrGetExportByName(BaseAddress, p+1, -1);
838      }
839
840    return NULL;
841 }
842
843
844 /**********************************************************************
845  * NAME                                                         LOCAL
846  *      LdrGetExportByOrdinal
847  *      
848  * DESCRIPTION
849  *
850  * ARGUMENTS
851  *
852  * RETURN VALUE
853  *
854  * REVISIONS
855  *
856  * NOTE
857  *
858  */
859 static PVOID
860 LdrGetExportByOrdinal (
861         PVOID   BaseAddress,
862         ULONG   Ordinal
863         )
864 {
865         PIMAGE_EXPORT_DIRECTORY ExportDir;
866         PDWORD                  * ExFunctions;
867         USHORT                  * ExOrdinals;
868
869         ExportDir = (PIMAGE_EXPORT_DIRECTORY)
870                 RtlImageDirectoryEntryToData (BaseAddress,
871                                               TRUE,
872                                               IMAGE_DIRECTORY_ENTRY_EXPORT,
873                                               NULL);
874
875
876         ExOrdinals = (USHORT *)
877                 RVA(
878                         BaseAddress,
879                         ExportDir->AddressOfNameOrdinals
880                         );
881         ExFunctions = (PDWORD *)
882                 RVA(
883                         BaseAddress,
884                         ExportDir->AddressOfFunctions
885                         );
886         DbgPrint(
887                 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
888                 Ordinal,
889                 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
890                 );
891         return(RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] ));
892 }
893
894
895 /**********************************************************************
896  * NAME                                                         LOCAL
897  *      LdrGetExportByName
898  *      
899  * DESCRIPTION
900  *
901  * ARGUMENTS
902  *
903  * RETURN VALUE
904  *
905  * REVISIONS
906  *
907  * NOTE
908  *  AddressOfNames and AddressOfNameOrdinals are paralell tables, 
909  *  both with NumberOfNames entries.
910  *
911  */
912 static PVOID
913 LdrGetExportByName(PVOID BaseAddress,
914                    PUCHAR SymbolName,
915                    WORD Hint)
916 {
917    PIMAGE_EXPORT_DIRECTORY      ExportDir;
918    PDWORD                       * ExFunctions;
919    PDWORD                       * ExNames;
920    USHORT                       * ExOrdinals;
921    ULONG                        i;
922    PVOID                        ExName;
923    ULONG                        Ordinal;
924    PVOID                        Function;
925    ULONG minn, maxn;
926    ULONG ExportDirSize;
927    
928    DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
929
930    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
931      RtlImageDirectoryEntryToData(BaseAddress,
932                                   TRUE,
933                                   IMAGE_DIRECTORY_ENTRY_EXPORT,
934                                   &ExportDirSize);
935    if (ExportDir == NULL)
936      {
937         DbgPrint("LdrGetExportByName(): no export directory!\n");
938         return NULL;
939      }
940
941
942    //The symbol names may be missing entirely
943    if (ExportDir->AddressOfNames == 0)
944    {
945       DPRINT("LdrGetExportByName(): symbol names missing entirely\n");  
946       return NULL;
947    }
948
949    /*
950     * Get header pointers
951     */
952    ExNames = (PDWORD *)RVA(BaseAddress,
953                            ExportDir->AddressOfNames);
954    ExOrdinals = (USHORT *)RVA(BaseAddress,
955                               ExportDir->AddressOfNameOrdinals);
956    ExFunctions = (PDWORD *)RVA(BaseAddress,
957                                ExportDir->AddressOfFunctions);
958    
959    /*
960     * Check the hint first
961     */
962    if (Hint < ExportDir->NumberOfNames)
963      {
964         ExName = RVA(BaseAddress, ExNames[Hint]);
965         if (strcmp(ExName, SymbolName) == 0)
966           {
967              Ordinal = ExOrdinals[Hint];
968              Function = RVA(BaseAddress, ExFunctions[Ordinal]);
969              if (((ULONG)Function >= (ULONG)ExportDir) &&
970                  ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
971                {
972                   DPRINT("Forward: %s\n", (PCHAR)Function);
973                   Function = LdrFixupForward((PCHAR)Function);
974                }
975              if (Function != NULL)
976                return Function;
977           }
978      }
979    
980    /*
981     * Try a binary search first
982     */
983    minn = 0;
984    maxn = ExportDir->NumberOfNames;
985    while (minn <= maxn)
986      {
987         ULONG mid;
988         LONG res;
989
990         mid = (minn + maxn) / 2;
991
992         ExName = RVA(BaseAddress, ExNames[mid]);
993         res = strcmp(ExName, SymbolName);
994         if (res == 0)
995           {
996              Ordinal = ExOrdinals[mid];
997              Function = RVA(BaseAddress, ExFunctions[Ordinal]);
998              if (((ULONG)Function >= (ULONG)ExportDir) &&
999                  ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
1000                {
1001                   DPRINT("Forward: %s\n", (PCHAR)Function);
1002                   Function = LdrFixupForward((PCHAR)Function);
1003                }
1004              if (Function != NULL)
1005                return Function;
1006           }
1007         else if (minn == maxn)
1008           {
1009              DPRINT("LdrGetExportByName(): binary search failed\n");
1010              break;
1011           }
1012         else if (res > 0)
1013           {
1014              maxn = mid - 1;
1015           }
1016         else
1017           {
1018              minn = mid + 1;
1019           }
1020      }
1021    
1022    /*
1023     * Fall back on a linear search
1024     */
1025    DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
1026    for (i = 0; i < ExportDir->NumberOfNames; i++)
1027      {
1028         ExName = RVA(BaseAddress, ExNames[i]);
1029         if (strcmp(ExName,SymbolName) == 0)
1030           {
1031              Ordinal = ExOrdinals[i];
1032              Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1033              DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
1034              if (((ULONG)Function >= (ULONG)ExportDir) &&
1035                  ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
1036                {
1037                   DPRINT("Forward: %s\n", (PCHAR)Function);
1038                   Function = LdrFixupForward((PCHAR)Function);
1039                }
1040              return Function;
1041           }
1042      }
1043    DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
1044    return NULL;
1045 }
1046
1047
1048 /**********************************************************************
1049  * NAME                                                         LOCAL
1050  *      LdrPerformRelocations
1051  *      
1052  * DESCRIPTION
1053  *      Relocate a DLL's memory image.
1054  *      
1055  * ARGUMENTS
1056  *
1057  * RETURN VALUE
1058  *
1059  * REVISIONS
1060  *
1061  * NOTE
1062  *
1063  */
1064 static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS        NTHeaders,
1065                                        PVOID                    ImageBase)
1066 {
1067   USHORT                        NumberOfEntries;
1068   PUSHORT                       pValue16;
1069   ULONG                 RelocationRVA;
1070   ULONG                 Delta32;
1071   ULONG                 Offset;
1072   PULONG                        pValue32;
1073   PRELOCATION_DIRECTORY RelocationDir;
1074   PRELOCATION_ENTRY     RelocationBlock;
1075   int                   i;
1076   PIMAGE_DATA_DIRECTORY RelocationDDir;
1077   ULONG OldProtect;
1078   ULONG OldProtect2;
1079   NTSTATUS Status;
1080   PIMAGE_SECTION_HEADER Sections;
1081   ULONG MaxExtend;
1082
1083   if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1084     {
1085       return STATUS_UNSUCCESSFUL;
1086     }
1087
1088   Sections = 
1089     (PIMAGE_SECTION_HEADER)((PVOID)NTHeaders + sizeof(IMAGE_NT_HEADERS));
1090   MaxExtend = 0;
1091   for (i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++)
1092     {
1093       if (!(Sections[i].Characteristics & IMAGE_SECTION_NOLOAD))
1094         {
1095           ULONG Extend;
1096           Extend = 
1097             (ULONG)(Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize);
1098           MaxExtend = max(MaxExtend, Extend);
1099         }
1100     }
1101   
1102   RelocationDDir = 
1103     &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1104   RelocationRVA = RelocationDDir->VirtualAddress;
1105
1106   if (RelocationRVA)
1107     {
1108       RelocationDir = 
1109         (PRELOCATION_DIRECTORY)((PCHAR)ImageBase + RelocationRVA);
1110
1111       while (RelocationDir->SizeOfBlock)
1112         {
1113           if (RelocationDir->VirtualAddress > MaxExtend)
1114             {
1115               RelocationRVA += RelocationDir->SizeOfBlock;
1116               RelocationDir = 
1117                 (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
1118               continue;
1119             }
1120
1121           Delta32 = (ULONG)(ImageBase - NTHeaders->OptionalHeader.ImageBase);
1122           RelocationBlock = 
1123             (PRELOCATION_ENTRY) (RelocationRVA + ImageBase + 
1124                                  sizeof (RELOCATION_DIRECTORY));          
1125           NumberOfEntries = 
1126             RelocationDir->SizeOfBlock - sizeof (RELOCATION_DIRECTORY);
1127           NumberOfEntries = NumberOfEntries / sizeof (RELOCATION_ENTRY);
1128
1129           Status = NtProtectVirtualMemory(NtCurrentProcess(),
1130                                           ImageBase + 
1131                                           RelocationDir->VirtualAddress,
1132                                           PAGE_SIZE,
1133                                           PAGE_READWRITE,
1134                                           &OldProtect);
1135           if (!NT_SUCCESS(Status))
1136             {
1137               DPRINT1("Failed to unprotect relocation target.\n");
1138               return(Status);
1139             }
1140
1141           if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
1142             {
1143                   Status = NtProtectVirtualMemory(NtCurrentProcess(),
1144                                                   ImageBase + 
1145                                                   RelocationDir->VirtualAddress + PAGE_SIZE,
1146                                                   PAGE_SIZE,
1147                                                   PAGE_READWRITE,
1148                                                   &OldProtect2);
1149                   if (!NT_SUCCESS(Status))
1150                     {
1151                       DPRINT1("Failed to unprotect relocation target (2).\n");
1152                   NtProtectVirtualMemory(NtCurrentProcess(),
1153                                         ImageBase + 
1154                                         RelocationDir->VirtualAddress,
1155                                         PAGE_SIZE,
1156                                         OldProtect,
1157                                         &OldProtect);
1158                       return(Status);
1159                     }
1160               }
1161                 
1162           for (i = 0; i < NumberOfEntries; i++)
1163             {
1164               Offset = (RelocationBlock[i].TypeOffset & 0xfff);
1165               Offset += (ULONG)(RelocationDir->VirtualAddress + ImageBase);
1166
1167               /*
1168                * What kind of relocations should we perform
1169                * for the current entry?
1170                */
1171               switch (RelocationBlock[i].TypeOffset >> 12)
1172                 {
1173                 case TYPE_RELOC_ABSOLUTE:
1174                   break;
1175                   
1176                 case TYPE_RELOC_HIGH:
1177                   pValue16 = (PUSHORT)Offset;
1178                   *pValue16 += Delta32 >> 16;
1179                   break;
1180                   
1181                 case TYPE_RELOC_LOW:
1182                   pValue16 = (PUSHORT)Offset;
1183                   *pValue16 += Delta32 & 0xffff;
1184                   break;
1185                   
1186                 case TYPE_RELOC_HIGHLOW:
1187                   pValue32 = (PULONG)Offset;
1188                   *pValue32 += Delta32;
1189                   break;
1190                           
1191                 case TYPE_RELOC_HIGHADJ:
1192                   /* FIXME: do the highadjust fixup  */
1193                   DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
1194                   return(STATUS_UNSUCCESSFUL);
1195                   
1196                 default:
1197                   DPRINT("unexpected fixup type\n");
1198                   return STATUS_UNSUCCESSFUL;
1199                 }             
1200             }
1201
1202           Status = NtProtectVirtualMemory(NtCurrentProcess(),
1203                                           ImageBase + 
1204                                           RelocationDir->VirtualAddress,
1205                                           PAGE_SIZE,
1206                                           OldProtect,
1207                                           &OldProtect);
1208           if (!NT_SUCCESS(Status))
1209             {
1210               DPRINT1("Failed to protect relocation target.\n");
1211               return(Status);
1212             }
1213
1214           if (RelocationDir->VirtualAddress + PAGE_SIZE < MaxExtend)
1215             {
1216                   Status = NtProtectVirtualMemory(NtCurrentProcess(),
1217                                                   ImageBase + 
1218                                                   RelocationDir->VirtualAddress + PAGE_SIZE,
1219                                                   PAGE_SIZE,
1220                                                   OldProtect2,
1221                                                   &OldProtect2);
1222                   if (!NT_SUCCESS(Status))
1223                     {
1224                       DPRINT1("Failed to protect relocation target2.\n");
1225                       return(Status);
1226                     }
1227             }
1228
1229           RelocationRVA += RelocationDir->SizeOfBlock;
1230           RelocationDir = 
1231             (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
1232         }
1233     }
1234   return STATUS_SUCCESS;
1235 }
1236
1237
1238 /**********************************************************************
1239  * NAME                                                         LOCAL
1240  *      LdrFixupImports
1241  *      
1242  * DESCRIPTION
1243  *      Compute the entry point for every symbol the DLL imports
1244  *      from other modules.
1245  *
1246  * ARGUMENTS
1247  *
1248  * RETURN VALUE
1249  *
1250  * REVISIONS
1251  *
1252  * NOTE
1253  *
1254  */
1255 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS       NTHeaders,
1256                                 PVOID                   ImageBase)
1257 {
1258    PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1259    ULONG Ordinal;
1260    PVOID BaseAddress;
1261    NTSTATUS Status;
1262    ULONG IATSize;
1263    
1264    DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders, 
1265            ImageBase);
1266    
1267    /*
1268     * Process each import module.
1269     */
1270    ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
1271                                ImageBase + NTHeaders->OptionalHeader
1272                                  .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1273                              .VirtualAddress);
1274    DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
1275
1276    while (ImportModuleDirectory->dwRVAModuleName)
1277      {
1278         PVOID   * ImportAddressList;
1279         PULONG  FunctionNameList;
1280         UNICODE_STRING DllName;
1281         DWORD   pName;
1282         WORD    pHint;
1283         PVOID   IATBase;
1284         ULONG   OldProtect;
1285
1286         DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
1287                (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1288
1289         RtlCreateUnicodeStringFromAsciiz (&DllName,
1290                   (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
1291
1292         Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
1293         if (!NT_SUCCESS(Status))
1294           {
1295              Status = LdrLoadDll(NULL,
1296                                  0,
1297                                  &DllName,
1298                                  &BaseAddress);
1299              RtlFreeUnicodeString (&DllName);
1300              if (!NT_SUCCESS(Status))
1301                {
1302                   DbgPrint("LdrFixupImports:failed to load %s\n"
1303                         ,(PCHAR)(ImageBase 
1304                                 + ImportModuleDirectory->dwRVAModuleName));
1305
1306                   return Status;
1307                }
1308           }
1309
1310         /*
1311          * Get the import address list.
1312          */
1313         ImportAddressList = (PVOID *)(ImageBase
1314                         + ImportModuleDirectory->dwRVAFunctionAddressList);
1315         
1316         /*
1317          * Get the list of functions to import.
1318          */
1319         if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1320           {
1321              FunctionNameList = (PULONG) (
1322                                           ImageBase
1323                                           + ImportModuleDirectory->dwRVAFunctionNameList
1324                                           );
1325           }
1326         else
1327           {
1328              FunctionNameList = 
1329                (PULONG)(ImageBase 
1330                         + ImportModuleDirectory->dwRVAFunctionAddressList);
1331           }
1332
1333         /*
1334          * Get the size of IAT.
1335          */
1336         IATSize = 0;
1337         while (FunctionNameList[IATSize] != 0L)
1338           {
1339             IATSize++;
1340           }
1341
1342         /*
1343          * Unprotect the region we are about to write into.
1344          */
1345         IATBase = (PVOID)ImportAddressList;
1346         Status = NtProtectVirtualMemory(NtCurrentProcess(),
1347                                         IATBase,
1348                                         IATSize * sizeof(PVOID*),
1349                                         PAGE_READWRITE,
1350                                         &OldProtect);
1351         if (!NT_SUCCESS(Status))
1352           {
1353             DbgPrint("LDR: Failed to unprotect IAT.\n");
1354             return(Status);
1355           }
1356
1357         /*
1358          * Walk through function list and fixup addresses.
1359          */
1360         while (*FunctionNameList != 0L)
1361           {
1362              if ((*FunctionNameList) & 0x80000000)
1363                {
1364                   Ordinal = (*FunctionNameList) & 0x7fffffff;
1365                   *ImportAddressList = 
1366                     LdrGetExportByOrdinal(BaseAddress,
1367                                           Ordinal);
1368                }
1369              else
1370                {
1371                   pName = (DWORD) (ImageBase + *FunctionNameList + 2);
1372                   pHint = *(PWORD)(ImageBase + *FunctionNameList);
1373
1374                   *ImportAddressList = 
1375                     LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
1376                   if ((*ImportAddressList) == NULL)
1377                     {
1378                        DbgPrint("Failed to import %s\n", pName);
1379                        return STATUS_UNSUCCESSFUL;
1380                     }
1381                }
1382              ImportAddressList++;
1383              FunctionNameList++;
1384           }
1385
1386         /*
1387          * Protect the region we are about to write into.
1388          */
1389         Status = NtProtectVirtualMemory(NtCurrentProcess(),
1390                                         IATBase,
1391                                         IATSize * sizeof(PVOID*),
1392                                         OldProtect,
1393                                         &OldProtect);
1394         if (!NT_SUCCESS(Status))
1395           {
1396             DbgPrint("LDR: Failed to protect IAT.\n");
1397             return(Status);
1398           }
1399
1400         ImportModuleDirectory++;
1401      }
1402    return STATUS_SUCCESS;
1403 }
1404
1405
1406 /**********************************************************************
1407  * NAME
1408  *      LdrPEStartup
1409  *
1410  * DESCRIPTION
1411  *      1. Map the DLL's sections into memory.
1412  *      2. Relocate, if needed the DLL.
1413  *      3. Fixup any imported symbol.
1414  *      4. Compute the DLL's entry point.
1415  *
1416  * ARGUMENTS
1417  *      ImageBase
1418  *              Address at which the DLL's image
1419  *              is loaded.
1420  *              
1421  *      SectionHandle
1422  *              Handle of the section that contains
1423  *              the DLL's image.
1424  *
1425  * RETURN VALUE
1426  *      NULL on error; otherwise the entry point
1427  *      to call for initializing the DLL.
1428  *
1429  * REVISIONS
1430  *
1431  * NOTE
1432  *
1433  */
1434 PEPFUNC LdrPEStartup (PVOID  ImageBase,
1435                       HANDLE SectionHandle,
1436                       PLDR_MODULE* Module,
1437                       PWSTR FullDosName)
1438 {
1439    NTSTATUS             Status;
1440    PEPFUNC              EntryPoint = NULL;
1441    PIMAGE_DOS_HEADER    DosHeader;
1442    PIMAGE_NT_HEADERS    NTHeaders;
1443
1444    DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1445            ImageBase, (ULONG)SectionHandle);
1446
1447    /*
1448     * Overlay DOS and WNT headers structures
1449     * to the DLL's image.
1450     */
1451    DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1452    NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
1453
1454    /*
1455     * If the base address is different from the
1456     * one the DLL is actually loaded, perform any
1457     * relocation.
1458     */
1459    if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1460      {
1461        DbgPrint("LDR: Performing relocations\n");
1462        Status = LdrPerformRelocations(NTHeaders, ImageBase);
1463        if (!NT_SUCCESS(Status))
1464          {
1465            DbgPrint("LdrPerformRelocations() failed\n");
1466            return NULL;
1467          }
1468      }
1469
1470    if (Module != NULL)
1471      {
1472        *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
1473        (*Module)->SectionHandle = SectionHandle;
1474      }
1475
1476    /*
1477     * If the DLL's imports symbols from other
1478     * modules, fixup the imported calls entry points.
1479     */
1480    if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1481        .VirtualAddress != 0)
1482      {
1483         DPRINT("About to fixup imports\n");
1484         Status = LdrFixupImports(NTHeaders, ImageBase);
1485         if (!NT_SUCCESS(Status))
1486           {
1487              DbgPrint("LdrFixupImports() failed\n");
1488              return NULL;
1489           }
1490         DPRINT("Fixup done\n");
1491      }
1492
1493    /*
1494     * Compute the DLL's entry point's address.
1495     */
1496    DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
1497    DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
1498    if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
1499      {
1500         EntryPoint = (PEPFUNC) (ImageBase
1501                            + NTHeaders->OptionalHeader.AddressOfEntryPoint);
1502      }
1503    DPRINT("LdrPEStartup() = %x\n",EntryPoint);
1504    return EntryPoint;
1505 }
1506
1507
1508 /*
1509  * @implemented
1510  */
1511 NTSTATUS STDCALL
1512 LdrUnloadDll (IN PVOID BaseAddress)
1513 {
1514    PIMAGE_NT_HEADERS NtHeaders;
1515    PDLLMAIN_FUNC Entrypoint;
1516    PLIST_ENTRY ModuleListHead;
1517    PLIST_ENTRY Entry;
1518    PLDR_MODULE Module;
1519    NTSTATUS Status;
1520
1521    if (BaseAddress == NULL)
1522      return STATUS_SUCCESS;
1523
1524    RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1525
1526    ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1527    Entry = ModuleListHead->Flink;
1528
1529    while (Entry != ModuleListHead)
1530      {
1531         Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1532         if (Module->BaseAddress == BaseAddress)
1533           {
1534              if (Module->LoadCount == -1)
1535                {
1536                   /* never unload this dll */
1537                   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1538                   return STATUS_SUCCESS;
1539                }
1540              else if (Module->LoadCount > 1)
1541                {
1542                   Module->LoadCount--;
1543                   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1544                   return STATUS_SUCCESS;
1545                }
1546
1547              NtHeaders = RtlImageNtHeader (Module->BaseAddress);
1548              if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
1549                {
1550                   if (Module->EntryPoint != 0)
1551                     {
1552                        Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1553                        DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1554                        Entrypoint(Module->BaseAddress,
1555                                   DLL_PROCESS_DETACH,
1556                                   NULL);
1557                     }
1558                   else
1559                     {
1560                        DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1561                     }
1562                }
1563              Status = ZwUnmapViewOfSection (NtCurrentProcess (),
1564                                             Module->BaseAddress);
1565              ZwClose (Module->SectionHandle);
1566
1567              /* remove the module entry from the list */
1568              RemoveEntryList (&Module->InLoadOrderModuleList)
1569              RemoveEntryList (&Module->InInitializationOrderModuleList);
1570              RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1571
1572              RtlFreeUnicodeString (&Module->FullDllName);
1573              RtlFreeUnicodeString (&Module->BaseDllName);
1574
1575              RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
1576
1577              return Status;
1578           }
1579
1580         Entry = Entry->Flink;
1581      }
1582    RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1583
1584    DPRINT("NTDLL.LDR: Dll not found\n")
1585
1586    return STATUS_UNSUCCESSFUL;
1587 }
1588
1589
1590 /*
1591  * @implemented
1592  */
1593 NTSTATUS STDCALL
1594 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
1595 {
1596     PLIST_ENTRY ModuleListHead;
1597     PLIST_ENTRY Entry;
1598     PLDR_MODULE Module;
1599     NTSTATUS Status;
1600
1601     DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress);
1602
1603     Status = STATUS_DLL_NOT_FOUND;
1604     RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1605     ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1606     Entry = ModuleListHead->Flink;
1607     while (Entry != ModuleListHead) {
1608         Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1609
1610         DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module->BaseDllName, Module->BaseAddress);
1611
1612         if (Module->BaseAddress == BaseAddress) {
1613             if (Module->TlsIndex == 0) {
1614                 Module->Flags |= 0x00040000;
1615                 Status = STATUS_SUCCESS;
1616             }
1617             break;
1618         }
1619         Entry = Entry->Flink;
1620     }
1621     RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1622     return Status;
1623 }
1624
1625
1626 /*
1627  * @implemented
1628  */
1629 NTSTATUS STDCALL
1630 LdrGetDllHandle(IN ULONG Unknown1,
1631                 IN ULONG Unknown2,
1632                 IN PUNICODE_STRING DllName,
1633                 OUT PVOID* BaseAddress)
1634 {
1635     UNICODE_STRING FullDllName;
1636     PLIST_ENTRY ModuleListHead;
1637     PLIST_ENTRY Entry;
1638     PLDR_MODULE Module;
1639
1640     DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1641            Unknown1, Unknown2, DllName, BaseAddress);
1642
1643     /* NULL is the current executable */
1644     if (DllName == NULL) {
1645         *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
1646         DPRINT("BaseAddress %x\n", *BaseAddress);
1647         return STATUS_SUCCESS;
1648     }
1649     LdrAdjustDllName(&FullDllName, DllName, TRUE);
1650
1651     DPRINT("FullDllName %wZ\n", &FullDllName);
1652
1653     RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1654     ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1655     Entry = ModuleListHead->Flink;
1656     while (Entry != ModuleListHead) {
1657         Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1658
1659         DPRINT("EntryPoint %x\n", Module->EntryPoint);
1660         DPRINT("Comparing %wZ and %wZ\n", &Module->BaseDllName, &FullDllName);
1661
1662         if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE)) {
1663              RtlFreeUnicodeString(&FullDllName);
1664              *BaseAddress = Module->BaseAddress;
1665              DPRINT("BaseAddress %x\n", *BaseAddress);
1666              RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1667              return STATUS_SUCCESS;
1668         }
1669         Entry = Entry->Flink;
1670     }
1671
1672     DPRINT("Failed to find dll %wZ\n", &FullDllName);
1673
1674     RtlFreeUnicodeString(&FullDllName);
1675     *BaseAddress = NULL;
1676     RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1677     return STATUS_DLL_NOT_FOUND;
1678 }
1679
1680
1681 /*
1682  * @implemented
1683  */
1684 NTSTATUS STDCALL
1685 LdrGetProcedureAddress (IN PVOID BaseAddress,
1686                         IN PANSI_STRING Name,
1687                         IN ULONG Ordinal,
1688                         OUT PVOID *ProcedureAddress)
1689 {
1690    PIMAGE_EXPORT_DIRECTORY ExportDir;
1691    PUSHORT OrdinalPtr;
1692    PULONG NamePtr;
1693    PULONG AddressPtr;
1694    ULONG i = 0;
1695
1696    DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1697           BaseAddress, Name, Ordinal, ProcedureAddress);
1698
1699    /* Get the pointer to the export directory */
1700    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1701                 RtlImageDirectoryEntryToData (BaseAddress,
1702                                               TRUE,
1703                                               IMAGE_DIRECTORY_ENTRY_EXPORT,
1704                                               &i);
1705
1706    DPRINT("ExportDir %x i %lu\n", ExportDir, i);
1707
1708    if (!ExportDir || !i || !ProcedureAddress)
1709      {
1710         return STATUS_INVALID_PARAMETER;
1711      }
1712
1713    AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
1714    if (Name && Name->Length)
1715      {
1716         /* by name */
1717         OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
1718         NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
1719         for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
1720           {
1721              if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
1722                {
1723                   *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
1724                   return STATUS_SUCCESS;
1725                }
1726           }
1727         DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
1728      }
1729    else
1730      {
1731         /* by ordinal */
1732         Ordinal &= 0x0000FFFF;
1733         if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
1734           {
1735              *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
1736              return STATUS_SUCCESS;
1737           }
1738         DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
1739   }
1740
1741    return STATUS_PROCEDURE_NOT_FOUND;
1742 }
1743
1744
1745 /*
1746  * @implemented
1747  */
1748 NTSTATUS STDCALL
1749 LdrShutdownProcess (VOID)
1750 {
1751    PLIST_ENTRY ModuleListHead;
1752    PLIST_ENTRY Entry;
1753    PLDR_MODULE Module;
1754
1755    DPRINT("LdrShutdownProcess() called\n");
1756
1757    RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1758
1759    ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1760    Entry = ModuleListHead->Blink;
1761
1762    while (Entry != ModuleListHead)
1763      {
1764         Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1765
1766         DPRINT("  Unloading %wZ\n",
1767                &Module->BaseDllName);
1768         // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
1769         // they loaded dynamically, and when the last reference is gone, that lib will
1770         // be detached.  
1771         if (Module->EntryPoint != 0 && Module->LoadCount == -1)
1772           {
1773              PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1774
1775              DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1776              Entrypoint (Module->BaseAddress,
1777                          DLL_PROCESS_DETACH,
1778                          NULL);
1779           }
1780
1781         Entry = Entry->Blink;
1782      }
1783
1784    RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1785
1786    DPRINT("LdrShutdownProcess() done\n");
1787
1788    return STATUS_SUCCESS;
1789 }
1790
1791
1792 /*
1793  * @implemented
1794  */
1795 NTSTATUS STDCALL
1796 LdrShutdownThread (VOID)
1797 {
1798    PLIST_ENTRY ModuleListHead;
1799    PLIST_ENTRY Entry;
1800    PLDR_MODULE Module;
1801
1802    DPRINT("LdrShutdownThread() called\n");
1803
1804    RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1805
1806    ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1807    Entry = ModuleListHead->Blink;
1808
1809    while (Entry != ModuleListHead)
1810      {
1811         Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1812
1813         DPRINT("  Unloading %wZ\n",
1814                &Module->BaseDllName);
1815
1816         if (Module->EntryPoint != 0)
1817           {
1818              PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1819
1820              DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1821              Entrypoint (Module->BaseAddress,
1822                          DLL_THREAD_DETACH,
1823                          NULL);
1824           }
1825
1826         Entry = Entry->Blink;
1827      }
1828
1829    RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1830
1831    DPRINT("LdrShutdownThread() done\n");
1832
1833    return STATUS_SUCCESS;
1834 }
1835
1836
1837 /***************************************************************************
1838  * NAME                                                         EXPORTED
1839  *      LdrQueryProcessModuleInformation
1840  *
1841  * DESCRIPTION
1842  *
1843  * ARGUMENTS
1844  *
1845  * RETURN VALUE
1846  *
1847  * REVISIONS
1848  *
1849  * NOTE
1850  *
1851  * @implemented
1852  */
1853 NTSTATUS STDCALL
1854 LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
1855                                  IN ULONG Size OPTIONAL,
1856                                  OUT PULONG ReturnedSize)
1857 {
1858   PLIST_ENTRY ModuleListHead;
1859   PLIST_ENTRY Entry;
1860   PLDR_MODULE Module;
1861   PMODULE_ENTRY ModulePtr = NULL;
1862   NTSTATUS Status = STATUS_SUCCESS;
1863   ULONG UsedSize = sizeof(ULONG);
1864   ANSI_STRING AnsiString;
1865   PCHAR p;
1866
1867   DPRINT("LdrQueryProcessModuleInformation() called\n");
1868
1869   RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1870
1871   if (ModuleInformation == NULL || Size == 0)
1872     {
1873       Status = STATUS_INFO_LENGTH_MISMATCH;
1874     }
1875   else
1876     {
1877       ModuleInformation->ModuleCount = 0;
1878       ModulePtr = &ModuleInformation->ModuleEntry[0];
1879       Status = STATUS_SUCCESS;
1880     }
1881
1882   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1883   Entry = ModuleListHead->Flink;
1884
1885   while (Entry != ModuleListHead)
1886     {
1887       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1888
1889       DPRINT("  Module %wZ\n",
1890              &Module->FullDllName);
1891
1892       if (UsedSize > Size)
1893         {
1894           Status = STATUS_INFO_LENGTH_MISMATCH;
1895         }
1896       else if (ModuleInformation != NULL)
1897         {
1898           ModulePtr->Unknown0 = 0;      // FIXME: ??
1899           ModulePtr->Unknown1 = 0;      // FIXME: ??
1900           ModulePtr->BaseAddress = Module->BaseAddress;
1901           ModulePtr->SizeOfImage = Module->SizeOfImage;
1902           ModulePtr->Flags = Module->Flags;
1903           ModulePtr->Unknown2 = 0;      // FIXME: load order index ??
1904           ModulePtr->Unknown3 = 0;      // FIXME: ??
1905           ModulePtr->LoadCount = Module->LoadCount;
1906
1907           AnsiString.Length = 0;
1908           AnsiString.MaximumLength = 256;
1909           AnsiString.Buffer = ModulePtr->ModuleName;
1910           RtlUnicodeStringToAnsiString(&AnsiString,
1911                                        &Module->FullDllName,
1912                                        FALSE);
1913           p = strrchr(ModulePtr->ModuleName, '\\');
1914           if (p != NULL)
1915             ModulePtr->PathLength = p - ModulePtr->ModuleName + 1;
1916           else
1917             ModulePtr->PathLength = 0;
1918
1919           ModulePtr++;
1920           ModuleInformation->ModuleCount++;
1921         }
1922       UsedSize += sizeof(MODULE_ENTRY);
1923
1924       Entry = Entry->Flink;
1925     }
1926
1927   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1928
1929   if (ReturnedSize != 0)
1930     *ReturnedSize = UsedSize;
1931
1932   DPRINT("LdrQueryProcessModuleInformation() done\n");
1933
1934   return(Status);
1935 }
1936
1937
1938 static BOOLEAN
1939 LdrpCheckImageChecksum (IN PVOID BaseAddress,
1940                         IN ULONG ImageSize)
1941 {
1942   PIMAGE_NT_HEADERS Header;
1943   PUSHORT Ptr;
1944   ULONG Sum;
1945   ULONG CalcSum;
1946   ULONG HeaderSum;
1947   ULONG i;
1948
1949   Header = RtlImageNtHeader (BaseAddress);
1950   if (Header == NULL)
1951     return FALSE;
1952
1953   HeaderSum = Header->OptionalHeader.CheckSum;
1954   if (HeaderSum == 0)
1955     return TRUE;
1956
1957    Sum = 0;
1958    Ptr = (PUSHORT) BaseAddress;
1959    for (i = 0; i < ImageSize / sizeof (USHORT); i++)
1960      {
1961       Sum += (ULONG)*Ptr;
1962       if (HIWORD(Sum) != 0)
1963         {
1964           Sum = LOWORD(Sum) + HIWORD(Sum);
1965         }
1966       Ptr++;
1967      }
1968
1969   if (ImageSize & 1)
1970     {
1971       Sum += (ULONG)*((PUCHAR)Ptr);
1972       if (HIWORD(Sum) != 0)
1973         {
1974           Sum = LOWORD(Sum) + HIWORD(Sum);
1975         }
1976     }
1977
1978   CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
1979
1980   /* Subtract image checksum from calculated checksum. */
1981   /* fix low word of checksum */
1982   if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
1983     {
1984       CalcSum -= LOWORD(HeaderSum);
1985     }
1986   else
1987     {
1988       CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
1989     }
1990
1991    /* fix high word of checksum */
1992   if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
1993     {
1994       CalcSum -= HIWORD(HeaderSum);
1995     }
1996   else
1997     {
1998       CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
1999     }
2000
2001   /* add file length */
2002   CalcSum += ImageSize;
2003
2004   return (BOOLEAN)(CalcSum == HeaderSum);
2005 }
2006
2007
2008 /***************************************************************************
2009  * NAME                                                         EXPORTED
2010  *      LdrVerifyImageMatchesChecksum
2011  *
2012  * DESCRIPTION
2013  *
2014  * ARGUMENTS
2015  *
2016  * RETURN VALUE
2017  *
2018  * REVISIONS
2019  *
2020  * NOTE
2021  *
2022  * @implemented
2023  */
2024 NTSTATUS STDCALL
2025 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
2026                                ULONG Unknown1,
2027                                ULONG Unknown2,
2028                                ULONG Unknown3)
2029 {
2030   FILE_STANDARD_INFORMATION FileInfo;
2031   IO_STATUS_BLOCK IoStatusBlock;
2032   HANDLE SectionHandle;
2033   ULONG ViewSize;
2034   PVOID BaseAddress;
2035   BOOLEAN Result;
2036   NTSTATUS Status;
2037
2038   DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
2039
2040   Status = NtCreateSection (&SectionHandle,
2041                             SECTION_MAP_EXECUTE,
2042                             NULL,
2043                             NULL,
2044                             PAGE_EXECUTE,
2045                             SEC_COMMIT,
2046                             FileHandle);
2047   if (!NT_SUCCESS(Status))
2048     {
2049       DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
2050       return Status;
2051     }
2052
2053   ViewSize = 0;
2054   BaseAddress = NULL;
2055   Status = NtMapViewOfSection (SectionHandle,
2056                                NtCurrentProcess (),
2057                                &BaseAddress,
2058                                0,
2059                                0,
2060                                NULL,
2061                                &ViewSize,
2062                                ViewShare,
2063                                0,
2064                                PAGE_EXECUTE);
2065   if (!NT_SUCCESS(Status))
2066     {
2067       DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
2068       NtClose (SectionHandle);
2069       return Status;
2070     }
2071
2072   Status = NtQueryInformationFile (FileHandle,
2073                                    &IoStatusBlock,
2074                                    &FileInfo,
2075                                    sizeof (FILE_STANDARD_INFORMATION),
2076                                    FileStandardInformation);
2077   if (!NT_SUCCESS(Status))
2078     {
2079       DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
2080       NtUnmapViewOfSection (NtCurrentProcess (),
2081                             BaseAddress);
2082       NtClose (SectionHandle);
2083       return Status;
2084     }
2085
2086   Result = LdrpCheckImageChecksum (BaseAddress,
2087                                    FileInfo.EndOfFile.u.LowPart);
2088   if (Result == FALSE)
2089     {
2090       Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
2091     }
2092
2093   NtUnmapViewOfSection (NtCurrentProcess (),
2094                         BaseAddress);
2095
2096   NtClose (SectionHandle);
2097
2098   return Status;
2099 }
2100
2101
2102 /***************************************************************************
2103  * NAME                                                         EXPORTED
2104  *      LdrQueryImageFileExecutionOptions
2105  *
2106  * DESCRIPTION
2107  *
2108  * ARGUMENTS
2109  *
2110  * RETURN VALUE
2111  *
2112  * REVISIONS
2113  *
2114  * NOTE
2115  *
2116  * @implemented
2117  */
2118 NTSTATUS STDCALL
2119 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
2120                                    IN PCWSTR ValueName,
2121                                    IN ULONG ValueSize,
2122                                    OUT PVOID Buffer,
2123                                    IN ULONG BufferSize,
2124                                    OUT PULONG ReturnedLength OPTIONAL)
2125 {
2126   PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
2127   OBJECT_ATTRIBUTES ObjectAttributes;
2128   UNICODE_STRING ValueNameString;
2129   UNICODE_STRING ValueString;
2130   UNICODE_STRING KeyName;
2131   WCHAR NameBuffer[256];
2132   HANDLE KeyHandle;
2133   ULONG KeyInfoSize;
2134   ULONG ResultSize;
2135   PWCHAR Ptr;
2136   NTSTATUS Status;
2137
2138   wcscpy (NameBuffer,
2139           L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
2140   Ptr = wcsrchr (SubKey->Buffer, L'\\');
2141   if (Ptr == NULL)
2142     {
2143       Ptr = SubKey->Buffer;
2144     }
2145   else
2146     {
2147       Ptr++;
2148     }
2149   wcscat (NameBuffer, Ptr);
2150   RtlInitUnicodeString (&KeyName,
2151                         NameBuffer);
2152
2153   InitializeObjectAttributes (&ObjectAttributes,
2154                               &KeyName,
2155                               OBJ_CASE_INSENSITIVE,
2156                               NULL,
2157                               NULL);
2158
2159   Status = NtOpenKey (&KeyHandle,
2160                       KEY_READ,
2161                       &ObjectAttributes);
2162   if (!NT_SUCCESS(Status))
2163     {
2164       DPRINT1 ("NtOpenKey() failed (Status %lx)\n", Status);
2165       return Status;
2166     }
2167
2168   KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
2169   KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
2170                              HEAP_ZERO_MEMORY,
2171                              KeyInfoSize);
2172
2173   RtlInitUnicodeString (&ValueNameString,
2174                         (PWSTR)ValueName);
2175   Status = NtQueryValueKey (KeyHandle,
2176                             &ValueNameString,
2177                             KeyValuePartialInformation,
2178                             KeyInfo,
2179                             KeyInfoSize,
2180                             &ResultSize);
2181   if (Status == STATUS_BUFFER_OVERFLOW)
2182     {
2183       KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
2184       RtlFreeHeap (RtlGetProcessHeap(),
2185                    0,
2186                    KeyInfo);
2187       KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
2188                                  HEAP_ZERO_MEMORY,
2189                                  KeyInfoSize);
2190       if (KeyInfo == NULL)
2191         {
2192           NtClose (KeyHandle);
2193           return Status;
2194         }
2195
2196       Status = NtQueryValueKey (KeyHandle,
2197                                 &ValueNameString,
2198                                 KeyValuePartialInformation,
2199                                 KeyInfo,
2200                                 KeyInfoSize,
2201                                 &ResultSize);
2202     }
2203   NtClose (KeyHandle);
2204
2205   if (!NT_SUCCESS(Status))
2206     {
2207       if (KeyInfo != NULL)
2208         {
2209           RtlFreeHeap (RtlGetProcessHeap(),
2210                        0,
2211                        KeyInfo);
2212         }
2213       return Status;
2214     }
2215
2216   if (KeyInfo->Type != REG_SZ)
2217     {
2218       RtlFreeHeap (RtlGetProcessHeap(),
2219                    0,
2220                    KeyInfo);
2221       return STATUS_OBJECT_TYPE_MISMATCH;
2222     }
2223
2224   if (ValueSize == sizeof(ULONG))
2225     {
2226       if (BufferSize != sizeof(ULONG))
2227         {
2228           ResultSize = 0;
2229           Status = STATUS_INFO_LENGTH_MISMATCH;
2230         }
2231       else
2232         {
2233           ResultSize = sizeof(ULONG);
2234           ValueString.Length = (USHORT)KeyInfo->DataLength - sizeof(WCHAR);
2235           ValueString.MaximumLength = (USHORT)KeyInfo->DataLength;
2236           ValueString.Buffer = (PWSTR)&KeyInfo->Data;
2237           Status = RtlUnicodeStringToInteger (&ValueString,
2238                                               0,
2239                                               Buffer);
2240         }
2241     }
2242   else
2243     {
2244       ResultSize = BufferSize;
2245       if (ResultSize < KeyInfo->DataLength)
2246         {
2247           Status = STATUS_BUFFER_OVERFLOW;
2248         }
2249       else
2250         {
2251           ResultSize = KeyInfo->DataLength;
2252         }
2253       RtlCopyMemory (Buffer,
2254                      &KeyInfo->Data,
2255                      ResultSize);
2256     }
2257
2258   RtlFreeHeap (RtlGetProcessHeap(),
2259                0,
2260                KeyInfo);
2261
2262   if (ReturnedLength != NULL)
2263     {
2264       *ReturnedLength = ResultSize;
2265     }
2266
2267   return Status;
2268 }
2269
2270 /* EOF */