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