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