[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / dll / ntdll / ldr / ldrpe.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/ntdll/ldr/ldrpe.c
5 * PURPOSE: Loader Functions dealing low-level PE Format structures
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntdll.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine;
19 ULONG LdrpNormalSnap;
20
21 /* FUNCTIONS *****************************************************************/
22
23
24 NTSTATUS
25 NTAPI
26 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry,
27 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry,
28 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry,
29 IN BOOLEAN EntriesValid)
30 {
31 PVOID Iat;
32 NTSTATUS Status;
33 PIMAGE_THUNK_DATA OriginalThunk, FirstThunk;
34 PIMAGE_NT_HEADERS NtHeader;
35 PIMAGE_SECTION_HEADER SectionHeader;
36 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
37 LPSTR ImportName;
38 ULONG ForwarderChain, i, Rva, OldProtect, IatSize, ExportSize;
39 SIZE_T ImportSize;
40 DPRINT("LdrpSnapIAT(%wZ %wZ %p %u)\n", &ExportLdrEntry->BaseDllName, &ImportLdrEntry->BaseDllName, IatEntry, EntriesValid);
41
42 /* Get export directory */
43 ExportDirectory = RtlImageDirectoryEntryToData(ExportLdrEntry->DllBase,
44 TRUE,
45 IMAGE_DIRECTORY_ENTRY_EXPORT,
46 &ExportSize);
47
48 /* Make sure it has one */
49 if (!ExportDirectory)
50 {
51 /* Fail */
52 DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n",
53 &ExportLdrEntry->BaseDllName);
54 return STATUS_INVALID_IMAGE_FORMAT;
55 }
56
57 /* Get the IAT */
58 Iat = RtlImageDirectoryEntryToData(ImportLdrEntry->DllBase,
59 TRUE,
60 IMAGE_DIRECTORY_ENTRY_IAT,
61 &IatSize);
62 ImportSize = IatSize;
63
64 /* Check if we don't have one */
65 if (!Iat)
66 {
67 /* Get the NT Header and the first section */
68 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
69 if (!NtHeader) return STATUS_INVALID_IMAGE_FORMAT;
70 SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
71
72 /* Get the RVA of the import directory */
73 Rva = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
74
75 /* Make sure we got one */
76 if (Rva)
77 {
78 /* Loop all the sections */
79 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
80 {
81 /* Check if we are inside this section */
82 if ((Rva >= SectionHeader->VirtualAddress) &&
83 (Rva < (SectionHeader->VirtualAddress +
84 SectionHeader->SizeOfRawData)))
85 {
86 /* We are, so set the IAT here */
87 Iat = (PVOID)((ULONG_PTR)(ImportLdrEntry->DllBase) +
88 SectionHeader->VirtualAddress);
89
90 /* Set the size */
91 IatSize = SectionHeader->Misc.VirtualSize;
92
93 /* Deal with Watcom and other retarded compilers */
94 if (!IatSize) IatSize = SectionHeader->SizeOfRawData;
95
96 /* Found it, get out */
97 break;
98 }
99
100 /* No match, move to the next section */
101 SectionHeader++;
102 }
103 }
104
105 /* If we still don't have an IAT, that's bad */
106 if (!Iat)
107 {
108 /* Fail */
109 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
110 &ImportLdrEntry->BaseDllName,
111 ImportLdrEntry->DllBase);
112 return STATUS_INVALID_IMAGE_FORMAT;
113 }
114
115 /* Set the right size */
116 ImportSize = IatSize;
117 }
118
119 /* Unprotect the IAT */
120 Status = NtProtectVirtualMemory(NtCurrentProcess(),
121 &Iat,
122 &ImportSize,
123 PAGE_READWRITE,
124 &OldProtect);
125 if (!NT_SUCCESS(Status))
126 {
127 /* Fail */
128 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
129 &ImportLdrEntry->BaseDllName,
130 Status);
131 return Status;
132 }
133
134 /* Check if the Thunks are already valid */
135 if (EntriesValid)
136 {
137 /* We'll only do forwarders. Get the import name */
138 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + IatEntry->Name);
139
140 /* Get the list of forwarders */
141 ForwarderChain = IatEntry->ForwarderChain;
142
143 /* Loop them */
144 while (ForwarderChain != -1)
145 {
146 /* Get the cached thunk VA*/
147 OriginalThunk = (PIMAGE_THUNK_DATA)
148 ((ULONG_PTR)ImportLdrEntry->DllBase +
149 IatEntry->OriginalFirstThunk +
150 (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
151
152 /* Get the first thunk */
153 FirstThunk = (PIMAGE_THUNK_DATA)
154 ((ULONG_PTR)ImportLdrEntry->DllBase +
155 IatEntry->FirstThunk +
156 (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
157
158 /* Get the Forwarder from the thunk */
159 ForwarderChain = (ULONG)FirstThunk->u1.Ordinal;
160
161 /* Snap the thunk */
162 _SEH2_TRY
163 {
164 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
165 ImportLdrEntry->DllBase,
166 OriginalThunk,
167 FirstThunk,
168 ExportDirectory,
169 ExportSize,
170 TRUE,
171 ImportName);
172
173 /* Move to the next thunk */
174 FirstThunk++;
175 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
176 {
177 /* Fail with the SEH error */
178 Status = _SEH2_GetExceptionCode();
179 } _SEH2_END;
180
181 /* If we messed up, exit */
182 if (!NT_SUCCESS(Status)) break;
183 }
184 }
185 else if (IatEntry->FirstThunk)
186 {
187 /* Full snapping. Get the First thunk */
188 FirstThunk = (PIMAGE_THUNK_DATA)
189 ((ULONG_PTR)ImportLdrEntry->DllBase +
190 IatEntry->FirstThunk);
191
192 /* Get the NT Header */
193 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
194
195 /* Get the Original thunk VA, watch out for weird images */
196 if ((IatEntry->Characteristics < NtHeader->OptionalHeader.SizeOfHeaders) ||
197 (IatEntry->Characteristics >= NtHeader->OptionalHeader.SizeOfImage))
198 {
199 /* Refuse it, this is a strange linked file */
200 OriginalThunk = FirstThunk;
201 }
202 else
203 {
204 /* Get the address from the field and convert to VA */
205 OriginalThunk = (PIMAGE_THUNK_DATA)
206 ((ULONG_PTR)ImportLdrEntry->DllBase +
207 IatEntry->OriginalFirstThunk);
208 }
209
210 /* Get the Import name VA */
211 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase +
212 IatEntry->Name);
213
214 /* Loop while it's valid */
215 while (OriginalThunk->u1.AddressOfData)
216 {
217 /* Snap the Thunk */
218 _SEH2_TRY
219 {
220 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
221 ImportLdrEntry->DllBase,
222 OriginalThunk,
223 FirstThunk,
224 ExportDirectory,
225 ExportSize,
226 TRUE,
227 ImportName);
228
229 /* Next thunks */
230 OriginalThunk++;
231 FirstThunk++;
232 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
233 {
234 /* Fail with the SEH error */
235 Status = _SEH2_GetExceptionCode();
236 } _SEH2_END;
237
238 /* If we failed the snap, break out */
239 if (!NT_SUCCESS(Status)) break;
240 }
241 }
242
243 /* Protect the IAT again */
244 NtProtectVirtualMemory(NtCurrentProcess(),
245 &Iat,
246 &ImportSize,
247 OldProtect,
248 &OldProtect);
249
250 /* Also flush out the cache */
251 NtFlushInstructionCache(NtCurrentProcess(), Iat, IatSize);
252
253 /* Return to Caller */
254 return Status;
255 }
256
257 NTSTATUS
258 NTAPI
259 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
260 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
261 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR *BoundEntryPtr,
262 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry)
263 {
264 LPSTR ImportName = NULL, BoundImportName, ForwarderName;
265 NTSTATUS Status;
266 BOOLEAN AlreadyLoaded = FALSE, Stale;
267 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
268 PLDR_DATA_TABLE_ENTRY DllLdrEntry, ForwarderLdrEntry;
269 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry;
270 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry;
271 PPEB Peb = NtCurrentPeb();
272 ULONG i, IatSize;
273
274 /* Get the pointer to the bound entry */
275 BoundEntry = *BoundEntryPtr;
276
277 /* Get the name's VA */
278 BoundImportName = (LPSTR)FirstEntry + BoundEntry->OffsetModuleName;
279
280 /* Show debug message */
281 if (ShowSnaps)
282 {
283 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry->BaseDllName, BoundImportName);
284 }
285
286 /* Load the module for this entry */
287 Status = LdrpLoadImportModule(DllPath,
288 BoundImportName,
289 &DllLdrEntry,
290 &AlreadyLoaded);
291 if (!NT_SUCCESS(Status))
292 {
293 /* Show debug message */
294 if (ShowSnaps)
295 {
296 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
297 &LdrEntry->BaseDllName,
298 BoundImportName,
299 Status);
300 }
301 goto Quickie;
302 }
303
304 /* Check if it wasn't already loaded */
305 if (!AlreadyLoaded)
306 {
307 /* Add it to our list */
308 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
309 &DllLdrEntry->InInitializationOrderLinks);
310 }
311
312 /* Check if the Bound Entry is now invalid */
313 if ((BoundEntry->TimeDateStamp != DllLdrEntry->TimeDateStamp) ||
314 (DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
315 {
316 /* Show debug message */
317 if (ShowSnaps)
318 {
319 DPRINT1("LDR: %wZ has stale binding to %s\n",
320 &LdrEntry->BaseDllName,
321 BoundImportName);
322 }
323
324 /* Remember it's become stale */
325 Stale = TRUE;
326 }
327 else
328 {
329 /* Show debug message */
330 if (ShowSnaps)
331 {
332 DPRINT1("LDR: %wZ has correct binding to %s\n",
333 &LdrEntry->BaseDllName,
334 BoundImportName);
335 }
336
337 /* Remember it's valid */
338 Stale = FALSE;
339 }
340
341 /* Get the forwarders */
342 ForwarderEntry = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1);
343
344 /* Loop them */
345 for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++)
346 {
347 /* Get the name */
348 ForwarderName = (LPSTR)FirstEntry + ForwarderEntry->OffsetModuleName;
349
350 /* Show debug message */
351 if (ShowSnaps)
352 {
353 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
354 &LdrEntry->BaseDllName,
355 ForwarderName,
356 &DllLdrEntry->BaseDllName);
357 }
358
359 /* Load the module */
360 Status = LdrpLoadImportModule(DllPath,
361 ForwarderName,
362 &ForwarderLdrEntry,
363 &AlreadyLoaded);
364 if (NT_SUCCESS(Status))
365 {
366 /* Loaded it, was it already loaded? */
367 if (!AlreadyLoaded)
368 {
369 /* Add it to our list */
370 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
371 &ForwarderLdrEntry->InInitializationOrderLinks);
372 }
373 }
374
375 /* Check if the Bound Entry is now invalid */
376 if (!(NT_SUCCESS(Status)) ||
377 (ForwarderEntry->TimeDateStamp != ForwarderLdrEntry->TimeDateStamp) ||
378 (ForwarderLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
379 {
380 /* Show debug message */
381 if (ShowSnaps)
382 {
383 DPRINT1("LDR: %wZ has stale binding to %s\n",
384 &LdrEntry->BaseDllName,
385 ForwarderName);
386 }
387
388 /* Remember it's become stale */
389 Stale = TRUE;
390 }
391 else
392 {
393 /* Show debug message */
394 if (ShowSnaps)
395 {
396 DPRINT1("LDR: %wZ has correct binding to %s\n",
397 &LdrEntry->BaseDllName,
398 ForwarderName);
399 }
400
401 /* Remember it's valid */
402 Stale = FALSE;
403 }
404
405 /* Move to the next one */
406 ForwarderEntry++;
407 }
408
409 /* Set the next bound entry to the forwarder */
410 FirstEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ForwarderEntry;
411
412 /* Check if the binding was stale */
413 if (Stale)
414 {
415 /* It was, so find the IAT entry for it */
416 ++LdrpNormalSnap;
417 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
418 TRUE,
419 IMAGE_DIRECTORY_ENTRY_IMPORT,
420 &IatSize);
421
422 /* Make sure it has a name */
423 while (ImportEntry->Name)
424 {
425 /* Get the name */
426 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
427
428 /* Compare it */
429 if (!_stricmp(ImportName, BoundImportName)) break;
430
431 /* Move to next entry */
432 ImportEntry++;
433 }
434
435 /* If we didn't find a name, fail */
436 if (!ImportEntry->Name)
437 {
438 /* Show debug message */
439 if (ShowSnaps)
440 {
441 DPRINT1("LDR: LdrpWalkImportTable - failing with"
442 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
443 }
444
445 /* Return error */
446 Status = STATUS_OBJECT_NAME_INVALID;
447 goto Quickie;
448 }
449
450 /* Show debug message */
451 if (ShowSnaps)
452 {
453 DPRINT1("LDR: Stale Bind %s from %wZ\n",
454 ImportName,
455 &LdrEntry->BaseDllName);
456 }
457
458 /* Snap the IAT Entry*/
459 Status = LdrpSnapIAT(DllLdrEntry,
460 LdrEntry,
461 ImportEntry,
462 FALSE);
463
464 /* Make sure we didn't fail */
465 if (!NT_SUCCESS(Status))
466 {
467 /* Show debug message */
468 if (ShowSnaps)
469 {
470 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
471 &LdrEntry->BaseDllName,
472 BoundImportName,
473 Status);
474 }
475
476 /* Return */
477 goto Quickie;
478 }
479 }
480
481 /* All done */
482 Status = STATUS_SUCCESS;
483
484 Quickie:
485 /* Write where we are now and return */
486 *BoundEntryPtr = FirstEntry;
487 return Status;
488 }
489
490 NTSTATUS
491 NTAPI
492 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
493 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
494 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry)
495 {
496 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry = BoundEntry;
497 NTSTATUS Status;
498
499 /* Make sure we have a name */
500 while (BoundEntry->OffsetModuleName)
501 {
502 /* Parse this descriptor */
503 Status = LdrpHandleOneNewFormatImportDescriptor(DllPath,
504 LdrEntry,
505 &BoundEntry,
506 FirstEntry);
507 if (!NT_SUCCESS(Status)) return Status;
508 }
509
510 /* Done */
511 return STATUS_SUCCESS;
512 }
513
514 NTSTATUS
515 NTAPI
516 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
517 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
518 IN PIMAGE_IMPORT_DESCRIPTOR *ImportEntry)
519 {
520 LPSTR ImportName;
521 NTSTATUS Status;
522 BOOLEAN AlreadyLoaded = FALSE;
523 PLDR_DATA_TABLE_ENTRY DllLdrEntry;
524 PIMAGE_THUNK_DATA FirstThunk;
525 PPEB Peb = NtCurrentPeb();
526
527 /* Get the import name's VA */
528 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + (*ImportEntry)->Name);
529
530 /* Get the first thunk */
531 FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase +
532 (*ImportEntry)->FirstThunk);
533
534 /* Make sure it's valid */
535 if (!FirstThunk->u1.Function) goto SkipEntry;
536
537 /* Show debug message */
538 if (ShowSnaps)
539 {
540 DPRINT1("LDR: %s used by %wZ\n",
541 ImportName,
542 &LdrEntry->BaseDllName);
543 }
544
545 /* Load the module associated to it */
546 Status = LdrpLoadImportModule(DllPath,
547 ImportName,
548 &DllLdrEntry,
549 &AlreadyLoaded);
550 if (!NT_SUCCESS(Status))
551 {
552 /* Fail */
553 if (ShowSnaps)
554 {
555 DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed "
556 "on import %s with status %x\n",
557 ImportName,
558 Status);
559 }
560
561 /* Return */
562 return Status;
563 }
564
565 /* Show debug message */
566 if (ShowSnaps)
567 {
568 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
569 &LdrEntry->BaseDllName,
570 ImportName);
571 }
572
573 /* Check if it wasn't already loaded */
574 ++LdrpNormalSnap;
575 if (!AlreadyLoaded)
576 {
577 /* Add the DLL to our list */
578 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
579 &DllLdrEntry->InInitializationOrderLinks);
580 }
581
582 /* Now snap the IAT Entry */
583 Status = LdrpSnapIAT(DllLdrEntry, LdrEntry, *ImportEntry, FALSE);
584 if (!NT_SUCCESS(Status))
585 {
586 /* Fail */
587 if (ShowSnaps)
588 {
589 DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with "
590 "status %x\n",
591 Status);
592 }
593
594 /* Return */
595 return Status;
596 }
597
598 SkipEntry:
599 /* Move on */
600 (*ImportEntry)++;
601 return STATUS_SUCCESS;
602 }
603
604 NTSTATUS
605 NTAPI
606 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
607 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
608 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry)
609 {
610 NTSTATUS Status;
611
612 /* Check for Name and Thunk */
613 while ((ImportEntry->Name) && (ImportEntry->FirstThunk))
614 {
615 /* Parse this descriptor */
616 Status = LdrpHandleOneOldFormatImportDescriptor(DllPath,
617 LdrEntry,
618 &ImportEntry);
619 if (!NT_SUCCESS(Status)) return Status;
620 }
621
622 /* Done */
623 return STATUS_SUCCESS;
624 }
625
626 USHORT
627 NTAPI
628 LdrpNameToOrdinal(IN LPSTR ImportName,
629 IN ULONG NumberOfNames,
630 IN PVOID ExportBase,
631 IN PULONG NameTable,
632 IN PUSHORT OrdinalTable)
633 {
634 LONG Start, End, Next, CmpResult;
635
636 /* Use classical binary search to find the ordinal */
637 Start = Next = 0;
638 End = NumberOfNames - 1;
639 while (End >= Start)
640 {
641 /* Next will be exactly between Start and End */
642 Next = (Start + End) >> 1;
643
644 /* Compare this name with the one we need to find */
645 CmpResult = strcmp(ImportName, (PCHAR)((ULONG_PTR)ExportBase + NameTable[Next]));
646
647 /* We found our entry if result is 0 */
648 if (!CmpResult) break;
649
650 /* We didn't find, update our range then */
651 if (CmpResult < 0)
652 {
653 End = Next - 1;
654 }
655 else if (CmpResult > 0)
656 {
657 Start = Next + 1;
658 }
659 }
660
661 /* If end is before start, then the search failed */
662 if (End < Start) return -1;
663
664 /* Return found name */
665 return OrdinalTable[Next];
666 }
667
668 NTSTATUS
669 NTAPI
670 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL,
671 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
672 {
673 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
674 PPEB Peb = NtCurrentPeb();
675 NTSTATUS Status = STATUS_SUCCESS, Status2;
676 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL;
677 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
678 ULONG BoundSize, IatSize;
679
680 DPRINT("LdrpWalkImportDescriptor - BEGIN (%wZ %p '%S')\n", &LdrEntry->BaseDllName, LdrEntry, DllPath);
681
682 /* Set up the Act Ctx */
683 RtlZeroMemory(&ActCtx, sizeof(ActCtx));
684 ActCtx.Size = sizeof(ActCtx);
685 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
686
687 /* Check if we have a manifest prober routine */
688 if (LdrpManifestProberRoutine)
689 {
690 /* Probe the DLL for its manifest. Some details are omitted */
691 Status2 = LdrpManifestProberRoutine(LdrEntry->DllBase, LdrEntry->FullDllName.Buffer, &LdrEntry->EntryPointActivationContext);
692
693 if (!NT_SUCCESS(Status2) &&
694 Status2 != STATUS_NO_SUCH_FILE &&
695 Status2 != STATUS_RESOURCE_DATA_NOT_FOUND &&
696 Status2 != STATUS_RESOURCE_TYPE_NOT_FOUND &&
697 Status2 != STATUS_RESOURCE_NAME_NOT_FOUND &&
698 Status2 != STATUS_RESOURCE_LANG_NOT_FOUND)
699 {
700 /* Some serious issue */
701 //Status = Status2; // FIXME: Ignore that error for now
702 DbgPrintEx(DPFLTR_SXS_ID,
703 DPFLTR_WARNING_LEVEL,
704 "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its "
705 "manifest, ntstatus = 0x%08lx\n",
706 &LdrEntry->FullDllName, Status2);
707 }
708 }
709
710 /* Check if we failed above */
711 if (!NT_SUCCESS(Status)) return Status;
712
713 /* Get the Active ActCtx */
714 if (!LdrEntry->EntryPointActivationContext)
715 {
716 Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext);
717
718 if (!NT_SUCCESS(Status))
719 {
720 /* Exit */
721 DbgPrintEx(DPFLTR_SXS_ID,
722 DPFLTR_WARNING_LEVEL,
723 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
724 "0x%08lx\n",
725 Status);
726 return Status;
727 }
728 }
729
730 /* Activate the ActCtx */
731 RtlActivateActivationContextUnsafeFast(&ActCtx,
732 LdrEntry->EntryPointActivationContext);
733
734 /* Check if we were redirected */
735 if (!(LdrEntry->Flags & LDRP_REDIRECTED))
736 {
737 /* Get the Bound IAT */
738 BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
739 TRUE,
740 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
741 &BoundSize);
742 }
743
744 /* Get the regular IAT, for fallback */
745 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
746 TRUE,
747 IMAGE_DIRECTORY_ENTRY_IMPORT,
748 &IatSize);
749
750 /* Check if we got at least one */
751 if ((BoundEntry) || (ImportEntry))
752 {
753 /* Do we have a Bound IAT */
754 if (BoundEntry)
755 {
756 /* Handle the descriptor */
757 Status = LdrpHandleNewFormatImportDescriptors(DllPath,
758 LdrEntry,
759 BoundEntry);
760 }
761 else
762 {
763 /* Handle the descriptor */
764 Status = LdrpHandleOldFormatImportDescriptors(DllPath,
765 LdrEntry,
766 ImportEntry);
767 }
768
769 /* Check the status of the handlers */
770 if (NT_SUCCESS(Status))
771 {
772 /* Check for Per-DLL Heap Tagging */
773 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL)
774 {
775 /* FIXME */
776 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
777 }
778
779 /* Check if Page Heap was enabled */
780 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
781 {
782 /* Initialize target DLL */
783 AVrfPageHeapDllNotification(LdrEntry);
784 }
785
786 /* Check if Application Verifier was enabled */
787 if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
788 {
789 AVrfDllLoadNotification(LdrEntry);
790 }
791
792 /* Just to be safe */
793 Status = STATUS_SUCCESS;
794 }
795 }
796
797 /* Release the activation context */
798 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
799
800 DPRINT("LdrpWalkImportDescriptor - END (%wZ %p)\n", &LdrEntry->BaseDllName, LdrEntry);
801
802 /* Return status */
803 return Status;
804 }
805
806 NTSTATUS
807 NTAPI
808 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
809 IN LPSTR ImportName,
810 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
811 OUT PBOOLEAN Existing)
812 {
813 ANSI_STRING AnsiString;
814 PUNICODE_STRING ImpDescName;
815 const WCHAR *p;
816 BOOLEAN GotExtension;
817 WCHAR c;
818 NTSTATUS Status;
819 PPEB Peb = RtlGetCurrentPeb();
820 PTEB Teb = NtCurrentTeb();
821 UNICODE_STRING RedirectedImpDescName;
822 BOOLEAN RedirectedDll;
823
824 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p)\n", DllPath, ImportName, DataTableEntry, Existing);
825
826 RedirectedDll = FALSE;
827 RtlInitEmptyUnicodeString(&RedirectedImpDescName, NULL, 0);
828
829 /* Convert import descriptor name to unicode string */
830 ImpDescName = &Teb->StaticUnicodeString;
831 RtlInitAnsiString(&AnsiString, ImportName);
832 Status = RtlAnsiStringToUnicodeString(ImpDescName, &AnsiString, FALSE);
833 if (!NT_SUCCESS(Status)) return Status;
834
835 /* Find the extension, if present */
836 p = ImpDescName->Buffer + ImpDescName->Length / sizeof(WCHAR) - 1;
837 GotExtension = FALSE;
838 while (p >= ImpDescName->Buffer)
839 {
840 c = *p--;
841 if (c == L'.')
842 {
843 GotExtension = TRUE;
844 break;
845 }
846 else if (c == L'\\')
847 {
848 break;
849 }
850 }
851
852 /* If no extension was found, add the default extension */
853 if (!GotExtension)
854 {
855 /* Check that we have space to add one */
856 if ((ImpDescName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >=
857 sizeof(Teb->StaticUnicodeBuffer))
858 {
859 /* No space to add the extension */
860 DbgPrintEx(DPFLTR_LDR_ID,
861 DPFLTR_ERROR_LEVEL,
862 "LDR: %s - Dll name missing extension; with extension "
863 "added the name is too long\n"
864 " ImpDescName: (@ %p) \"%wZ\"\n"
865 " ImpDescName->Length: %u\n",
866 __FUNCTION__,
867 ImpDescName,
868 ImpDescName,
869 ImpDescName->Length);
870 return STATUS_NAME_TOO_LONG;
871 }
872
873 /* Add it. Needs to be null terminated, thus the length check above */
874 (VOID)RtlAppendUnicodeStringToString(ImpDescName,
875 &LdrApiDefaultExtension);
876 }
877
878 /* Check if the SxS Assemblies specify another file */
879 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
880 ImpDescName,
881 &LdrApiDefaultExtension,
882 NULL,
883 &RedirectedImpDescName,
884 &ImpDescName,
885 NULL,
886 NULL,
887 NULL);
888
889 /* Check success */
890 if (NT_SUCCESS(Status))
891 {
892 /* Let Ldrp know */
893 RedirectedDll = TRUE;
894 }
895 else if (Status != STATUS_SXS_KEY_NOT_FOUND)
896 {
897 /* Unrecoverable SxS failure */
898 DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed with status %x for dll %wZ\n", Status, ImpDescName);
899 goto done;
900 }
901
902 /* Check if it's loaded */
903 if (LdrpCheckForLoadedDll(DllPath,
904 ImpDescName,
905 TRUE,
906 RedirectedDll,
907 DataTableEntry))
908 {
909 /* It's already existing in the list */
910 *Existing = TRUE;
911 Status = STATUS_SUCCESS;
912 goto done;
913 }
914
915 /* We're loading it for the first time */
916 *Existing = FALSE;
917
918 /* Map it */
919 Status = LdrpMapDll(DllPath,
920 NULL,
921 ImpDescName->Buffer,
922 NULL,
923 TRUE,
924 RedirectedDll,
925 DataTableEntry);
926 if (!NT_SUCCESS(Status))
927 {
928 DPRINT1("LDR: LdrpMapDll failed with status %x for dll %wZ\n", Status, ImpDescName);
929 goto done;
930 }
931
932 /* Walk its import descriptor table */
933 Status = LdrpWalkImportDescriptor(DllPath,
934 *DataTableEntry);
935 if (!NT_SUCCESS(Status))
936 {
937 /* Add it to the in-init-order list in case of failure */
938 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
939 &(*DataTableEntry)->InInitializationOrderLinks);
940 }
941
942 done:
943 RtlFreeUnicodeString(&RedirectedImpDescName);
944
945 return Status;
946 }
947
948 NTSTATUS
949 NTAPI
950 LdrpSnapThunk(IN PVOID ExportBase,
951 IN PVOID ImportBase,
952 IN PIMAGE_THUNK_DATA OriginalThunk,
953 IN OUT PIMAGE_THUNK_DATA Thunk,
954 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
955 IN ULONG ExportSize,
956 IN BOOLEAN Static,
957 IN LPSTR DllName)
958 {
959 BOOLEAN IsOrdinal;
960 USHORT Ordinal;
961 ULONG OriginalOrdinal = 0;
962 PIMAGE_IMPORT_BY_NAME AddressOfData;
963 PULONG NameTable;
964 PUSHORT OrdinalTable;
965 LPSTR ImportName = NULL, DotPosition;
966 USHORT Hint;
967 NTSTATUS Status;
968 ULONG_PTR HardErrorParameters[3];
969 UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
970 ANSI_STRING TempString;
971 ULONG Mask;
972 ULONG Response;
973 PULONG AddressOfFunctions;
974 UNICODE_STRING TempUString;
975 ANSI_STRING ForwarderName;
976 PANSI_STRING ForwardName;
977 PVOID ForwarderHandle;
978 ULONG ForwardOrdinal;
979
980 /* Check if the snap is by ordinal */
981 if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))
982 {
983 /* Get the ordinal number, and its normalized version */
984 OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
985 Ordinal = (USHORT)(OriginalOrdinal - ExportDirectory->Base);
986 }
987 else
988 {
989 /* First get the data VA */
990 AddressOfData = (PIMAGE_IMPORT_BY_NAME)
991 ((ULONG_PTR)ImportBase +
992 ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
993
994 /* Get the name */
995 ImportName = (LPSTR)AddressOfData->Name;
996
997 /* Now get the VA of the Name and Ordinal Tables */
998 NameTable = (PULONG)((ULONG_PTR)ExportBase +
999 (ULONG_PTR)ExportDirectory->AddressOfNames);
1000 OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase +
1001 (ULONG_PTR)ExportDirectory->AddressOfNameOrdinals);
1002
1003 /* Get the hint */
1004 Hint = AddressOfData->Hint;
1005
1006 /* Try to get a match by using the hint */
1007 if (((ULONG)Hint < ExportDirectory->NumberOfNames) &&
1008 (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint])))))
1009 {
1010 /* We got a match, get the Ordinal from the hint */
1011 Ordinal = OrdinalTable[Hint];
1012 }
1013 else
1014 {
1015 /* Well bummer, hint didn't work, do it the long way */
1016 Ordinal = LdrpNameToOrdinal(ImportName,
1017 ExportDirectory->NumberOfNames,
1018 ExportBase,
1019 NameTable,
1020 OrdinalTable);
1021 }
1022 }
1023
1024 /* Check if the ordinal is invalid */
1025 if ((ULONG)Ordinal >= ExportDirectory->NumberOfFunctions)
1026 {
1027 FailurePath:
1028 /* Is this a static snap? */
1029 if (Static)
1030 {
1031 UNICODE_STRING SnapTarget;
1032 PLDR_DATA_TABLE_ENTRY LdrEntry;
1033
1034 /* What was the module we were searching in */
1035 RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown");
1036
1037 /* What was the module we were searching for */
1038 if (LdrpCheckForLoadedDllHandle(ImportBase, &LdrEntry))
1039 SnapTarget = LdrEntry->BaseDllName;
1040 else
1041 RtlInitUnicodeString(&SnapTarget, L"Unknown");
1042
1043 /* Inform the debug log */
1044 if (IsOrdinal)
1045 DPRINT1("Failed to snap ordinal %Z!0x%x for %wZ\n", &TempString, OriginalOrdinal, &SnapTarget);
1046 else
1047 DPRINT1("Failed to snap %Z!%s for %wZ\n", &TempString, ImportName, &SnapTarget);
1048
1049 /* These are critical errors. Setup a string for the DLL name */
1050 RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE);
1051
1052 /* Set it as the parameter */
1053 HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName;
1054 Mask = 2;
1055
1056 /* Check if we have an ordinal */
1057 if (IsOrdinal)
1058 {
1059 /* Then set the ordinal as the 1st parameter */
1060 HardErrorParameters[0] = OriginalOrdinal;
1061 }
1062 else
1063 {
1064 /* We don't, use the entrypoint. Set up a string for it */
1065 RtlInitAnsiString(&TempString, ImportName);
1066 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName,
1067 &TempString,
1068 TRUE);
1069
1070 /* Set it as the parameter */
1071 HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName;
1072 Mask = 3;
1073 }
1074
1075 /* Raise the error */
1076 NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1077 STATUS_ENTRYPOINT_NOT_FOUND,
1078 2,
1079 Mask,
1080 HardErrorParameters,
1081 OptionOk,
1082 &Response);
1083
1084 /* Increase the error count */
1085 if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1086
1087 /* Free our string */
1088 RtlFreeUnicodeString(&HardErrorDllName);
1089 if (!IsOrdinal)
1090 {
1091 /* Free our second string. Return entrypoint error */
1092 RtlFreeUnicodeString(&HardErrorEntryPointName);
1093 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
1094 }
1095
1096 /* Return ordinal error */
1097 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
1098 }
1099 else
1100 {
1101 /* Inform the debug log */
1102 if (IsOrdinal)
1103 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal);
1104 else
1105 DPRINT("Non-fatal: Failed to snap %s\n", ImportName);
1106 }
1107
1108 /* Set this as a bad DLL */
1109 Thunk->u1.Function = (ULONG_PTR)0xffbadd11;
1110
1111 /* Return the right error code */
1112 Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1113 STATUS_ENTRYPOINT_NOT_FOUND;
1114 }
1115 else
1116 {
1117 /* The ordinal seems correct, get the AddressOfFunctions VA */
1118 AddressOfFunctions = (PULONG)
1119 ((ULONG_PTR)ExportBase +
1120 (ULONG_PTR)ExportDirectory->AddressOfFunctions);
1121
1122 /* Write the function pointer*/
1123 Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
1124
1125 /* Make sure it's within the exports */
1126 if ((Thunk->u1.Function > (ULONG_PTR)ExportDirectory) &&
1127 (Thunk->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
1128 {
1129 /* Get the Import and Forwarder Names */
1130 ImportName = (LPSTR)Thunk->u1.Function;
1131
1132 DotPosition = strchr(ImportName, '.');
1133 ASSERT(DotPosition != NULL);
1134 if (!DotPosition)
1135 goto FailurePath;
1136
1137 ForwarderName.Buffer = ImportName;
1138 ForwarderName.Length = (USHORT)(DotPosition - ImportName);
1139 ForwarderName.MaximumLength = ForwarderName.Length;
1140 Status = RtlAnsiStringToUnicodeString(&TempUString,
1141 &ForwarderName,
1142 TRUE);
1143
1144 /* Make sure the conversion was OK */
1145 if (NT_SUCCESS(Status))
1146 {
1147 WCHAR StringBuffer[MAX_PATH];
1148 UNICODE_STRING StaticString, *RedirectedImportName;
1149 BOOLEAN Redirected = FALSE;
1150
1151 RtlInitEmptyUnicodeString(&StaticString, StringBuffer, sizeof(StringBuffer));
1152
1153 /* Check if the SxS Assemblies specify another file */
1154 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
1155 &TempUString,
1156 &LdrApiDefaultExtension,
1157 &StaticString,
1158 NULL,
1159 &RedirectedImportName,
1160 NULL,
1161 NULL,
1162 NULL);
1163 if (NT_SUCCESS(Status))
1164 {
1165 if (ShowSnaps)
1166 {
1167 DPRINT1("LDR: %Z got redirected to %wZ\n", &ForwarderName, RedirectedImportName);
1168 }
1169 /* Let Ldrp know */
1170 Redirected = TRUE;
1171 }
1172 else
1173 {
1174 RedirectedImportName = &TempUString;
1175 }
1176
1177 /* Load the forwarder */
1178 Status = LdrpLoadDll(Redirected,
1179 NULL,
1180 NULL,
1181 RedirectedImportName,
1182 &ForwarderHandle,
1183 FALSE);
1184
1185 RtlFreeUnicodeString(&TempUString);
1186 }
1187
1188 /* If the load or conversion failed, use the failure path */
1189 if (!NT_SUCCESS(Status)) goto FailurePath;
1190
1191 /* Now set up a name for the actual forwarder dll */
1192 RtlInitAnsiString(&ForwarderName,
1193 ImportName + ForwarderName.Length + sizeof(CHAR));
1194
1195 /* Check if it's an ordinal forward */
1196 if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
1197 {
1198 /* We don't have an actual function name */
1199 ForwardName = NULL;
1200
1201 /* Convert the string into an ordinal */
1202 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),
1203 0,
1204 &ForwardOrdinal);
1205
1206 /* If this fails, then error out */
1207 if (!NT_SUCCESS(Status)) goto FailurePath;
1208 }
1209 else
1210 {
1211 /* Import by name */
1212 ForwardName = &ForwarderName;
1213 ForwardOrdinal = 0;
1214 }
1215
1216 /* Get the pointer */
1217 Status = LdrpGetProcedureAddress(ForwarderHandle,
1218 ForwardName,
1219 ForwardOrdinal,
1220 (PVOID*)&Thunk->u1.Function,
1221 FALSE);
1222 /* If this fails, then error out */
1223 if (!NT_SUCCESS(Status)) goto FailurePath;
1224 }
1225 else
1226 {
1227 /* It's not within the exports, let's hope it's valid */
1228 if (!AddressOfFunctions[Ordinal]) goto FailurePath;
1229 }
1230
1231 /* If we got here, then it's success */
1232 Status = STATUS_SUCCESS;
1233 }
1234
1235 /* Return status */
1236 return Status;
1237 }
1238
1239 /* EOF */