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