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