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