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