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