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