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