xref: /reactos/dll/ntdll/ldr/ldrutils.c (revision d6eebaa4)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS NT User-Mode Library
4  * FILE:            dll/ntdll/ldr/ldrutils.c
5  * PURPOSE:         Internal Loader Utility Functions
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  *                  Aleksey Bragin (aleksey@reactos.org)
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <ntdll.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* GLOBALS *******************************************************************/
18 
19 PLDR_DATA_TABLE_ENTRY LdrpLoadedDllHandleCache, LdrpGetModuleHandleCache;
20 
21 BOOLEAN g_ShimsEnabled;
22 PVOID g_pShimEngineModule;
23 PVOID g_pfnSE_DllLoaded;
24 PVOID g_pfnSE_DllUnloaded;
25 PVOID g_pfnSE_InstallBeforeInit;
26 PVOID g_pfnSE_InstallAfterInit;
27 PVOID g_pfnSE_ProcessDying;
28 
29 /* FUNCTIONS *****************************************************************/
30 
31 NTSTATUS
32 NTAPI
33 LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut,
34                           IN ULONG Length)
35 {
36     /* Sanity checks */
37     ASSERT(StringOut);
38     ASSERT(Length <= UNICODE_STRING_MAX_BYTES);
39 
40     /* Assume failure */
41     StringOut->Length = 0;
42 
43     /* Make sure it's not mis-aligned */
44     if (Length & 1)
45     {
46         /* Fail */
47         StringOut->Buffer = NULL;
48         StringOut->MaximumLength = 0;
49         return STATUS_INVALID_PARAMETER;
50     }
51 
52     /* Allocate the string*/
53     StringOut->Buffer = RtlAllocateHeap(LdrpHeap,
54                                         0,
55                                         Length + sizeof(WCHAR));
56     if (!StringOut->Buffer)
57     {
58         /* Fail */
59         StringOut->MaximumLength = 0;
60         return STATUS_NO_MEMORY;
61     }
62 
63     /* Null-terminate it */
64     StringOut->Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
65 
66     /* Check if this is a maximum-sized string */
67     if (Length != UNICODE_STRING_MAX_BYTES)
68     {
69         /* It's not, so set the maximum length to be one char more */
70         StringOut->MaximumLength = (USHORT)Length + sizeof(UNICODE_NULL);
71     }
72     else
73     {
74         /* The length is already the maximum possible */
75         StringOut->MaximumLength = UNICODE_STRING_MAX_BYTES;
76     }
77 
78     /* Return success */
79     return STATUS_SUCCESS;
80 }
81 
82 VOID
83 NTAPI
84 LdrpFreeUnicodeString(IN PUNICODE_STRING StringIn)
85 {
86     ASSERT(StringIn != NULL);
87 
88     /* If Buffer is not NULL - free it */
89     if (StringIn->Buffer)
90     {
91         RtlFreeHeap(LdrpHeap, 0, StringIn->Buffer);
92     }
93 
94     /* Zero it out */
95     RtlInitEmptyUnicodeString(StringIn, NULL, 0);
96 }
97 
98 BOOLEAN
99 NTAPI
100 LdrpCallInitRoutine(IN PDLL_INIT_ROUTINE EntryPoint,
101                     IN PVOID BaseAddress,
102                     IN ULONG Reason,
103                     IN PVOID Context)
104 {
105     /* Call the entry */
106     return EntryPoint(BaseAddress, Reason, Context);
107 }
108 
109 /* NOTE: This function is broken */
110 VOID
111 NTAPI
112 LdrpUpdateLoadCount3(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
113                      IN ULONG Flags,
114                      OUT PUNICODE_STRING UpdateString)
115 {
116     PIMAGE_BOUND_FORWARDER_REF NewImportForwarder;
117     PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry;
118     PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry;
119     PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
120     PIMAGE_THUNK_DATA FirstThunk;
121     PLDR_DATA_TABLE_ENTRY Entry;
122     PUNICODE_STRING ImportNameUnic, RedirectedImportName;
123     ANSI_STRING ImportNameAnsi;
124     LPSTR ImportName;
125     ULONG ImportSize;
126     NTSTATUS Status;
127     ULONG i;
128     BOOLEAN RedirectedDll;
129     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
130 
131     /* Set up the Act Ctx */
132     ActCtx.Size = sizeof(ActCtx);
133     ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
134     RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
135 
136     /* Activate the ActCtx */
137     RtlActivateActivationContextUnsafeFast(&ActCtx,
138                                            LdrEntry->EntryPointActivationContext);
139 
140     /* Check the action we need to perform */
141     if ((Flags == LDRP_UPDATE_REFCOUNT) || (Flags == LDRP_UPDATE_PIN))
142     {
143         /* Make sure entry is not being loaded already */
144         if (LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS)
145             goto done;
146 
147         LdrEntry->Flags |= LDRP_LOAD_IN_PROGRESS;
148     }
149     else if (Flags == LDRP_UPDATE_DEREFCOUNT)
150     {
151         /* Make sure the entry is not being unloaded already */
152         if (LdrEntry->Flags & LDRP_UNLOAD_IN_PROGRESS)
153             goto done;
154 
155         LdrEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS;
156     }
157 
158     /* Go through all bound DLLs and dereference them */
159     ImportNameUnic = &NtCurrentTeb()->StaticUnicodeString;
160 
161     /* Try to get the new import entry */
162     FirstEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
163                                               TRUE,
164                                               IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
165                                               &ImportSize);
166 
167     if (FirstEntry)
168     {
169         /* Set entry flags if refing/derefing */
170         if (Flags == LDRP_UPDATE_REFCOUNT)
171             LdrEntry->Flags |= LDRP_LOAD_IN_PROGRESS;
172         else if (Flags == LDRP_UPDATE_DEREFCOUNT)
173             LdrEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS;
174 
175         BoundEntry = FirstEntry;
176         while (BoundEntry->OffsetModuleName)
177         {
178             /* Get pointer to the current import name */
179             ImportName = (LPSTR)FirstEntry + BoundEntry->OffsetModuleName;
180 
181             RtlInitAnsiString(&ImportNameAnsi, ImportName);
182             Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE);
183 
184             if (NT_SUCCESS(Status))
185             {
186                 RedirectedDll = FALSE;
187                 RedirectedImportName = ImportNameUnic;
188 
189                 /* Check if the SxS Assemblies specify another file */
190                 Status = LdrpApplyFileNameRedirection(
191                     ImportNameUnic, &LdrApiDefaultExtension, UpdateString, NULL, &RedirectedImportName,
192                     &RedirectedDll);
193 
194                 /* Check success */
195                 if (NT_SUCCESS(Status) && RedirectedDll)
196                 {
197                     if (ShowSnaps)
198                     {
199                         DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi, RedirectedImportName);
200                     }
201                 }
202 
203                 if (NT_SUCCESS(Status))
204                 {
205                     if (LdrpCheckForLoadedDll(NULL,
206                                               RedirectedImportName,
207                                               TRUE,
208                                               RedirectedDll,
209                                               &Entry))
210                     {
211                         if (Entry->LoadCount != 0xFFFF)
212                         {
213                             /* Perform the required action */
214                             switch (Flags)
215                             {
216                             case LDRP_UPDATE_REFCOUNT:
217                                 Entry->LoadCount++;
218                                 break;
219                             case LDRP_UPDATE_DEREFCOUNT:
220                                 Entry->LoadCount--;
221                                 break;
222                             case LDRP_UPDATE_PIN:
223                                 Entry->LoadCount = 0xFFFF;
224                                 break;
225                             }
226 
227                             /* Show snaps */
228                             if (ShowSnaps)
229                             {
230                                 DPRINT1("LDR: Flags %lu  %wZ (%lx)\n", Flags, RedirectedImportName, Entry->LoadCount);
231                             }
232                         }
233 
234                         /* Recurse into this entry */
235                         LdrpUpdateLoadCount3(Entry, Flags, UpdateString);
236                     }
237                     else if (RedirectedDll)
238                     {
239                         DPRINT1("LDR: LdrpCheckForLoadedDll failed for redirected dll %wZ\n", RedirectedImportName);
240                     }
241                 }
242                 else
243                 {
244                     /* Unrecoverable SxS failure */
245                     DPRINT1("LDR: LdrpApplyFileNameRedirection failed with status %x for dll %wZ\n", Status, ImportNameUnic);
246                 }
247 
248             }
249 
250             /* Go through forwarders */
251             NewImportForwarder = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1);
252             for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++)
253             {
254                 ImportName = (LPSTR)FirstEntry + NewImportForwarder->OffsetModuleName;
255 
256                 RtlInitAnsiString(&ImportNameAnsi, ImportName);
257                 Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE);
258                 if (NT_SUCCESS(Status))
259                 {
260                     RedirectedDll = FALSE;
261                     RedirectedImportName = ImportNameUnic;
262 
263                     /* Check if the SxS Assemblies specify another file */
264                     Status = LdrpApplyFileNameRedirection(
265                         ImportNameUnic, &LdrApiDefaultExtension, UpdateString, NULL, &RedirectedImportName,
266                         &RedirectedDll);
267 
268                     /* Check success */
269                     if (NT_SUCCESS(Status) && RedirectedDll)
270                     {
271                         if (ShowSnaps)
272                         {
273                             DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi, RedirectedImportName);
274                         }
275                     }
276 
277                     if (NT_SUCCESS(Status))
278                     {
279                         if (LdrpCheckForLoadedDll(NULL,
280                                                   RedirectedImportName,
281                                                   TRUE,
282                                                   RedirectedDll,
283                                                   &Entry))
284                         {
285                             if (Entry->LoadCount != 0xFFFF)
286                             {
287                                 /* Perform the required action */
288                                 switch (Flags)
289                                 {
290                                 case LDRP_UPDATE_REFCOUNT:
291                                     Entry->LoadCount++;
292                                     break;
293                                 case LDRP_UPDATE_DEREFCOUNT:
294                                     Entry->LoadCount--;
295                                     break;
296                                 case LDRP_UPDATE_PIN:
297                                     Entry->LoadCount = 0xFFFF;
298                                     break;
299                                 }
300 
301                                 /* Show snaps */
302                                 if (ShowSnaps)
303                                 {
304                                     DPRINT1("LDR: Flags %lu  %wZ (%lx)\n", Flags, RedirectedImportName, Entry->LoadCount);
305                                 }
306                             }
307 
308                             /* Recurse into this entry */
309                             LdrpUpdateLoadCount3(Entry, Flags, UpdateString);
310                         }
311                         else if (RedirectedDll)
312                         {
313                             DPRINT1("LDR: LdrpCheckForLoadedDll failed with status %x for redirected dll %wZ\n", Status, RedirectedImportName);
314                         }
315                     }
316                     else
317                     {
318                         /* Unrecoverable SxS failure */
319                         DPRINT1("LDR: LdrpApplyFileNameRedirection failed  with status %x for dll %wZ\n", Status, ImportNameUnic);
320                     }
321 
322                 }
323 
324                 NewImportForwarder++;
325             }
326 
327             BoundEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)NewImportForwarder;
328         }
329 
330         /* We're done */
331         goto done;
332     }
333 
334     /* Check oldstyle import descriptor */
335     ImportEntry = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(LdrEntry->DllBase,
336                                                                          TRUE,
337                                                                          IMAGE_DIRECTORY_ENTRY_IMPORT,
338                                                                          &ImportSize);
339     if (ImportEntry)
340     {
341         /* There is old one, so go through its entries */
342         while (ImportEntry->Name && ImportEntry->FirstThunk)
343         {
344             FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->FirstThunk);
345 
346             /* Skip this entry if needed */
347             if (!FirstThunk->u1.Function)
348             {
349                 ImportEntry++;
350                 continue;
351             }
352 
353             ImportName = (PSZ)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
354 
355             RtlInitAnsiString(&ImportNameAnsi, ImportName);
356             Status = RtlAnsiStringToUnicodeString(ImportNameUnic, &ImportNameAnsi, FALSE);
357             if (NT_SUCCESS(Status))
358             {
359                 RedirectedDll = FALSE;
360                 RedirectedImportName = ImportNameUnic;
361 
362                 /* Check if the SxS Assemblies specify another file */
363                 Status = LdrpApplyFileNameRedirection(
364                     ImportNameUnic, &LdrApiDefaultExtension, UpdateString, NULL, &RedirectedImportName, &RedirectedDll);
365 
366                 /* Check success */
367                 if (NT_SUCCESS(Status) && RedirectedDll)
368                 {
369                     if (ShowSnaps)
370                     {
371                         DPRINT1("LDR: %Z got redirected to %wZ\n", &ImportNameAnsi, RedirectedImportName);
372                     }
373                 }
374 
375                 if (NT_SUCCESS(Status))
376                 {
377                     if (LdrpCheckForLoadedDll(NULL,
378                                               RedirectedImportName,
379                                               TRUE,
380                                               RedirectedDll,
381                                               &Entry))
382                     {
383                         if (Entry->LoadCount != 0xFFFF)
384                         {
385                             /* Perform the required action */
386                             switch (Flags)
387                             {
388                             case LDRP_UPDATE_REFCOUNT:
389                                 Entry->LoadCount++;
390                                 break;
391                             case LDRP_UPDATE_DEREFCOUNT:
392                                 Entry->LoadCount--;
393                                 break;
394                             case LDRP_UPDATE_PIN:
395                                 Entry->LoadCount = 0xFFFF;
396                                 break;
397                             }
398 
399                             /* Show snaps */
400                             if (ShowSnaps)
401                             {
402                                 DPRINT1("LDR: Flags %lu  %wZ (%lx)\n", Flags, RedirectedImportName, Entry->LoadCount);
403                             }
404                         }
405 
406                         /* Recurse */
407                         LdrpUpdateLoadCount3(Entry, Flags, UpdateString);
408                     }
409                     else if (RedirectedDll)
410                     {
411                         DPRINT1("LDR: LdrpCheckForLoadedDll failed for redirected dll %wZ\n", RedirectedImportName);
412                     }
413 
414                 }
415                 else
416                 {
417                     /* Unrecoverable SxS failure */
418                     DPRINT1("LDR: LdrpApplyFileNameRedirection failed for dll %wZ\n", ImportNameUnic);
419                 }
420             }
421 
422             /* Go to the next entry */
423             ImportEntry++;
424         }
425     }
426 
427 done:
428     /* Release the context */
429     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
430 }
431 
432 VOID
433 NTAPI
434 LdrpUpdateLoadCount2(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
435                      IN ULONG Flags)
436 {
437     WCHAR Buffer[MAX_PATH];
438     UNICODE_STRING UpdateString;
439 
440     /* Setup the string and call the extended API */
441     RtlInitEmptyUnicodeString(&UpdateString, Buffer, sizeof(Buffer));
442     LdrpUpdateLoadCount3(LdrEntry, Flags, &UpdateString);
443 }
444 
445 VOID
446 NTAPI
447 LdrpCallTlsInitializers(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
448                         IN ULONG Reason)
449 {
450     PIMAGE_TLS_DIRECTORY TlsDirectory;
451     PIMAGE_TLS_CALLBACK *Array, Callback;
452     ULONG Size;
453 
454     /* Get the TLS Directory */
455     TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
456                                                 TRUE,
457                                                 IMAGE_DIRECTORY_ENTRY_TLS,
458                                                 &Size);
459 
460     /* Protect against invalid pointers */
461     _SEH2_TRY
462     {
463         /* Make sure it's valid */
464         if (TlsDirectory)
465         {
466             /* Get the array */
467             Array = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;
468             if (Array)
469             {
470                 /* Display debug */
471                 if (ShowSnaps)
472                 {
473                     DPRINT1("LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
474                             LdrEntry->DllBase, TlsDirectory, Array);
475                 }
476 
477                 /* Loop the array */
478                 while (*Array)
479                 {
480                     /* Get the TLS Entrypoint */
481                     Callback = *Array++;
482 
483                     /* Display debug */
484                     if (ShowSnaps)
485                     {
486                         DPRINT1("LDR: Calling Tls Callback Imagebase %p Function %p\n",
487                                 LdrEntry->DllBase, Callback);
488                     }
489 
490                     /* Call it */
491                     LdrpCallInitRoutine((PDLL_INIT_ROUTINE)Callback,
492                                         LdrEntry->DllBase,
493                                         Reason,
494                                         NULL);
495                 }
496             }
497         }
498     }
499     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
500     {
501         DPRINT1("LDR: Exception 0x%x during Tls Callback(%u) for %wZ\n",
502                 _SEH2_GetExceptionCode(), Reason, &LdrEntry->BaseDllName);
503     }
504     _SEH2_END;
505 }
506 
507 NTSTATUS
508 NTAPI
509 LdrpCodeAuthzCheckDllAllowed(IN PUNICODE_STRING FullName,
510                              IN HANDLE DllHandle)
511 {
512     /* Not implemented */
513     return STATUS_SUCCESS;
514 }
515 
516 NTSTATUS
517 NTAPI
518 LdrpCreateDllSection(IN PUNICODE_STRING FullName,
519                      IN HANDLE DllHandle,
520                      IN PULONG DllCharacteristics OPTIONAL,
521                      OUT PHANDLE SectionHandle)
522 {
523     HANDLE FileHandle;
524     NTSTATUS Status;
525     OBJECT_ATTRIBUTES ObjectAttributes;
526     IO_STATUS_BLOCK IoStatusBlock;
527     ULONG_PTR HardErrorParameters[1];
528     ULONG Response;
529     SECTION_IMAGE_INFORMATION SectionImageInfo;
530 
531     /* Check if we don't already have a handle */
532     if (!DllHandle)
533     {
534         /* Create the object attributes */
535         InitializeObjectAttributes(&ObjectAttributes,
536                                    FullName,
537                                    OBJ_CASE_INSENSITIVE,
538                                    NULL,
539                                    NULL);
540 
541         /* Open the DLL */
542         Status = NtOpenFile(&FileHandle,
543                             SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
544                             &ObjectAttributes,
545                             &IoStatusBlock,
546                             FILE_SHARE_READ | FILE_SHARE_DELETE,
547                             FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
548 
549         /* Check if we failed */
550         if (!NT_SUCCESS(Status))
551         {
552             /* Attempt to open for execute only */
553             Status = NtOpenFile(&FileHandle,
554                                 SYNCHRONIZE | FILE_EXECUTE,
555                                 &ObjectAttributes,
556                                 &IoStatusBlock,
557                                 FILE_SHARE_READ | FILE_SHARE_DELETE,
558                                 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
559 
560             /* Check if this failed too */
561             if (!NT_SUCCESS(Status))
562             {
563                 /* Show debug message */
564                 if (ShowSnaps)
565                 {
566                     DPRINT1("LDR: LdrpCreateDllSection - NtOpenFile failed; status = %x\n",
567                             Status);
568                 }
569 
570                 /* Make sure to return an expected status code */
571                 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
572                 {
573                     /* Callers expect this instead */
574                     Status = STATUS_DLL_NOT_FOUND;
575                 }
576 
577                 /* Return an empty section handle */
578                 *SectionHandle = NULL;
579                 return Status;
580             }
581         }
582     }
583     else
584     {
585         /* Use the handle we already have */
586         FileHandle = DllHandle;
587     }
588 
589     /* Create a section for the DLL */
590     Status = NtCreateSection(SectionHandle,
591                              SECTION_MAP_READ | SECTION_MAP_EXECUTE |
592                              SECTION_MAP_WRITE | SECTION_QUERY,
593                              NULL,
594                              NULL,
595                              PAGE_EXECUTE,
596                              SEC_IMAGE,
597                              FileHandle);
598 
599     /* If mapping failed, raise a hard error */
600     if (!NT_SUCCESS(Status))
601     {
602         /* Forget the handle */
603         *SectionHandle = NULL;
604 
605         /* Give the DLL name */
606         HardErrorParameters[0] = (ULONG_PTR)FullName;
607 
608         /* Raise the error */
609         ZwRaiseHardError(STATUS_INVALID_IMAGE_FORMAT,
610                          1,
611                          1,
612                          HardErrorParameters,
613                          OptionOk,
614                          &Response);
615 
616         /* Increment the error count */
617         if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
618 
619         goto Exit;
620     }
621 
622     /* Check for Safer restrictions */
623     if (!DllCharacteristics ||
624         !(*DllCharacteristics & IMAGE_FILE_SYSTEM))
625     {
626         /* Make sure it's executable */
627         Status = ZwQuerySection(*SectionHandle,
628                                 SectionImageInformation,
629                                 &SectionImageInfo,
630                                 sizeof(SECTION_IMAGE_INFORMATION),
631                                 NULL);
632         if (NT_SUCCESS(Status))
633         {
634             /* Bypass the check for .NET images */
635             if (!(SectionImageInfo.LoaderFlags & IMAGE_LOADER_FLAGS_COMPLUS))
636             {
637                 /* Check with Safer */
638                 Status = LdrpCodeAuthzCheckDllAllowed(FullName, DllHandle);
639                 if (!NT_SUCCESS(Status) && (Status != STATUS_NOT_FOUND))
640                 {
641                     /* Show debug message */
642                     if (ShowSnaps)
643                     {
644                         DPRINT1("LDR: Loading of (%wZ) blocked by Winsafer\n",
645                                 &FullName);
646                     }
647 
648                     /* Failure case, close section handle */
649                     NtClose(*SectionHandle);
650                     *SectionHandle = NULL;
651                 }
652             }
653         }
654         else
655         {
656             /* Failure case, close section handle */
657             NtClose(*SectionHandle);
658             *SectionHandle = NULL;
659         }
660     }
661 
662 Exit:
663     /* Close the file handle, we don't need it */
664     NtClose(FileHandle);
665 
666     /* Return status */
667     return Status;
668 }
669 
670 /* NOTE: This function is totally b0rked and doesn't handle the parameters/functionality it should */
671 BOOLEAN
672 NTAPI
673 LdrpResolveDllName(PWSTR DllPath,
674                    PWSTR DllName,
675                    PUNICODE_STRING FullDllName,
676                    PUNICODE_STRING BaseDllName)
677 {
678     PWCHAR NameBuffer, p1, p2 = 0;
679     ULONG Length;
680     ULONG BufSize = 500;
681 
682     /* Allocate space for full DLL name */
683     FullDllName->Buffer = RtlAllocateHeap(LdrpHeap, 0, BufSize + sizeof(UNICODE_NULL));
684     if (!FullDllName->Buffer) return FALSE;
685 
686     Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer,
687                                 DllName,
688                                 NULL,
689                                 BufSize,
690                                 FullDllName->Buffer,
691                                 &BaseDllName->Buffer);
692 
693     if (!Length || Length > BufSize)
694     {
695         if (ShowSnaps)
696         {
697             DPRINT1("LDR: LdrResolveDllName - Unable to find ");
698             DPRINT1("%ws from %ws\n", DllName, DllPath ? DllPath : LdrpDefaultPath.Buffer);
699         }
700 
701         LdrpFreeUnicodeString(FullDllName);
702         return FALSE;
703     }
704 
705     /* Construct full DLL name */
706     FullDllName->Length = Length;
707     FullDllName->MaximumLength = FullDllName->Length + sizeof(UNICODE_NULL);
708 
709     /* Allocate a new buffer */
710     NameBuffer = RtlAllocateHeap(LdrpHeap, 0, FullDllName->MaximumLength);
711     if (!NameBuffer)
712     {
713         RtlFreeHeap(LdrpHeap, 0, FullDllName->Buffer);
714         return FALSE;
715     }
716 
717     /* Copy over the contents from the previous one and free it */
718     RtlCopyMemory(NameBuffer, FullDllName->Buffer, FullDllName->MaximumLength);
719     RtlFreeHeap(LdrpHeap, 0, FullDllName->Buffer);
720     FullDllName->Buffer = NameBuffer;
721 
722     /* Find last backslash */
723     p1 = FullDllName->Buffer;
724     while (*p1)
725     {
726         if (*p1++ == L'\\')
727         {
728             p2 = p1;
729         }
730     }
731 
732     /* If found, set p1 to it, otherwise p1 points to the beginning of DllName */
733     if (p2)
734         p1 = p2;
735     else
736         p1 = DllName;
737 
738     p2 = p1;
739 
740     /* Calculate remaining length */
741     while (*p1) ++p1;
742 
743     /* Construct base DLL name */
744     BaseDllName->Length = (ULONG_PTR)p1 - (ULONG_PTR)p2;
745     BaseDllName->MaximumLength = BaseDllName->Length + sizeof(UNICODE_NULL);
746     BaseDllName->Buffer = RtlAllocateHeap(LdrpHeap, 0, BaseDllName->MaximumLength);
747 
748     if (!BaseDllName->Buffer)
749     {
750         RtlFreeHeap(LdrpHeap, 0, NameBuffer);
751         return FALSE;
752     }
753 
754     /* Copy base dll name to the new buffer */
755     RtlMoveMemory(BaseDllName->Buffer,
756                   p2,
757                   BaseDllName->Length);
758 
759     /* Null-terminate the string */
760     BaseDllName->Buffer[BaseDllName->Length / sizeof(WCHAR)] = 0;
761 
762     return TRUE;
763 }
764 
765 PVOID
766 NTAPI
767 LdrpFetchAddressOfEntryPoint(IN PVOID ImageBase)
768 {
769     PIMAGE_NT_HEADERS NtHeaders;
770     ULONG_PTR EntryPoint = 0;
771 
772     /* Get entry point offset from NT headers */
773     NtHeaders = RtlImageNtHeader(ImageBase);
774     if (NtHeaders)
775     {
776         /* Add image base */
777         EntryPoint = NtHeaders->OptionalHeader.AddressOfEntryPoint;
778         if (EntryPoint) EntryPoint += (ULONG_PTR)ImageBase;
779     }
780 
781     /* Return calculated pointer (or zero in case of failure) */
782     return (PVOID)EntryPoint;
783 }
784 
785 /* NOTE: This function is partially missing SxS */
786 NTSTATUS
787 NTAPI
788 LdrpCheckForKnownDll(PWSTR DllName,
789                      PUNICODE_STRING FullDllName,
790                      PUNICODE_STRING BaseDllName,
791                      HANDLE *SectionHandle)
792 {
793     OBJECT_ATTRIBUTES ObjectAttributes;
794     HANDLE Section = NULL;
795     UNICODE_STRING DllNameUnic;
796     NTSTATUS Status;
797     PCHAR p1;
798     PWCHAR p2;
799 
800     /* Zero initialize provided parameters */
801     if (SectionHandle) *SectionHandle = 0;
802 
803     if (FullDllName)
804     {
805         FullDllName->Length = 0;
806         FullDllName->MaximumLength = 0;
807         FullDllName->Buffer = NULL;
808     }
809 
810     if (BaseDllName)
811     {
812         BaseDllName->Length = 0;
813         BaseDllName->MaximumLength = 0;
814         BaseDllName->Buffer = NULL;
815     }
816 
817     /* If any of these three params are missing then fail */
818     if (!SectionHandle || !FullDllName || !BaseDllName)
819         return STATUS_INVALID_PARAMETER;
820 
821     /* Check the Loader Lock */
822     LdrpEnsureLoaderLockIsHeld();
823 
824     /* Upgrade DllName to a unicode string */
825     RtlInitUnicodeString(&DllNameUnic, DllName);
826 
827     /* FIXME: Missing RtlComputePrivatizedDllName_U related functionality */
828 
829     /* Get the activation context */
830     Status = RtlFindActivationContextSectionString(0,
831                                                    NULL,
832                                                    ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
833                                                    &DllNameUnic,
834                                                    NULL);
835 
836     /* Check if it's a SxS or not */
837     if (Status == STATUS_SXS_SECTION_NOT_FOUND ||
838         Status == STATUS_SXS_KEY_NOT_FOUND)
839     {
840         /* NOTE: Here it's beneficial to allocate one big unicode string
841                  using LdrpAllocateUnicodeString instead of fragmenting the heap
842                  with two allocations as it's done now. */
843 
844         /* Set up BaseDllName */
845         BaseDllName->Length = DllNameUnic.Length;
846         BaseDllName->MaximumLength = DllNameUnic.MaximumLength;
847         BaseDllName->Buffer = RtlAllocateHeap(LdrpHeap,
848                                               0,
849                                               DllNameUnic.MaximumLength);
850         if (!BaseDllName->Buffer)
851         {
852             Status = STATUS_NO_MEMORY;
853             goto Failure;
854         }
855 
856         /* Copy the contents there */
857         RtlMoveMemory(BaseDllName->Buffer, DllNameUnic.Buffer, DllNameUnic.MaximumLength);
858 
859         /* Set up FullDllName */
860         FullDllName->Length = LdrpKnownDllPath.Length + BaseDllName->Length + sizeof(WCHAR);
861         FullDllName->MaximumLength = FullDllName->Length + sizeof(UNICODE_NULL);
862         FullDllName->Buffer = RtlAllocateHeap(LdrpHeap, 0, FullDllName->MaximumLength);
863         if (!FullDllName->Buffer)
864         {
865             Status = STATUS_NO_MEMORY;
866             goto Failure;
867         }
868 
869         RtlMoveMemory(FullDllName->Buffer, LdrpKnownDllPath.Buffer, LdrpKnownDllPath.Length);
870 
871         /* Put a slash there */
872         p1 = (PCHAR)FullDllName->Buffer + LdrpKnownDllPath.Length;
873         p2 = (PWCHAR)p1;
874         *p2++ = (WCHAR)'\\';
875         p1 = (PCHAR)p2;
876 
877         /* Set up DllNameUnic for a relative path */
878         DllNameUnic.Buffer = (PWSTR)p1;
879         DllNameUnic.Length = BaseDllName->Length;
880         DllNameUnic.MaximumLength = DllNameUnic.Length + sizeof(UNICODE_NULL);
881 
882         /* Copy the contents */
883         RtlMoveMemory(p1, BaseDllName->Buffer, BaseDllName->MaximumLength);
884 
885         /* There are all names, init attributes and open the section */
886         InitializeObjectAttributes(&ObjectAttributes,
887                                    &DllNameUnic,
888                                    OBJ_CASE_INSENSITIVE,
889                                    LdrpKnownDllObjectDirectory,
890                                    NULL);
891 
892         Status = NtOpenSection(&Section,
893                                SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE,
894                                &ObjectAttributes);
895         if (!NT_SUCCESS(Status))
896         {
897             /* Clear status in case it was just not found */
898             if (Status == STATUS_OBJECT_NAME_NOT_FOUND) Status = STATUS_SUCCESS;
899             goto Failure;
900         }
901 
902         /* Pass section handle to the caller and return success */
903         *SectionHandle = Section;
904         return STATUS_SUCCESS;
905     }
906 
907 Failure:
908     /* Close section object if it was opened */
909     if (Section) NtClose(Section);
910 
911     /* Free string resources */
912     if (BaseDllName->Buffer) RtlFreeHeap(LdrpHeap, 0, BaseDllName->Buffer);
913     if (FullDllName->Buffer) RtlFreeHeap(LdrpHeap, 0, FullDllName->Buffer);
914 
915     /* Return status */
916     return Status;
917 }
918 
919 NTSTATUS
920 NTAPI
921 LdrpSetProtection(PVOID ViewBase,
922                   BOOLEAN Restore)
923 {
924     PIMAGE_NT_HEADERS NtHeaders;
925     PIMAGE_SECTION_HEADER Section;
926     NTSTATUS Status;
927     PVOID SectionBase;
928     SIZE_T SectionSize;
929     ULONG NewProtection, OldProtection, i;
930 
931     /* Get the NT headers */
932     NtHeaders = RtlImageNtHeader(ViewBase);
933     if (!NtHeaders) return STATUS_INVALID_IMAGE_FORMAT;
934 
935     /* Compute address of the first section header */
936     Section = IMAGE_FIRST_SECTION(NtHeaders);
937 
938     /* Go through all sections */
939     for (i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++)
940     {
941         /* Check for read-only non-zero section */
942         if ((Section->SizeOfRawData) &&
943             !(Section->Characteristics & IMAGE_SCN_MEM_WRITE))
944         {
945             /* Check if we are setting or restoring protection */
946             if (Restore)
947             {
948                 /* Set it to either EXECUTE or READONLY */
949                 if (Section->Characteristics & IMAGE_SCN_MEM_EXECUTE)
950                 {
951                     NewProtection = PAGE_EXECUTE;
952                 }
953                 else
954                 {
955                     NewProtection = PAGE_READONLY;
956                 }
957 
958                 /* Add PAGE_NOCACHE if needed */
959                 if (Section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED)
960                 {
961                     NewProtection |= PAGE_NOCACHE;
962                 }
963             }
964             else
965             {
966                 /* Enable write access */
967                 NewProtection = PAGE_READWRITE;
968             }
969 
970             /* Get the section VA */
971             SectionBase = (PVOID)((ULONG_PTR)ViewBase + Section->VirtualAddress);
972             SectionSize = Section->SizeOfRawData;
973             if (SectionSize)
974             {
975                 /* Set protection */
976                 Status = ZwProtectVirtualMemory(NtCurrentProcess(),
977                                                 &SectionBase,
978                                                 &SectionSize,
979                                                 NewProtection,
980                                                 &OldProtection);
981                 if (!NT_SUCCESS(Status)) return Status;
982             }
983         }
984 
985         /* Move to the next section */
986         Section++;
987     }
988 
989     /* Flush instruction cache if necessary */
990     if (Restore) ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0);
991     return STATUS_SUCCESS;
992 }
993 
994 /* NOTE: Not yet reviewed */
995 NTSTATUS
996 NTAPI
997 LdrpMapDll(IN PWSTR SearchPath OPTIONAL,
998            IN PWSTR DllPath2,
999            IN PWSTR DllName OPTIONAL,
1000            IN PULONG DllCharacteristics,
1001            IN BOOLEAN Static,
1002            IN BOOLEAN Redirect,
1003            OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry)
1004 {
1005     PTEB Teb = NtCurrentTeb();
1006     PPEB Peb = NtCurrentPeb();
1007     PWCHAR p1 = DllName;
1008     WCHAR TempChar;
1009     BOOLEAN KnownDll = FALSE;
1010     UNICODE_STRING FullDllName, BaseDllName;
1011     HANDLE SectionHandle = NULL, DllHandle = 0;
1012     UNICODE_STRING NtPathDllName;
1013     ULONG_PTR HardErrorParameters[2];
1014     UNICODE_STRING HardErrorDllName, HardErrorDllPath;
1015     ULONG Response;
1016     SIZE_T ViewSize = 0;
1017     PVOID ViewBase = NULL;
1018     PVOID ArbitraryUserPointer;
1019     PIMAGE_NT_HEADERS NtHeaders;
1020     NTSTATUS HardErrorStatus, Status;
1021     BOOLEAN OverlapDllFound = FALSE;
1022     ULONG_PTR ImageBase, ImageEnd;
1023     PLIST_ENTRY ListHead, NextEntry;
1024     PLDR_DATA_TABLE_ENTRY CandidateEntry, LdrEntry;
1025     ULONG_PTR CandidateBase, CandidateEnd;
1026     UNICODE_STRING OverlapDll;
1027     BOOLEAN RelocatableDll = TRUE;
1028     UNICODE_STRING IllegalDll;
1029     PVOID RelocData;
1030     ULONG RelocDataSize = 0;
1031 
1032     // FIXME: AppCompat stuff is missing
1033 
1034     if (ShowSnaps)
1035     {
1036         DPRINT1("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
1037                 DllName,
1038                 SearchPath ? SearchPath : L"");
1039     }
1040 
1041     /* Check if we have a known dll directory */
1042     if (LdrpKnownDllObjectDirectory && Redirect == FALSE)
1043     {
1044         /* Check if the path is full */
1045         while (*p1)
1046         {
1047             TempChar = *p1++;
1048             if (TempChar == '\\' || TempChar == '/' )
1049             {
1050                 /* Complete path, don't do Known Dll lookup */
1051                 goto SkipCheck;
1052             }
1053         }
1054 
1055         /* Try to find a Known DLL */
1056         Status = LdrpCheckForKnownDll(DllName,
1057                                       &FullDllName,
1058                                       &BaseDllName,
1059                                       &SectionHandle);
1060 
1061         if (!NT_SUCCESS(Status) && (Status != STATUS_DLL_NOT_FOUND))
1062         {
1063             /* Failure */
1064             DbgPrintEx(DPFLTR_LDR_ID,
1065                        DPFLTR_ERROR_LEVEL,
1066                        "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
1067                         __FUNCTION__,
1068                         DllName,
1069                         Status);
1070 
1071             return Status;
1072         }
1073     }
1074 
1075 SkipCheck:
1076 
1077     /* Check if the Known DLL Check returned something */
1078     if (!SectionHandle)
1079     {
1080         /* It didn't, so try to resolve the name now */
1081         if (LdrpResolveDllName(SearchPath,
1082                                DllName,
1083                                &FullDllName,
1084                                &BaseDllName))
1085         {
1086             /* Got a name, display a message */
1087             if (ShowSnaps)
1088             {
1089                 DPRINT1("LDR: Loading (%s) %wZ\n",
1090                         Static ? "STATIC" : "DYNAMIC",
1091                         &FullDllName);
1092             }
1093 
1094             /* Convert to NT Name */
1095             if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer,
1096                                               &NtPathDllName,
1097                                               NULL,
1098                                               NULL))
1099             {
1100                 /* Path was invalid */
1101                 return STATUS_OBJECT_PATH_SYNTAX_BAD;
1102             }
1103 
1104             /* Create a section for this dLL */
1105             Status = LdrpCreateDllSection(&NtPathDllName,
1106                                           DllHandle,
1107                                           DllCharacteristics,
1108                                           &SectionHandle);
1109 
1110             /* Free the NT Name */
1111             RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathDllName.Buffer);
1112 
1113             /* If we failed */
1114             if (!NT_SUCCESS(Status))
1115             {
1116                 /* Free the name strings and return */
1117                 LdrpFreeUnicodeString(&FullDllName);
1118                 LdrpFreeUnicodeString(&BaseDllName);
1119                 return Status;
1120             }
1121         }
1122         else
1123         {
1124             /* We couldn't resolve the name, is this a static load? */
1125             if (Static)
1126             {
1127                 /*
1128                  * This is BAD! Static loads are CRITICAL. Bugcheck!
1129                  * Initialize the strings for the error
1130                  */
1131                 RtlInitUnicodeString(&HardErrorDllName, DllName);
1132                 RtlInitUnicodeString(&HardErrorDllPath,
1133                                      DllPath2 ? DllPath2 : LdrpDefaultPath.Buffer);
1134 
1135                 /* Set them as error parameters */
1136                 HardErrorParameters[0] = (ULONG_PTR)&HardErrorDllName;
1137                 HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllPath;
1138 
1139                 /* Raise the hard error */
1140                 NtRaiseHardError(STATUS_DLL_NOT_FOUND,
1141                                  2,
1142                                  0x00000003,
1143                                  HardErrorParameters,
1144                                  OptionOk,
1145                                  &Response);
1146 
1147                 /* We're back, where we initializing? */
1148                 if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1149             }
1150 
1151             /* Return failure */
1152             return STATUS_DLL_NOT_FOUND;
1153         }
1154     }
1155     else
1156     {
1157         /* We have a section handle, so this is a known dll */
1158         KnownDll = TRUE;
1159     }
1160 
1161     /* Stuff the image name in the TIB, for the debugger */
1162     ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
1163     Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer;
1164 
1165     /* Map the DLL */
1166     ViewBase = NULL;
1167     ViewSize = 0;
1168     Status = NtMapViewOfSection(SectionHandle,
1169                                 NtCurrentProcess(),
1170                                 &ViewBase,
1171                                 0,
1172                                 0,
1173                                 NULL,
1174                                 &ViewSize,
1175                                 ViewShare,
1176                                 0,
1177                                 PAGE_READWRITE);
1178 
1179     /* Restore */
1180     Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
1181 
1182     /* Fail if we couldn't map it */
1183     if (!NT_SUCCESS(Status))
1184     {
1185         /* Close and return */
1186         NtClose(SectionHandle);
1187         return Status;
1188     }
1189 
1190     /* Get the NT Header */
1191     if (!(NtHeaders = RtlImageNtHeader(ViewBase)))
1192     {
1193         /* Invalid image, unmap, close handle and fail */
1194         NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1195         NtClose(SectionHandle);
1196         return STATUS_INVALID_IMAGE_FORMAT;
1197     }
1198 
1199     // FIXME: .NET support is missing
1200 
1201     /* Allocate an entry */
1202     if (!(LdrEntry = LdrpAllocateDataTableEntry(ViewBase)))
1203     {
1204         /* Invalid image, unmap, close handle and fail */
1205         NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1206         NtClose(SectionHandle);
1207         return STATUS_NO_MEMORY;
1208     }
1209 
1210     /* Setup the entry */
1211     LdrEntry->Flags = Static ? LDRP_STATIC_LINK : 0;
1212     if (Redirect) LdrEntry->Flags |= LDRP_REDIRECTED;
1213     LdrEntry->LoadCount = 0;
1214     LdrEntry->FullDllName = FullDllName;
1215     LdrEntry->BaseDllName = BaseDllName;
1216     LdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrEntry->DllBase);
1217 
1218     /* Show debug message */
1219     if (ShowSnaps)
1220     {
1221         DPRINT1("LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
1222                 &FullDllName,
1223                 &BaseDllName);
1224     }
1225 
1226     /* Insert this entry */
1227     LdrpInsertMemoryTableEntry(LdrEntry);
1228 
1229     // LdrpSendDllNotifications(LdrEntry, TRUE, Status == STATUS_IMAGE_NOT_AT_BASE)
1230 
1231     /* Check for invalid CPU Image */
1232     if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)
1233     {
1234         /* Load our header */
1235         PIMAGE_NT_HEADERS ImageNtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1236 
1237         /* Assume defaults if we don't have to run the Hard Error path */
1238         HardErrorStatus = STATUS_SUCCESS;
1239         Response = ResponseCancel;
1240 
1241         /* Are we an NT 3.0 image? [Do these still exist? LOL -- IAI] */
1242         if (ImageNtHeader->OptionalHeader.MajorSubsystemVersion <= 3)
1243         {
1244             /* Reset the entrypoint, save our Dll Name */
1245             LdrEntry->EntryPoint = 0;
1246             HardErrorParameters[0] = (ULONG_PTR)&FullDllName;
1247 
1248             /* Raise the error */
1249             HardErrorStatus = ZwRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH,
1250                                                1,
1251                                                1,
1252                                                HardErrorParameters,
1253                                                OptionOkCancel,
1254                                                &Response);
1255         }
1256 
1257         /* Check if the user pressed cancel */
1258         if (NT_SUCCESS(HardErrorStatus) && Response == ResponseCancel)
1259         {
1260             /* Remove the DLL from the lists */
1261             RemoveEntryList(&LdrEntry->InLoadOrderLinks);
1262             RemoveEntryList(&LdrEntry->InMemoryOrderLinks);
1263             RemoveEntryList(&LdrEntry->HashLinks);
1264 
1265             /* Remove the LDR Entry */
1266             RtlFreeHeap(LdrpHeap, 0, LdrEntry );
1267 
1268             /* Unmap and close section */
1269             NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1270             NtClose(SectionHandle);
1271 
1272             /* Did we do a hard error? */
1273             if (ImageNtHeader->OptionalHeader.MajorSubsystemVersion <= 3)
1274             {
1275                 /* Yup, so increase fatal error count if we are initializing */
1276                 if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1277             }
1278 
1279             /* Return failure */
1280             return STATUS_INVALID_IMAGE_FORMAT;
1281         }
1282     }
1283     else
1284     {
1285         /* The image was valid. Is it a DLL? */
1286         if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
1287         {
1288             /* Set the DLL Flag */
1289             LdrEntry->Flags |= LDRP_IMAGE_DLL;
1290         }
1291 
1292         /* If we're not a DLL, clear the entrypoint */
1293         if (!(LdrEntry->Flags & LDRP_IMAGE_DLL))
1294         {
1295             LdrEntry->EntryPoint = 0;
1296         }
1297     }
1298 
1299     /* Return it for the caller */
1300     *DataTableEntry = LdrEntry;
1301 
1302     /* Check if we loaded somewhere else */
1303     if (Status == STATUS_IMAGE_NOT_AT_BASE)
1304     {
1305         /* Write the flag */
1306         LdrEntry->Flags |= LDRP_IMAGE_NOT_AT_BASE;
1307 
1308         /* Find our region */
1309         ImageBase = (ULONG_PTR)NtHeaders->OptionalHeader.ImageBase;
1310         ImageEnd = ImageBase + ViewSize;
1311 
1312         DPRINT("LDR: LdrpMapDll Relocating Image Name %ws (%p-%p -> %p)\n", DllName, (PVOID)ImageBase, (PVOID)ImageEnd, ViewBase);
1313 
1314         /* Scan all the modules */
1315         ListHead = &Peb->Ldr->InLoadOrderModuleList;
1316         NextEntry = ListHead->Flink;
1317         while (NextEntry != ListHead)
1318         {
1319             /* Get the entry */
1320             CandidateEntry = CONTAINING_RECORD(NextEntry,
1321                                                LDR_DATA_TABLE_ENTRY,
1322                                                InLoadOrderLinks);
1323             NextEntry = NextEntry->Flink;
1324 
1325             /* Get the entry's bounds */
1326             CandidateBase = (ULONG_PTR)CandidateEntry->DllBase;
1327             CandidateEnd = CandidateBase + CandidateEntry->SizeOfImage;
1328 
1329             /* Make sure this entry isn't unloading */
1330             if (!CandidateEntry->InMemoryOrderLinks.Flink) continue;
1331 
1332             /* Check if our regions are colliding */
1333             if ((ImageBase >= CandidateBase && ImageBase <= CandidateEnd) ||
1334                 (ImageEnd >= CandidateBase && ImageEnd <= CandidateEnd) ||
1335                 (CandidateBase >= ImageBase && CandidateBase <= ImageEnd))
1336             {
1337                 /* Found who is overlapping */
1338                 OverlapDllFound = TRUE;
1339                 OverlapDll = CandidateEntry->FullDllName;
1340                 break;
1341             }
1342         }
1343 
1344         /* Check if we found the DLL overlapping with us */
1345         if (!OverlapDllFound)
1346         {
1347             /* It's not another DLL, it's memory already here */
1348             RtlInitUnicodeString(&OverlapDll, L"Dynamically Allocated Memory");
1349         }
1350 
1351         DPRINT("Overlapping DLL: %wZ\n", &OverlapDll);
1352 
1353         /* Are we dealing with a DLL? */
1354         if (LdrEntry->Flags & LDRP_IMAGE_DLL)
1355         {
1356             /* Check if relocs were stripped */
1357             if (!(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED))
1358             {
1359                 /* Get the relocation data */
1360                 RelocData = RtlImageDirectoryEntryToData(ViewBase,
1361                                                          TRUE,
1362                                                          IMAGE_DIRECTORY_ENTRY_BASERELOC,
1363                                                          &RelocDataSize);
1364 
1365                 /* Does the DLL not have any? */
1366                 if (!RelocData && !RelocDataSize)
1367                 {
1368                     /* We'll allow this and simply continue */
1369                     goto NoRelocNeeded;
1370                 }
1371             }
1372 
1373             /* See if this is an Illegal DLL - IE: user32 and kernel32 */
1374             RtlInitUnicodeString(&IllegalDll,L"user32.dll");
1375             if (RtlEqualUnicodeString(&BaseDllName, &IllegalDll, TRUE))
1376             {
1377                 /* Can't relocate user32 */
1378                 RelocatableDll = FALSE;
1379             }
1380             else
1381             {
1382                 RtlInitUnicodeString(&IllegalDll, L"kernel32.dll");
1383                 if (RtlEqualUnicodeString(&BaseDllName, &IllegalDll, TRUE))
1384                 {
1385                     /* Can't relocate kernel32 */
1386                     RelocatableDll = FALSE;
1387                 }
1388             }
1389 
1390             /* Known DLLs are not allowed to be relocated */
1391             if (KnownDll && !RelocatableDll)
1392             {
1393                 /* Setup for hard error */
1394                 HardErrorParameters[0] = (ULONG_PTR)&IllegalDll;
1395                 HardErrorParameters[1] = (ULONG_PTR)&OverlapDll;
1396 
1397                 DPRINT1("Illegal DLL relocation! %wZ overlaps %wZ\n", &OverlapDll, &IllegalDll);
1398 
1399                 /* Raise the error */
1400                 ZwRaiseHardError(STATUS_ILLEGAL_DLL_RELOCATION,
1401                                  2,
1402                                  3,
1403                                  HardErrorParameters,
1404                                  OptionOk,
1405                                  &Response);
1406 
1407                 /* If initializing, increase the error count */
1408                 if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1409 
1410                 /* Don't do relocation */
1411                 Status = STATUS_CONFLICTING_ADDRESSES;
1412                 goto FailRelocate;
1413             }
1414 
1415             /* Change the protection to prepare for relocation */
1416             Status = LdrpSetProtection(ViewBase, FALSE);
1417 
1418             /* Make sure we changed the protection */
1419             if (NT_SUCCESS(Status))
1420             {
1421                 /* Do the relocation */
1422                 Status = LdrRelocateImageWithBias(ViewBase, 0LL, NULL, STATUS_SUCCESS,
1423                     STATUS_CONFLICTING_ADDRESSES, STATUS_INVALID_IMAGE_FORMAT);
1424 
1425                 if (NT_SUCCESS(Status))
1426                 {
1427                     /* Stuff the image name in the TIB, for the debugger */
1428                     ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
1429                     Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer;
1430 #if 0
1431                     /* Map the DLL */
1432                     Status = NtMapViewOfSection(SectionHandle,
1433                                                 NtCurrentProcess(),
1434                                                 &ViewBase,
1435                                                 0,
1436                                                 0,
1437                                                 NULL,
1438                                                 &ViewSize,
1439                                                 ViewShare,
1440                                                 0,
1441                                                 PAGE_READWRITE);
1442 #endif
1443                     /* Restore */
1444                     Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
1445 
1446                     /* Return the protection */
1447                     Status = LdrpSetProtection(ViewBase, TRUE);
1448                 }
1449             }
1450 FailRelocate:
1451             /* Handle any kind of failure */
1452             if (!NT_SUCCESS(Status))
1453             {
1454                 /* Remove it from the lists */
1455                 RemoveEntryList(&LdrEntry->InLoadOrderLinks);
1456                 RemoveEntryList(&LdrEntry->InMemoryOrderLinks);
1457                 RemoveEntryList(&LdrEntry->HashLinks);
1458 
1459                 /* Unmap it, clear the entry */
1460                 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
1461                 LdrEntry = NULL;
1462             }
1463 
1464             /* Show debug message */
1465             if (ShowSnaps)
1466             {
1467                 DPRINT1("LDR: Fixups %successfully re-applied @ %p\n",
1468                         NT_SUCCESS(Status) ? "s" : "uns", ViewBase);
1469             }
1470         }
1471         else
1472         {
1473 NoRelocNeeded:
1474             /* Not a DLL, or no relocation needed */
1475             Status = STATUS_SUCCESS;
1476 
1477             /* Stuff the image name in the TIB, for the debugger */
1478             ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
1479             Teb->NtTib.ArbitraryUserPointer = FullDllName.Buffer;
1480 #if 0
1481             /* Map the DLL */
1482             Status = NtMapViewOfSection(SectionHandle,
1483                                         NtCurrentProcess(),
1484                                         &ViewBase,
1485                                         0,
1486                                         0,
1487                                         NULL,
1488                                         &ViewSize,
1489                                         ViewShare,
1490                                         0,
1491                                         PAGE_READWRITE);
1492 #endif
1493             /* Restore */
1494             Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
1495 
1496             /* Show debug message */
1497             if (ShowSnaps)
1498             {
1499                 DPRINT1("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase);
1500             }
1501         }
1502     }
1503 
1504     // FIXME: LdrpCheckCorImage() is missing
1505 
1506     /* Check if this is an SMP Machine and a DLL */
1507     if ((LdrpNumberOfProcessors > 1) &&
1508         (LdrEntry && (LdrEntry->Flags & LDRP_IMAGE_DLL)))
1509     {
1510         /* Validate the image for MP */
1511         LdrpValidateImageForMp(LdrEntry);
1512     }
1513 
1514     // FIXME: LdrpCorUnloadImage() is missing
1515 
1516     /* Close section and return status */
1517     NtClose(SectionHandle);
1518     return Status;
1519 }
1520 
1521 PLDR_DATA_TABLE_ENTRY
1522 NTAPI
1523 LdrpAllocateDataTableEntry(IN PVOID BaseAddress)
1524 {
1525     PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
1526     PIMAGE_NT_HEADERS NtHeader;
1527 
1528     /* Make sure the header is valid */
1529     NtHeader = RtlImageNtHeader(BaseAddress);
1530     DPRINT("LdrpAllocateDataTableEntry(%p), NtHeader %p\n", BaseAddress, NtHeader);
1531 
1532     if (NtHeader)
1533     {
1534         /* Allocate an entry */
1535         LdrEntry = RtlAllocateHeap(LdrpHeap,
1536                                    HEAP_ZERO_MEMORY,
1537                                    sizeof(LDR_DATA_TABLE_ENTRY));
1538 
1539         /* Make sure we got one */
1540         if (LdrEntry)
1541         {
1542             /* Set it up */
1543             LdrEntry->DllBase = BaseAddress;
1544             LdrEntry->SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
1545             LdrEntry->TimeDateStamp = NtHeader->FileHeader.TimeDateStamp;
1546             LdrEntry->PatchInformation = NULL;
1547         }
1548     }
1549 
1550     /* Return the entry */
1551     return LdrEntry;
1552 }
1553 
1554 VOID
1555 NTAPI
1556 LdrpInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
1557 {
1558     PPEB_LDR_DATA PebData = NtCurrentPeb()->Ldr;
1559     ULONG i;
1560 
1561     /* Insert into hash table */
1562     i = LDR_GET_HASH_ENTRY(LdrEntry->BaseDllName.Buffer[0]);
1563     InsertTailList(&LdrpHashTable[i], &LdrEntry->HashLinks);
1564 
1565     /* Insert into other lists */
1566     InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks);
1567     InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderLinks);
1568 }
1569 
1570 VOID
1571 NTAPI
1572 LdrpFinalizeAndDeallocateDataTableEntry(IN PLDR_DATA_TABLE_ENTRY Entry)
1573 {
1574     /* Sanity check */
1575     ASSERT(Entry != NULL);
1576 
1577     /* Release the activation context if it exists and wasn't already released */
1578     if ((Entry->EntryPointActivationContext) &&
1579         (Entry->EntryPointActivationContext != INVALID_HANDLE_VALUE))
1580     {
1581         /* Mark it as invalid */
1582         RtlReleaseActivationContext(Entry->EntryPointActivationContext);
1583         Entry->EntryPointActivationContext = INVALID_HANDLE_VALUE;
1584     }
1585 
1586     /* Release the full dll name string */
1587     if (Entry->FullDllName.Buffer) LdrpFreeUnicodeString(&Entry->FullDllName);
1588 
1589     /* Finally free the entry's memory */
1590     RtlFreeHeap(LdrpHeap, 0, Entry);
1591 }
1592 
1593 BOOLEAN
1594 NTAPI
1595 LdrpCheckForLoadedDllHandle(IN PVOID Base,
1596                             OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
1597 {
1598     PLDR_DATA_TABLE_ENTRY Current;
1599     PLIST_ENTRY ListHead, Next;
1600 
1601     /* Check the cache first */
1602     if ((LdrpLoadedDllHandleCache) &&
1603         (LdrpLoadedDllHandleCache->DllBase == Base))
1604     {
1605         /* We got lucky, return the cached entry */
1606         *LdrEntry = LdrpLoadedDllHandleCache;
1607         return TRUE;
1608     }
1609 
1610     /* Time for a lookup */
1611     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1612     Next = ListHead->Flink;
1613     while (Next != ListHead)
1614     {
1615         /* Get the current entry */
1616         Current = CONTAINING_RECORD(Next,
1617                                     LDR_DATA_TABLE_ENTRY,
1618                                     InLoadOrderLinks);
1619 
1620         /* Make sure it's not unloading and check for a match */
1621         if ((Current->InMemoryOrderLinks.Flink) && (Base == Current->DllBase))
1622         {
1623             /* Save in cache */
1624             LdrpLoadedDllHandleCache = Current;
1625 
1626             /* Return it */
1627             *LdrEntry = Current;
1628             return TRUE;
1629         }
1630 
1631         /* Move to the next one */
1632         Next = Next->Flink;
1633     }
1634 
1635     /* Nothing found */
1636     return FALSE;
1637 }
1638 
1639 NTSTATUS
1640 NTAPI
1641 LdrpResolveFullName(IN PUNICODE_STRING OriginalName,
1642                     IN PUNICODE_STRING PathName,
1643                     IN PUNICODE_STRING FullPathName,
1644                     IN PUNICODE_STRING *ExpandedName)
1645 {
1646     NTSTATUS Status = STATUS_SUCCESS;
1647 //    RTL_PATH_TYPE PathType;
1648 //    BOOLEAN InvalidName;
1649     ULONG Length;
1650 
1651     /* Display debug output if snaps are on */
1652     if (ShowSnaps)
1653     {
1654         DbgPrintEx(DPFLTR_LDR_ID,
1655                    DPFLTR_ERROR_LEVEL,
1656                    "LDR: %s - Expanding full name of %wZ\n",
1657                    __FUNCTION__,
1658                    OriginalName);
1659     }
1660 
1661     /* FIXME: Lock the PEB */
1662     //RtlEnterCriticalSection(&FastPebLock);
1663 #if 0
1664     /* Get the path name */
1665     Length = RtlGetFullPathName_Ustr(OriginalName,
1666                                      PathName->Length,
1667                                      PathName->Buffer,
1668                                      NULL,
1669                                      &InvalidName,
1670                                      &PathType);
1671 #else
1672     Length = 0;
1673 #endif
1674     if (!(Length) || (Length > UNICODE_STRING_MAX_BYTES))
1675     {
1676         /* Fail */
1677         Status = STATUS_NAME_TOO_LONG;
1678         goto Quickie;
1679     }
1680 
1681     /* Check if the length hasn't changed */
1682     if (Length <= PathName->Length)
1683     {
1684         /* Return the same thing */
1685         *ExpandedName = PathName;
1686         PathName->Length = (USHORT)Length;
1687         goto Quickie;
1688     }
1689 
1690     /* Sanity check */
1691     ASSERT(Length >= sizeof(WCHAR));
1692 
1693     /* Allocate a string */
1694     Status = LdrpAllocateUnicodeString(FullPathName, Length - sizeof(WCHAR));
1695     if (!NT_SUCCESS(Status)) goto Quickie;
1696 
1697     /* Now get the full path again */
1698 #if 0
1699     Length = RtlGetFullPathName_Ustr(OriginalName,
1700                                      FullPathName->Length,
1701                                      FullPathName->Buffer,
1702                                      NULL,
1703                                      &InvalidName,
1704                                      &PathType);
1705 #else
1706     Length = 0;
1707 #endif
1708     if (!(Length) || (Length > FullPathName->Length))
1709     {
1710         /* Fail */
1711         LdrpFreeUnicodeString(FullPathName);
1712         Status = STATUS_NAME_TOO_LONG;
1713     }
1714     else
1715     {
1716         /* Return the expanded name */
1717         *ExpandedName = FullPathName;
1718         FullPathName->Length = (USHORT)Length;
1719     }
1720 
1721 Quickie:
1722     /* FIXME: Unlock the PEB */
1723     //RtlLeaveCriticalSection(&FastPebLock);
1724 
1725     /* Display debug output if snaps are on */
1726     if (ShowSnaps)
1727     {
1728         /* Check which output to use -- failure or success */
1729         if (NT_SUCCESS(Status))
1730         {
1731             DbgPrintEx(DPFLTR_LDR_ID,
1732                        DPFLTR_ERROR_LEVEL,
1733                        "LDR: %s - Expanded to %wZ\n",
1734                        __FUNCTION__,
1735                        *ExpandedName);
1736         }
1737         else
1738         {
1739             DbgPrintEx(DPFLTR_LDR_ID,
1740                        DPFLTR_ERROR_LEVEL,
1741                        "LDR: %s - Failed to expand %wZ; 0x%08x\n",
1742                        __FUNCTION__,
1743                        OriginalName,
1744                        Status);
1745         }
1746     }
1747 
1748     /* If we failed, return NULL */
1749     if (!NT_SUCCESS(Status)) *ExpandedName = NULL;
1750 
1751     /* Return status */
1752     return Status;
1753 }
1754 
1755 NTSTATUS
1756 NTAPI
1757 LdrpSearchPath(IN PWCHAR *SearchPath,
1758                IN PWCHAR DllName,
1759                IN PUNICODE_STRING PathName,
1760                IN PUNICODE_STRING FullPathName,
1761                IN PUNICODE_STRING *ExpandedName)
1762 {
1763     BOOLEAN TryAgain = FALSE;
1764     PWCHAR ActualSearchPath = *SearchPath;
1765     UNICODE_STRING TestName;
1766     NTSTATUS Status;
1767     PWCHAR Buffer, BufEnd = NULL;
1768     ULONG Length = 0;
1769     WCHAR p;
1770     //PWCHAR pp;
1771 
1772     /* Check if we don't have a search path */
1773     if (!ActualSearchPath) *SearchPath = LdrpDefaultPath.Buffer;
1774 
1775     /* Display debug output if snaps are on */
1776     if (ShowSnaps)
1777     {
1778         DbgPrintEx(DPFLTR_LDR_ID,
1779                    DPFLTR_ERROR_LEVEL,
1780                    "LDR: %s - Looking for %ws in %ws\n",
1781                    __FUNCTION__,
1782                    DllName,
1783                    *SearchPath);
1784     }
1785 
1786     /* Check if we're dealing with a relative path */
1787     if (RtlDetermineDosPathNameType_U(DllName) != RtlPathTypeRelative)
1788     {
1789         /* Good, we're not. Create the name string */
1790         Status = RtlInitUnicodeStringEx(&TestName, DllName);
1791         if (!NT_SUCCESS(Status)) goto Quickie;
1792 
1793         /* Make sure it exists */
1794         #if 0
1795         if (!RtlDoesFileExists_UstrEx(&TestName, TRUE))
1796         {
1797             /* It doesn't, fail */
1798             Status = STATUS_DLL_NOT_FOUND;
1799             goto Quickie;
1800         }
1801         #endif
1802 
1803         /* Resolve the full name */
1804         Status = LdrpResolveFullName(&TestName,
1805                                      PathName,
1806                                      FullPathName,
1807                                      ExpandedName);
1808         goto Quickie;
1809     }
1810 
1811     /* FIXME: Handle relative case semicolon-lookup here */
1812 
1813     /* Calculate length */
1814     Length += (ULONG)wcslen(DllName) + 1;
1815     if (Length > UNICODE_STRING_MAX_CHARS)
1816     {
1817         /* Too long, fail */
1818         Status = STATUS_NAME_TOO_LONG;
1819         goto Quickie;
1820     }
1821 
1822     /* Allocate buffer */
1823     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1824     if (!Buffer)
1825     {
1826         /* Fail */
1827         Status = STATUS_NO_MEMORY;
1828         goto Quickie;
1829     }
1830 
1831     /* FIXME: Setup TestName here */
1832     Status = STATUS_NOT_FOUND;
1833     BufEnd = Buffer;
1834 
1835     /* Start loop */
1836     do
1837     {
1838         /* Get character */
1839         p = *ActualSearchPath;
1840         if (!(p) || (p == ';'))
1841         {
1842             /* FIXME: We don't have a character, or is a semicolon.*/
1843 
1844             /* Display debug output if snaps are on */
1845             if (ShowSnaps)
1846             {
1847                 DbgPrintEx(DPFLTR_LDR_ID,
1848                            DPFLTR_ERROR_LEVEL,
1849                            "LDR: %s - Looking for %ws\n",
1850                            __FUNCTION__,
1851                            Buffer);
1852             }
1853 
1854             /* Sanity check */
1855             TestName.Length = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR);
1856 #if 0
1857             ASSERT(TestName.Length < TestName.MaximumLength);
1858 #endif
1859 
1860             /* Check if the file exists */
1861             #if 0
1862             if (RtlDoesFileExists_UstrEx(&TestName, FALSE))
1863             #endif
1864             {
1865                 /* It does. Reallocate the buffer */
1866                 TestName.MaximumLength = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR) + sizeof(WCHAR);
1867                 TestName.Buffer = RtlReAllocateHeap(RtlGetProcessHeap(),
1868                                                     0,
1869                                                     Buffer,
1870                                                     TestName.MaximumLength);
1871                 if (!TestName.Buffer)
1872                 {
1873                     /* Keep the old one */
1874                     TestName.Buffer = Buffer;
1875                 }
1876                 else
1877                 {
1878                     /* Update buffer */
1879                     Buffer = TestName.Buffer;
1880                 }
1881 
1882                 /* Make sure we have a buffer at least */
1883                 ASSERT(TestName.Buffer);
1884 
1885                 /* Resolve the name */
1886                 *SearchPath = ActualSearchPath++;
1887                 Status = LdrpResolveFullName(&TestName,
1888                                              PathName,
1889                                              FullPathName,
1890                                              ExpandedName);
1891                 break;
1892             }
1893 
1894             /* Update buffer end */
1895             BufEnd = Buffer;
1896 
1897             /* Update string position */
1898             //pp = ActualSearchPath++;
1899         }
1900         else
1901         {
1902             /* Otherwise, write the character */
1903             *BufEnd = p;
1904             BufEnd++;
1905         }
1906 
1907         /* Check if the string is empty, meaning we're done */
1908         if (!(*ActualSearchPath)) TryAgain = TRUE;
1909 
1910         /* Advance in the string */
1911         ActualSearchPath++;
1912     } while (!TryAgain);
1913 
1914     /* Check if we had a buffer and free it */
1915     if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1916 
1917 Quickie:
1918     /* Check if we got here through failure */
1919     if (!NT_SUCCESS(Status)) *ExpandedName = NULL;
1920 
1921     /* Display debug output if snaps are on */
1922     if (ShowSnaps)
1923     {
1924         /* Check which output to use -- failure or success */
1925         if (NT_SUCCESS(Status))
1926         {
1927             DbgPrintEx(DPFLTR_LDR_ID,
1928                        DPFLTR_ERROR_LEVEL,
1929                        "LDR: %s - Returning %wZ\n",
1930                        __FUNCTION__,
1931                        *ExpandedName);
1932         }
1933         else
1934         {
1935             DbgPrintEx(DPFLTR_LDR_ID,
1936                        DPFLTR_ERROR_LEVEL,
1937                        "LDR: %s -  Unable to locate %ws in %ws: 0x%08x\n",
1938                        __FUNCTION__,
1939                        DllName,
1940                        ActualSearchPath,
1941                        Status);
1942         }
1943     }
1944 
1945     /* Return status */
1946     return Status;
1947 }
1948 
1949 
1950 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1951 BOOLEAN
1952 NTAPI
1953 LdrpCheckForLoadedDll(IN PWSTR DllPath,
1954                       IN PUNICODE_STRING DllName,
1955                       IN BOOLEAN Flag,
1956                       IN BOOLEAN RedirectedDll,
1957                       OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
1958 {
1959     ULONG HashIndex;
1960     PLIST_ENTRY ListHead, ListEntry;
1961     PLDR_DATA_TABLE_ENTRY CurEntry;
1962     BOOLEAN FullPath = FALSE;
1963     PWCHAR wc;
1964     WCHAR NameBuf[266];
1965     UNICODE_STRING FullDllName, NtPathName;
1966     ULONG Length;
1967     OBJECT_ATTRIBUTES ObjectAttributes;
1968     NTSTATUS Status;
1969     HANDLE FileHandle, SectionHandle;
1970     IO_STATUS_BLOCK Iosb;
1971     PVOID ViewBase = NULL;
1972     SIZE_T ViewSize = 0;
1973     PIMAGE_NT_HEADERS NtHeader, NtHeader2;
1974     DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %u %u %p)\n", DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"", DllName, Flag, RedirectedDll, LdrEntry);
1975 
1976     /* Check if a dll name was provided */
1977     if (!(DllName->Buffer) || !(DllName->Buffer[0])) return FALSE;
1978 
1979     /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1980     /* FIXME: Warning, code does not support redirection at all */
1981 
1982     /* Look in the hash table if flag was set */
1983 lookinhash:
1984     if (Flag  /* the second check is a hack */ && !RedirectedDll)
1985     {
1986         /* FIXME: if we get redirected dll it means that we also get a full path so we need to find its filename for the hash lookup */
1987 
1988         /* Get hash index */
1989         HashIndex = LDR_GET_HASH_ENTRY(DllName->Buffer[0]);
1990 
1991         /* Traverse that list */
1992         ListHead = &LdrpHashTable[HashIndex];
1993         ListEntry = ListHead->Flink;
1994         while (ListEntry != ListHead)
1995         {
1996             /* Get the current entry */
1997             CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
1998 
1999             /* Check base name of that module */
2000             if (RtlEqualUnicodeString(DllName, &CurEntry->BaseDllName, TRUE))
2001             {
2002                 /* It matches, return it */
2003                 *LdrEntry = CurEntry;
2004                 return TRUE;
2005             }
2006 
2007             /* Advance to the next entry */
2008             ListEntry = ListEntry->Flink;
2009         }
2010 
2011         /* Module was not found, return failure */
2012         return FALSE;
2013     }
2014 
2015     /* Check if this is a redirected DLL */
2016     if (RedirectedDll)
2017     {
2018         /* Redirected dlls already have a full path */
2019         FullPath = TRUE;
2020         FullDllName = *DllName;
2021     }
2022     else
2023     {
2024         /* Check if there is a full path in this DLL */
2025         wc = DllName->Buffer;
2026         while (*wc)
2027         {
2028             /* Check for a slash in the current position*/
2029             if ((*wc == L'\\') || (*wc == L'/'))
2030             {
2031                 /* Found the slash, so dll name contains path */
2032                 FullPath = TRUE;
2033 
2034                 /* Setup full dll name string */
2035                 FullDllName.Buffer = NameBuf;
2036 
2037                 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2038                 Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer,
2039                                             DllName->Buffer,
2040                                             NULL,
2041                                             sizeof(NameBuf) - sizeof(UNICODE_NULL),
2042                                             FullDllName.Buffer,
2043                                             NULL);
2044 
2045                 /* Check if that was successful */
2046                 if (!(Length) || (Length > (sizeof(NameBuf) - sizeof(UNICODE_NULL))))
2047                 {
2048                     if (ShowSnaps)
2049                     {
2050                         DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %wZ: 0x%08x\n",
2051                             &DllName, Length);
2052                     }
2053                 }
2054 
2055                 /* Full dll name is found */
2056                 FullDllName.Length = Length;
2057                 FullDllName.MaximumLength = FullDllName.Length + sizeof(UNICODE_NULL);
2058                 break;
2059             }
2060 
2061             wc++;
2062         }
2063     }
2064 
2065     /* Go check the hash table */
2066     if (!FullPath)
2067     {
2068         Flag = TRUE;
2069         goto lookinhash;
2070     }
2071 
2072     /* FIXME: Warning, activation context missing */
2073     DPRINT("Warning, activation context missing\n");
2074 
2075     /* NOTE: From here on down, everything looks good */
2076 
2077     /* Loop the module list */
2078     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2079     ListEntry = ListHead->Flink;
2080     while (ListEntry != ListHead)
2081     {
2082         /* Get the current entry and advance to the next one */
2083         CurEntry = CONTAINING_RECORD(ListEntry,
2084                                      LDR_DATA_TABLE_ENTRY,
2085                                      InLoadOrderLinks);
2086         ListEntry = ListEntry->Flink;
2087 
2088         /* Check if it's being unloaded */
2089         if (!CurEntry->InMemoryOrderLinks.Flink) continue;
2090 
2091         /* Check if name matches */
2092         if (RtlEqualUnicodeString(&FullDllName,
2093                                   &CurEntry->FullDllName,
2094                                   TRUE))
2095         {
2096             /* Found it */
2097             *LdrEntry = CurEntry;
2098             return TRUE;
2099         }
2100     }
2101 
2102     /* Convert given path to NT path */
2103     if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer,
2104                                       &NtPathName,
2105                                       NULL,
2106                                       NULL))
2107     {
2108         /* Fail if conversion failed */
2109         return FALSE;
2110     }
2111 
2112     /* Initialize object attributes and open it */
2113     InitializeObjectAttributes(&ObjectAttributes,
2114                                &NtPathName,
2115                                OBJ_CASE_INSENSITIVE,
2116                                NULL,
2117                                NULL);
2118     Status = NtOpenFile(&FileHandle,
2119                         SYNCHRONIZE | FILE_EXECUTE,
2120                         &ObjectAttributes,
2121                         &Iosb,
2122                         FILE_SHARE_READ | FILE_SHARE_DELETE,
2123                         FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
2124 
2125     /* Free NT path name */
2126     RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
2127 
2128     /* If opening the file failed - return failure */
2129     if (!NT_SUCCESS(Status)) return FALSE;
2130 
2131     /* Create a section for this file */
2132     Status = NtCreateSection(&SectionHandle,
2133                              SECTION_MAP_READ |
2134                              SECTION_MAP_EXECUTE |
2135                              SECTION_MAP_WRITE,
2136                              NULL,
2137                              NULL,
2138                              PAGE_EXECUTE,
2139                              SEC_COMMIT,
2140                              FileHandle);
2141 
2142     /* Close file handle */
2143     NtClose(FileHandle);
2144 
2145     /* If creating section failed - return failure */
2146     if (!NT_SUCCESS(Status)) return FALSE;
2147 
2148     /* Map view of this section */
2149     Status = ZwMapViewOfSection(SectionHandle,
2150                                 NtCurrentProcess(),
2151                                 &ViewBase,
2152                                 0,
2153                                 0,
2154                                 NULL,
2155                                 &ViewSize,
2156                                 ViewShare,
2157                                 0,
2158                                 PAGE_EXECUTE);
2159 
2160     /* Close section handle */
2161     NtClose(SectionHandle);
2162 
2163     /* If section mapping failed - return failure */
2164     if (!NT_SUCCESS(Status)) return FALSE;
2165 
2166     /* Get pointer to the NT header of this section */
2167     Status = RtlImageNtHeaderEx(0, ViewBase, ViewSize, &NtHeader);
2168     if (!(NT_SUCCESS(Status)) || !(NtHeader))
2169     {
2170         /* Unmap the section and fail */
2171         NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2172         return FALSE;
2173     }
2174 
2175     /* Go through the list of modules again */
2176     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2177     ListEntry = ListHead->Flink;
2178     while (ListEntry != ListHead)
2179     {
2180         /* Get the current entry and advance to the next one */
2181         CurEntry = CONTAINING_RECORD(ListEntry,
2182                                      LDR_DATA_TABLE_ENTRY,
2183                                      InLoadOrderLinks);
2184         ListEntry = ListEntry->Flink;
2185 
2186         /* Check if it's in the process of being unloaded */
2187         if (!CurEntry->InMemoryOrderLinks.Flink) continue;
2188 
2189         /* The header is untrusted, use SEH */
2190         _SEH2_TRY
2191         {
2192             /* Check if timedate stamp and sizes match */
2193             if ((CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp) &&
2194                 (CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage))
2195             {
2196                 /* Time, date and size match. Let's compare their headers */
2197                 NtHeader2 = RtlImageNtHeader(CurEntry->DllBase);
2198                 if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS)))
2199                 {
2200                     /* Headers match too! Finally ask the kernel to compare mapped files */
2201                     Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase);
2202                     if (NT_SUCCESS(Status))
2203                     {
2204                         /* This is our entry!, unmap and return success */
2205                         *LdrEntry = CurEntry;
2206                         NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2207                         _SEH2_YIELD(return TRUE;)
2208                     }
2209                 }
2210             }
2211         }
2212         _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
2213         {
2214             _SEH2_YIELD(break;)
2215         }
2216         _SEH2_END;
2217     }
2218 
2219     /* Unmap the section and fail */
2220     NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2221     return FALSE;
2222 }
2223 
2224 NTSTATUS
2225 NTAPI
2226 LdrpGetProcedureAddress(
2227     _In_ PVOID BaseAddress,
2228     _In_opt_ _When_(Ordinal == 0, _Notnull_) PANSI_STRING Name,
2229     _In_opt_ _When_(Name == NULL, _In_range_(>, 0)) ULONG Ordinal,
2230     _Out_ PVOID *ProcedureAddress,
2231     _In_ BOOLEAN ExecuteInit)
2232 {
2233     NTSTATUS Status = STATUS_SUCCESS;
2234     UCHAR ImportBuffer[64]; // 128 since NT6.2
2235     PLDR_DATA_TABLE_ENTRY LdrEntry;
2236     IMAGE_THUNK_DATA Thunk;
2237     PVOID ImageBase;
2238     PIMAGE_IMPORT_BY_NAME ImportName = NULL;
2239     PIMAGE_EXPORT_DIRECTORY ExportDir;
2240     ULONG ExportDirSize, Length;
2241     PLIST_ENTRY Entry;
2242 
2243     /* Show debug message */
2244     if (ShowSnaps) DPRINT1("LDR: LdrGetProcedureAddress by ");
2245 
2246     /* Check if we got a name */
2247     if (Name)
2248     {
2249         /* Show debug message */
2250         if (ShowSnaps) DbgPrint("NAME - %s\n", Name->Buffer);
2251 
2252         /* Make sure it's not too long */
2253         Length = Name->Length +
2254                  sizeof(CHAR) +
2255                  FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name);
2256         if (Length > UNICODE_STRING_MAX_BYTES)
2257         {
2258             /* Won't have enough space to add the hint */
2259             return STATUS_NAME_TOO_LONG;
2260         }
2261 
2262         /* Check if our buffer is large enough */
2263         if (Length > sizeof(ImportBuffer))
2264         {
2265             /* Allocate from heap, plus 2 bytes for the Hint */
2266             ImportName = RtlAllocateHeap(RtlGetProcessHeap(),
2267                                          0,
2268                                          Length);
2269             if (!ImportName)
2270             {
2271                 /* Return STATUS_INSUFFICIENT_RESOURCES since NT6.2 */
2272                 return STATUS_INVALID_PARAMETER;
2273             }
2274         }
2275         else
2276         {
2277             /* Use our internal buffer */
2278             ImportName = (PIMAGE_IMPORT_BY_NAME)ImportBuffer;
2279         }
2280 
2281         /* Clear the hint */
2282         ImportName->Hint = 0;
2283 
2284         /* Copy the name and null-terminate it */
2285         RtlCopyMemory(ImportName->Name, Name->Buffer, Name->Length);
2286         ImportName->Name[Name->Length] = ANSI_NULL;
2287 
2288         /* Clear the high bit */
2289         ImageBase = ImportName;
2290         Thunk.u1.AddressOfData = 0;
2291     }
2292     else
2293     {
2294         /* Do it by ordinal */
2295         ImageBase = NULL;
2296 
2297         /* Show debug message */
2298         if (ShowSnaps) DbgPrint("ORDINAL - %lx\n", Ordinal);
2299 
2300         /* Make sure an ordinal was given */
2301         if (!Ordinal)
2302         {
2303             /* No ordinal */
2304             DPRINT1("No ordinal and no name\n");
2305             return STATUS_INVALID_PARAMETER;
2306         }
2307 
2308         /* Set the original flag in the thunk */
2309         Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG;
2310     }
2311 
2312     /* Acquire lock unless we are initting */
2313     if (!LdrpInLdrInit) RtlEnterCriticalSection(&LdrpLoaderLock);
2314 
2315     _SEH2_TRY
2316     {
2317         /* Try to find the loaded DLL */
2318         if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
2319         {
2320             /* Invalid base */
2321             DPRINT1("Invalid base address %p\n", BaseAddress);
2322             Status = STATUS_DLL_NOT_FOUND;
2323             _SEH2_YIELD(goto Quickie;)
2324         }
2325 
2326         /* Get the pointer to the export directory */
2327         ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
2328                                                  TRUE,
2329                                                  IMAGE_DIRECTORY_ENTRY_EXPORT,
2330                                                  &ExportDirSize);
2331 
2332         if (!ExportDir)
2333         {
2334             DPRINT1("Image %wZ has no exports, but were trying to get procedure %Z. BaseAddress asked 0x%p, got entry BA 0x%p\n",
2335                     &LdrEntry->BaseDllName, Name, BaseAddress, LdrEntry->DllBase);
2336             Status = STATUS_PROCEDURE_NOT_FOUND;
2337             _SEH2_YIELD(goto Quickie;)
2338         }
2339 
2340         /* Now get the thunk */
2341         Status = LdrpSnapThunk(LdrEntry->DllBase,
2342                                ImageBase,
2343                                &Thunk,
2344                                &Thunk,
2345                                ExportDir,
2346                                ExportDirSize,
2347                                FALSE,
2348                                NULL);
2349 
2350         /* Finally, see if we're supposed to run the init routines */
2351         if ((NT_SUCCESS(Status)) && (ExecuteInit))
2352         {
2353             /*
2354             * It's possible a forwarded entry had us load the DLL. In that case,
2355             * then we will call its DllMain. Use the last loaded DLL for this.
2356             */
2357             Entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink;
2358             LdrEntry = CONTAINING_RECORD(Entry,
2359                                          LDR_DATA_TABLE_ENTRY,
2360                                          InInitializationOrderLinks);
2361 
2362             /* Make sure we didn't process it yet*/
2363             if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
2364             {
2365                 /* Call the init routine */
2366                 _SEH2_TRY
2367                 {
2368                     Status = LdrpRunInitializeRoutines(NULL);
2369                 }
2370                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2371                 {
2372                     /* Get the exception code */
2373                     Status = _SEH2_GetExceptionCode();
2374                 }
2375                 _SEH2_END;
2376             }
2377         }
2378 
2379         /* Make sure we're OK till here */
2380         if (NT_SUCCESS(Status))
2381         {
2382             /* Return the address */
2383             *ProcedureAddress = (PVOID)Thunk.u1.Function;
2384         }
2385     }
2386     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2387     {
2388         /* Just ignore exceptions */
2389     }
2390     _SEH2_END;
2391 
2392 Quickie:
2393     /* Cleanup */
2394     if (ImportName && (ImportName != (PIMAGE_IMPORT_BY_NAME)ImportBuffer))
2395     {
2396         /* We allocated from heap, free it */
2397         RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName);
2398     }
2399 
2400     /* Release the CS if we entered it */
2401     if (!LdrpInLdrInit) RtlLeaveCriticalSection(&LdrpLoaderLock);
2402 
2403     /* We're done */
2404     return Status;
2405 }
2406 
2407 NTSTATUS
2408 NTAPI
2409 LdrpLoadDll(IN BOOLEAN Redirected,
2410             IN PWSTR DllPath OPTIONAL,
2411             IN PULONG DllCharacteristics OPTIONAL,
2412             IN PUNICODE_STRING DllName,
2413             OUT PVOID *BaseAddress,
2414             IN BOOLEAN CallInit)
2415 {
2416     PPEB Peb = NtCurrentPeb();
2417     NTSTATUS Status = STATUS_SUCCESS;
2418     const WCHAR *p;
2419     BOOLEAN GotExtension;
2420     WCHAR c;
2421     WCHAR NameBuffer[MAX_PATH + 6];
2422     UNICODE_STRING RawDllName;
2423     PLDR_DATA_TABLE_ENTRY LdrEntry;
2424     BOOLEAN InInit = LdrpInLdrInit;
2425 
2426     /* Save the Raw DLL Name */
2427     if (DllName->Length >= sizeof(NameBuffer)) return STATUS_NAME_TOO_LONG;
2428     RtlInitEmptyUnicodeString(&RawDllName, NameBuffer, sizeof(NameBuffer));
2429     RtlCopyUnicodeString(&RawDllName, DllName);
2430 
2431     /* Find the extension, if present */
2432     /* NOTE: Access violation is expected here in some cases (Buffer[-1]) */
2433     p = DllName->Buffer + DllName->Length / sizeof(WCHAR) - 1;
2434     GotExtension = FALSE;
2435     while (p >= DllName->Buffer)
2436     {
2437         c = *p--;
2438         if (c == L'.')
2439         {
2440             GotExtension = TRUE;
2441             break;
2442         }
2443         else if (c == L'\\')
2444         {
2445             break;
2446         }
2447     }
2448 
2449     /* If no extension was found, add the default extension */
2450     if (!GotExtension)
2451     {
2452         /* Check that we have space to add one */
2453         if ((DllName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >=
2454             sizeof(NameBuffer))
2455         {
2456             /* No space to add the extension */
2457             DbgPrintEx(DPFLTR_LDR_ID,
2458                        DPFLTR_ERROR_LEVEL,
2459                        "LDR: %s - Dll name missing extension; with extension "
2460                        "added the name is too long\n"
2461                        "   DllName: (@ %p) \"%wZ\"\n"
2462                        "   DllName->Length: %u\n",
2463                        __FUNCTION__,
2464                        DllName,
2465                        DllName,
2466                        DllName->Length);
2467             return STATUS_NAME_TOO_LONG;
2468         }
2469 
2470         /* Add it. Needs to be null terminated, thus the length check above */
2471         (VOID)RtlAppendUnicodeStringToString(&RawDllName,
2472                                              &LdrApiDefaultExtension);
2473     }
2474 
2475     /* Check for init flag and acquire lock */
2476     if (!InInit) RtlEnterCriticalSection(&LdrpLoaderLock);
2477 
2478     _SEH2_TRY
2479     {
2480         /* Show debug message */
2481         if (ShowSnaps)
2482         {
2483             DPRINT1("LDR: LdrLoadDll, loading %wZ from %ws\n",
2484                      &RawDllName,
2485                      DllPath ? DllPath : L"");
2486         }
2487 
2488         /* Check if the DLL is already loaded */
2489         if (!LdrpCheckForLoadedDll(DllPath,
2490                                    &RawDllName,
2491                                    FALSE,
2492                                    Redirected,
2493                                    &LdrEntry))
2494         {
2495             /* Map it */
2496             Status = LdrpMapDll(DllPath,
2497                                 DllPath,
2498                                 NameBuffer,
2499                                 DllCharacteristics,
2500                                 FALSE,
2501                                 Redirected,
2502                                 &LdrEntry);
2503             if (!NT_SUCCESS(Status))
2504                 _SEH2_LEAVE;
2505 
2506             /* FIXME: Need to mark the DLL range for the stack DB */
2507             //RtlpStkMarkDllRange(LdrEntry);
2508 
2509             /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2510             if ((DllCharacteristics) &&
2511                 (*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
2512             {
2513                 /* This is not a DLL, so remove such data */
2514                 LdrEntry->EntryPoint = NULL;
2515                 LdrEntry->Flags &= ~LDRP_IMAGE_DLL;
2516             }
2517 
2518             /* Make sure it's a DLL */
2519             if (LdrEntry->Flags & LDRP_IMAGE_DLL)
2520             {
2521                 /* Check if this is a .NET Image */
2522                 if (!(LdrEntry->Flags & LDRP_COR_IMAGE))
2523                 {
2524                     /* Walk the Import Descriptor */
2525                     Status = LdrpWalkImportDescriptor(DllPath, LdrEntry);
2526                 }
2527 
2528                 /* Update load count, unless it's locked */
2529                 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++;
2530                 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
2531 
2532                 /* Check if we failed */
2533                 if (!NT_SUCCESS(Status))
2534                 {
2535                     /* Clear entrypoint, and insert into list */
2536                     LdrEntry->EntryPoint = NULL;
2537                     InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
2538                                    &LdrEntry->InInitializationOrderLinks);
2539 
2540                     /* Cancel the load */
2541                     LdrpClearLoadInProgress();
2542 
2543                     /* Unload the DLL */
2544                     if (ShowSnaps)
2545                     {
2546                         DbgPrint("LDR: Unloading %wZ due to error %x walking "
2547                                  "import descriptors\n",
2548                                  DllName,
2549                                  Status);
2550                     }
2551                     LdrUnloadDll(LdrEntry->DllBase);
2552 
2553                     /* Return the error */
2554                     _SEH2_LEAVE;
2555                 }
2556             }
2557             else if (LdrEntry->LoadCount != 0xFFFF)
2558             {
2559                 /* Increase load count */
2560                 LdrEntry->LoadCount++;
2561             }
2562 
2563             /* Insert it into the list */
2564             InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
2565                            &LdrEntry->InInitializationOrderLinks);
2566 
2567             /* If we have to run the entrypoint, make sure the DB is ready */
2568             if (CallInit && LdrpLdrDatabaseIsSetup)
2569             {
2570                 /* Notify Shim Engine */
2571                 if (g_ShimsEnabled)
2572                 {
2573                     VOID (NTAPI* SE_DllLoaded)(PLDR_DATA_TABLE_ENTRY) = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
2574                     SE_DllLoaded(LdrEntry);
2575                 }
2576 
2577                 /* Run the init routine */
2578                 Status = LdrpRunInitializeRoutines(NULL);
2579                 if (!NT_SUCCESS(Status))
2580                 {
2581                     /* Failed, unload the DLL */
2582                     if (ShowSnaps)
2583                     {
2584                         DbgPrint("LDR: Unloading %wZ because either its init "
2585                                  "routine or one of its static imports failed; "
2586                                  "status = 0x%08lx\n",
2587                                  DllName,
2588                                  Status);
2589                     }
2590                     LdrUnloadDll(LdrEntry->DllBase);
2591                 }
2592             }
2593             else
2594             {
2595                 /* The DB isn't ready, which means we were loaded because of a forwarder */
2596                 Status = STATUS_SUCCESS;
2597             }
2598         }
2599         else
2600         {
2601             /* We were already loaded. Are we a DLL? */
2602             if ((LdrEntry->Flags & LDRP_IMAGE_DLL) && (LdrEntry->LoadCount != 0xFFFF))
2603             {
2604                 /* Increase load count */
2605                 LdrEntry->LoadCount++;
2606                 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
2607 
2608                 /* Clear the load in progress */
2609                 LdrpClearLoadInProgress();
2610             }
2611             else
2612             {
2613                 /* Not a DLL, just increase the load count */
2614                 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++;
2615             }
2616         }
2617 
2618     }
2619     _SEH2_FINALLY
2620     {
2621         /* Release the lock */
2622         if (!InInit) RtlLeaveCriticalSection(&LdrpLoaderLock);
2623     }
2624     _SEH2_END;
2625 
2626     /* Check for success */
2627     if (NT_SUCCESS(Status))
2628     {
2629         /* Return the base address */
2630         *BaseAddress = LdrEntry->DllBase;
2631     }
2632     else
2633     {
2634         /* Nothing found */
2635         *BaseAddress = NULL;
2636     }
2637 
2638     /* Return status */
2639     return Status;
2640 }
2641 
2642 ULONG
2643 NTAPI
2644 LdrpClearLoadInProgress(VOID)
2645 {
2646     PLIST_ENTRY ListHead, Entry;
2647     PLDR_DATA_TABLE_ENTRY LdrEntry;
2648     ULONG ModulesCount = 0;
2649 
2650     /* Traverse the init list */
2651     ListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2652     Entry = ListHead->Flink;
2653     while (Entry != ListHead)
2654     {
2655         /* Get the loader entry */
2656         LdrEntry = CONTAINING_RECORD(Entry,
2657                                      LDR_DATA_TABLE_ENTRY,
2658                                      InInitializationOrderLinks);
2659 
2660         /* Clear load in progress flag */
2661         LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2662 
2663         /* Check for modules with entry point count but not processed yet */
2664         if ((LdrEntry->EntryPoint) &&
2665             !(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
2666         {
2667             /* Increase counter */
2668             ModulesCount++;
2669         }
2670 
2671         /* Advance to the next entry */
2672         Entry = Entry->Flink;
2673     }
2674 
2675     /* Return final count */
2676     return ModulesCount;
2677 }
2678 
2679 PVOID LdrpGetShimEngineFunction(PCSZ FunctionName)
2680 {
2681     ANSI_STRING Function;
2682     NTSTATUS Status;
2683     PVOID Address;
2684     RtlInitAnsiString(&Function, FunctionName);
2685     /* Skip Dll init */
2686     Status = LdrpGetProcedureAddress(g_pShimEngineModule, &Function, 0, &Address, FALSE);
2687     return NT_SUCCESS(Status) ? Address : NULL;
2688 }
2689 
2690 VOID
2691 NTAPI
2692 LdrpGetShimEngineInterface()
2693 {
2694     PVOID SE_DllLoaded = LdrpGetShimEngineFunction("SE_DllLoaded");
2695     PVOID SE_DllUnloaded = LdrpGetShimEngineFunction("SE_DllUnloaded");
2696     PVOID SE_InstallBeforeInit = LdrpGetShimEngineFunction("SE_InstallBeforeInit");
2697     PVOID SE_InstallAfterInit = LdrpGetShimEngineFunction("SE_InstallAfterInit");
2698     PVOID SE_ProcessDying = LdrpGetShimEngineFunction("SE_ProcessDying");
2699 
2700     if (SE_DllLoaded && SE_DllUnloaded && SE_InstallBeforeInit && SE_InstallAfterInit && SE_ProcessDying)
2701     {
2702         g_pfnSE_DllLoaded = RtlEncodeSystemPointer(SE_DllLoaded);
2703         g_pfnSE_DllUnloaded = RtlEncodeSystemPointer(SE_DllUnloaded);
2704         g_pfnSE_InstallBeforeInit = RtlEncodeSystemPointer(SE_InstallBeforeInit);
2705         g_pfnSE_InstallAfterInit = RtlEncodeSystemPointer(SE_InstallAfterInit);
2706         g_pfnSE_ProcessDying = RtlEncodeSystemPointer(SE_ProcessDying);
2707         g_ShimsEnabled = TRUE;
2708     }
2709     else
2710     {
2711         LdrpUnloadShimEngine();
2712     }
2713 }
2714 
2715 VOID
2716 NTAPI
2717 LdrpRunShimEngineInitRoutine(IN ULONG Reason)
2718 {
2719     PLIST_ENTRY ListHead, Next;
2720     PLDR_DATA_TABLE_ENTRY LdrEntry;
2721 
2722     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2723     Next = ListHead->Flink;
2724     while (Next != ListHead)
2725     {
2726         LdrEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2727 
2728         if (g_pShimEngineModule == LdrEntry->DllBase)
2729         {
2730             if (LdrEntry->EntryPoint)
2731             {
2732                 _SEH2_TRY
2733                 {
2734                     LdrpCallInitRoutine(LdrEntry->EntryPoint, LdrEntry->DllBase, Reason, NULL);
2735                 }
2736                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2737                 {
2738                     DPRINT1("WARNING: Exception 0x%x during LdrpRunShimEngineInitRoutine(%u)\n",
2739                             _SEH2_GetExceptionCode(), Reason);
2740                 }
2741                 _SEH2_END;
2742             }
2743             return;
2744         }
2745 
2746         Next = Next->Flink;
2747     }
2748 }
2749 
2750 VOID
2751 NTAPI
2752 LdrpLoadShimEngine(IN PWSTR ImageName, IN PUNICODE_STRING ProcessImage, IN PVOID pShimData)
2753 {
2754     UNICODE_STRING ShimLibraryName;
2755     PVOID ShimLibrary;
2756     NTSTATUS Status;
2757     RtlInitUnicodeString(&ShimLibraryName, ImageName);
2758     /* We should NOT pass CallInit = TRUE!
2759        If we do this, other init routines will be called before we get a chance to shim stuff.. */
2760     Status = LdrpLoadDll(FALSE, NULL, NULL, &ShimLibraryName, &ShimLibrary, FALSE);
2761     if (NT_SUCCESS(Status))
2762     {
2763         g_pShimEngineModule = ShimLibrary;
2764         LdrpRunShimEngineInitRoutine(DLL_PROCESS_ATTACH);
2765         LdrpGetShimEngineInterface();
2766         if (g_ShimsEnabled)
2767         {
2768             VOID(NTAPI *SE_InstallBeforeInit)(PUNICODE_STRING, PVOID);
2769             SE_InstallBeforeInit = RtlDecodeSystemPointer(g_pfnSE_InstallBeforeInit);
2770             SE_InstallBeforeInit(ProcessImage, pShimData);
2771         }
2772     }
2773 }
2774 
2775 VOID
2776 NTAPI
2777 LdrpUnloadShimEngine()
2778 {
2779     /* Make sure we do not call into the shim engine anymore */
2780     g_ShimsEnabled = FALSE;
2781     LdrpRunShimEngineInitRoutine(DLL_PROCESS_DETACH);
2782     LdrUnloadDll(g_pShimEngineModule);
2783     g_pShimEngineModule = NULL;
2784 }
2785 
2786 /* EOF */
2787