[CMAKE]
[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 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16 ULONG LdrpFatalHardErrorCount;
17 PVOID LdrpManifestProberRoutine;
18
19 /* PROTOTYPES ****************************************************************/
20
21 #define IMAGE_REL_BASED_HIGH3ADJ 11
22
23 NTSTATUS
24 NTAPI
25 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
26 IN LPSTR ImportName,
27 IN PVOID DllBase,
28 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
29 OUT PBOOLEAN Existing);
30
31 /* FUNCTIONS *****************************************************************/
32
33 NTSTATUS
34 NTAPI
35 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry,
36 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry,
37 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry,
38 IN BOOLEAN EntriesValid)
39 {
40 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
41 ULONG ExportSize;
42 PVOID Iat;
43 SIZE_T ImportSize;
44 ULONG IatSize;
45 //PPEB Peb = NtCurrentPeb();
46 NTSTATUS Status;
47 PIMAGE_THUNK_DATA OriginalThunk, FirstThunk;
48 LPSTR ImportName;
49 ULONG ForwarderChain;
50 PIMAGE_NT_HEADERS NtHeader;
51 PIMAGE_SECTION_HEADER SectionHeader;
52 ULONG i, Rva;
53 ULONG OldProtect;
54
55 DPRINT("LdrpSnapIAT(%wZ %wZ %p %d)\n", &ExportLdrEntry->BaseDllName, &ImportLdrEntry->BaseDllName, IatEntry, EntriesValid);
56
57 /* Get export directory */
58 ExportDirectory = RtlImageDirectoryEntryToData(ExportLdrEntry->DllBase,
59 TRUE,
60 IMAGE_DIRECTORY_ENTRY_EXPORT,
61 &ExportSize);
62
63 /* Make sure it has one */
64 if (!ExportDirectory) return STATUS_INVALID_IMAGE_FORMAT;
65
66 /* Get the IAT */
67 Iat = RtlImageDirectoryEntryToData(ImportLdrEntry->DllBase,
68 TRUE,
69 IMAGE_DIRECTORY_ENTRY_IAT,
70 &IatSize);
71 ImportSize = IatSize;
72
73 /* Check if we don't have one */
74 if (!Iat)
75 {
76 /* Get the NT Header and the first section */
77 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
78 SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
79
80 /* Get the RVA of the import directory */
81 Rva = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
82
83 /* Make sure we got one */
84 if (Rva)
85 {
86 /* Loop all the sections */
87 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
88 {
89 /* Check if we are inside this section */
90 if ((Rva >= SectionHeader->VirtualAddress) &&
91 (Rva < (SectionHeader->VirtualAddress +
92 SectionHeader->SizeOfRawData)))
93 {
94 /* We are, so set the IAT here */
95 Iat = (PVOID)((ULONG_PTR)(ImportLdrEntry->DllBase) +
96 SectionHeader->VirtualAddress);
97
98 /* Set the size */
99 IatSize = SectionHeader->Misc.VirtualSize;
100
101 /* Deal with Watcom and other retarded compilers */
102 if (!IatSize)
103 {
104 IatSize = SectionHeader->SizeOfRawData;
105 }
106
107 /* Found it, get out */
108 break;
109 }
110
111 /* No match, move to the next section */
112 SectionHeader++;
113 }
114 }
115
116 /* If we still don't have an IAT, that's bad */
117 if (!Iat) return STATUS_INVALID_IMAGE_FORMAT;
118
119 /* Set the right size */
120 ImportSize = IatSize;
121 }
122
123 /* Unprotect the IAT */
124 Status = NtProtectVirtualMemory(NtCurrentProcess(),
125 &Iat,
126 &ImportSize,
127 PAGE_READWRITE,
128 &OldProtect);
129 if (!NT_SUCCESS(Status)) return Status;
130
131 /* Check if the Thunks are already valid */
132 if (EntriesValid)
133 {
134 /* We'll only do forwarders. Get the import name */
135 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + IatEntry->Name);
136
137 /* Get the list of forwaders */
138 ForwarderChain = IatEntry->ForwarderChain;
139
140 /* Loop them */
141 while (ForwarderChain != -1)
142 {
143 /* Get the cached thunk VA*/
144 OriginalThunk = (PIMAGE_THUNK_DATA)
145 ((ULONG_PTR)ImportLdrEntry->DllBase +
146 IatEntry->OriginalFirstThunk +
147 (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
148
149 /* Get the first thunk */
150 FirstThunk = (PIMAGE_THUNK_DATA)
151 ((ULONG_PTR)ImportLdrEntry->DllBase +
152 IatEntry->FirstThunk +
153 (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
154
155 /* Get the Forwarder from the thunk */
156 ForwarderChain = (ULONG)FirstThunk->u1.Ordinal;
157
158 /* Snap the thunk */
159 _SEH2_TRY
160 {
161 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
162 ImportLdrEntry->DllBase,
163 OriginalThunk,
164 FirstThunk,
165 ExportDirectory,
166 ExportSize,
167 TRUE,
168 ImportName);
169
170 /* Move to the next thunk */
171 FirstThunk++;
172 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
173 {
174 /* Fail with the SEH error */
175 Status = _SEH2_GetExceptionCode();
176 } _SEH2_END;
177
178 /* If we messed up, exit */
179 if (!NT_SUCCESS(Status)) break;
180 }
181 }
182 else if (IatEntry->FirstThunk)
183 {
184 /* Full snapping. Get the First thunk */
185 FirstThunk = (PIMAGE_THUNK_DATA)
186 ((ULONG_PTR)ImportLdrEntry->DllBase +
187 IatEntry->FirstThunk);
188
189 /* Get the NT Header */
190 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
191
192 /* Get the Original thunk VA, watch out for weird images */
193 if ((IatEntry->Characteristics < NtHeader->OptionalHeader.SizeOfHeaders) ||
194 (IatEntry->Characteristics >= NtHeader->OptionalHeader.SizeOfImage))
195 {
196 /* Refuse it, this is a strange linked file */
197 OriginalThunk = FirstThunk;
198 }
199 else
200 {
201 /* Get the address from the field and convert to VA */
202 OriginalThunk = (PIMAGE_THUNK_DATA)
203 ((ULONG_PTR)ImportLdrEntry->DllBase +
204 IatEntry->OriginalFirstThunk);
205 }
206
207 /* Get the Import name VA */
208 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase +
209 IatEntry->Name);
210
211 /* Loop while it's valid */
212 while (OriginalThunk->u1.AddressOfData)
213 {
214 /* Snap the Thunk */
215 _SEH2_TRY
216 {
217 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
218 ImportLdrEntry->DllBase,
219 OriginalThunk,
220 FirstThunk,
221 ExportDirectory,
222 ExportSize,
223 TRUE,
224 ImportName);
225
226 /* Next thunks */
227 OriginalThunk++;
228 FirstThunk++;
229 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
230 {
231 /* Fail with the SEH error */
232 Status = _SEH2_GetExceptionCode();
233 } _SEH2_END;
234
235 /* If we failed the snap, break out */
236 if (!NT_SUCCESS(Status)) break;
237 }
238 }
239
240 /* Protect the IAT again */
241 NtProtectVirtualMemory(NtCurrentProcess(),
242 &Iat,
243 &ImportSize,
244 OldProtect,
245 &OldProtect);
246
247 /* Also flush out the cache */
248 NtFlushInstructionCache(NtCurrentProcess(), Iat, IatSize);
249
250 /* Return to Caller */
251 return Status;
252 }
253
254 NTSTATUS
255 NTAPI
256 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
257 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
258 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry,
259 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry)
260 {
261 LPSTR ImportName = NULL, BoundImportName, ForwarderName;
262 NTSTATUS Status;
263 BOOLEAN AlreadyLoaded = FALSE, Stale;
264 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
265 PLDR_DATA_TABLE_ENTRY DllLdrEntry, ForwarderLdrEntry;
266 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry;
267 PPEB Peb = NtCurrentPeb();
268 ULONG i, IatSize;
269
270 /* Get the name's VA */
271 BoundImportName = (LPSTR)(BoundEntry + BoundEntry->OffsetModuleName);
272
273 /* Show debug mesage */
274 if (ShowSnaps)
275 {
276 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry->BaseDllName, BoundImportName);
277 }
278
279 /* Load the module for this entry */
280 Status = LdrpLoadImportModule(DllPath,
281 BoundImportName,
282 LdrEntry->DllBase,
283 &DllLdrEntry,
284 &AlreadyLoaded);
285 if (!NT_SUCCESS(Status))
286 {
287 /* Show debug message */
288 if (ShowSnaps)
289 {
290 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
291 &LdrEntry->BaseDllName,
292 BoundImportName,
293 Status);
294 }
295 goto Quickie;
296 }
297
298 /* Check if it wasn't already loaded */
299 if (!AlreadyLoaded)
300 {
301 /* Add it to our list */
302 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
303 &DllLdrEntry->InInitializationOrderModuleList);
304 }
305
306 /* Check if the Bound Entry is now invalid */
307 if ((BoundEntry->TimeDateStamp != DllLdrEntry->TimeDateStamp) ||
308 (DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
309 {
310 /* Show debug message */
311 if (ShowSnaps)
312 {
313 DPRINT1("LDR: %wZ has stale binding to %s\n",
314 &DllLdrEntry->BaseDllName,
315 BoundImportName);
316 }
317
318 /* Remember it's become stale */
319 Stale = TRUE;
320 }
321 else
322 {
323 /* Show debug message */
324 if (ShowSnaps)
325 {
326 DPRINT1("LDR: %wZ has correct binding to %s\n",
327 &DllLdrEntry->BaseDllName,
328 BoundImportName);
329 }
330
331 /* Remember it's valid */
332 Stale = FALSE;
333 }
334
335 /* Get the forwarders */
336 ForwarderEntry = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1);
337
338 /* Loop them */
339 for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++)
340 {
341 /* Get the name */
342 ForwarderName = (LPSTR)(FirstEntry + ForwarderEntry->OffsetModuleName);
343
344 /* Show debug message */
345 if (ShowSnaps)
346 {
347 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
348 &LdrEntry->BaseDllName,
349 ForwarderName,
350 &DllLdrEntry->BaseDllName);
351 }
352
353 /* Load the module */
354 Status = LdrpLoadImportModule(DllPath,
355 ForwarderName,
356 LdrEntry->DllBase,
357 &ForwarderLdrEntry,
358 &AlreadyLoaded);
359 if (NT_SUCCESS(Status))
360 {
361 /* Loaded it, was it already loaded? */
362 if (!AlreadyLoaded)
363 {
364 /* Add it to our list */
365 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
366 &ForwarderLdrEntry->InInitializationOrderModuleList);
367 }
368 }
369
370 /* Check if the Bound Entry is now invalid */
371 if (!(NT_SUCCESS(Status)) ||
372 (ForwarderEntry->TimeDateStamp != ForwarderLdrEntry->TimeDateStamp) ||
373 (ForwarderLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
374 {
375 /* Show debug message */
376 if (ShowSnaps)
377 {
378 DPRINT1("LDR: %wZ has stale binding to %s\n",
379 &ForwarderLdrEntry->BaseDllName,
380 ForwarderName);
381 }
382
383 /* Remember it's become stale */
384 Stale = TRUE;
385 }
386 else
387 {
388 /* Show debug message */
389 if (ShowSnaps)
390 {
391 DPRINT1("LDR: %wZ has correct binding to %s\n",
392 &ForwarderLdrEntry->BaseDllName,
393 ForwarderName);
394 }
395
396 /* Remember it's valid */
397 Stale = FALSE;
398 }
399
400 /* Move to the next one */
401 ForwarderEntry++;
402 }
403
404 /* Set the next bound entry to the forwarder */
405 FirstEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ForwarderEntry;
406
407 /* Check if the binding was stale */
408 if (Stale)
409 {
410 /* It was, so find the IAT entry for it */
411 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
412 TRUE,
413 IMAGE_DIRECTORY_ENTRY_IMPORT,
414 &IatSize);
415
416 /* Make sure it has a name */
417 while (ImportEntry->Name)
418 {
419 /* Get the name */
420 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
421
422 /* Compare it */
423 if (!_stricmp(ImportName, BoundImportName)) break;
424
425 /* Move to next entry */
426 ImportEntry += 1;
427 }
428
429 /* If we didn't find a name, fail */
430 if (!ImportEntry->Name)
431 {
432 /* Show debug message */
433 if (ShowSnaps)
434 {
435 DPRINT1("LDR: LdrpWalkImportTable - failing with"
436 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
437 }
438
439 /* Return error */
440 Status = STATUS_OBJECT_NAME_INVALID;
441 goto Quickie;
442 }
443
444 /* Show debug message */
445 if (ShowSnaps)
446 {
447 DPRINT1("LDR: Stale Bind %s from %wZ\n",
448 ImportName,
449 &LdrEntry->BaseDllName);
450 }
451
452 /* Snap the IAT Entry*/
453 Status = LdrpSnapIAT(DllLdrEntry,
454 LdrEntry,
455 ImportEntry,
456 FALSE);
457
458 /* Make sure we didn't fail */
459 if (!NT_SUCCESS(Status))
460 {
461 /* Show debug message */
462 if (ShowSnaps)
463 {
464 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
465 &LdrEntry->BaseDllName,
466 BoundImportName,
467 Status);
468 }
469
470 /* Return */
471 goto Quickie;
472 }
473 }
474
475 /* All done */
476 Status = STATUS_SUCCESS;
477
478 Quickie:
479 /* Write where we are now and return */
480 *BoundEntry = *FirstEntry;
481 return Status;
482 }
483
484 NTSTATUS
485 NTAPI
486 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
487 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
488 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry)
489 {
490 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry = BoundEntry;
491 NTSTATUS Status;
492
493 /* Make sure we have a name */
494 while (BoundEntry->OffsetModuleName)
495 {
496 /* Parse this descriptor */
497 Status = LdrpHandleOneNewFormatImportDescriptor(DllPath,
498 LdrEntry,
499 BoundEntry,
500 FirstEntry);
501 if (!NT_SUCCESS(Status)) return Status;
502 }
503
504 /* Done */
505 return STATUS_SUCCESS;
506 }
507
508 NTSTATUS
509 NTAPI
510 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
511 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
512 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry)
513 {
514 //ULONG IatSize, i;
515 LPSTR ImportName;
516 NTSTATUS Status;
517 BOOLEAN AlreadyLoaded = FALSE, StaticEntriesValid = FALSE, SkipSnap = FALSE;
518 PLDR_DATA_TABLE_ENTRY DllLdrEntry;
519 PIMAGE_THUNK_DATA FirstThunk;
520 PPEB Peb = NtCurrentPeb();
521
522 /* Get the import name's VA */
523 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
524
525 /* Get the first thunk */
526 FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase +
527 ImportEntry->FirstThunk);
528
529 /* Make sure it's valid */
530 if (!FirstThunk->u1.Function) goto SkipEntry;
531
532 /* Show debug message */
533 if (ShowSnaps)
534 {
535 DPRINT1("LDR: %s used by %wZ\n",
536 ImportName,
537 &LdrEntry->BaseDllName);
538 }
539
540 /* Load the module associated to it */
541 Status = LdrpLoadImportModule(DllPath,
542 ImportName,
543 LdrEntry->DllBase,
544 &DllLdrEntry,
545 &AlreadyLoaded);
546 if (!NT_SUCCESS(Status)) return Status;
547
548 /* Show debug message */
549 if (ShowSnaps)
550 {
551 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
552 &LdrEntry->BaseDllName,
553 ImportName);
554 }
555
556 /* Check if the image was bound when compiled */
557 if (ImportEntry->OriginalFirstThunk)
558 {
559 /* It was, so check if the static IAT entries are still valid */
560 if ((ImportEntry->TimeDateStamp) &&
561 (ImportEntry->TimeDateStamp == DllLdrEntry->TimeDateStamp) &&
562 (!(DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)))
563 {
564 /* Show debug message */
565 if (ShowSnaps)
566 {
567 DPRINT1("LDR: Snap bypass %s from %wZ\n",
568 ImportName,
569 &LdrEntry->BaseDllName);
570 }
571
572 /*
573 * They are still valid, so we can skip snapping them.
574 * Additionally, if we have no forwarders, we are totally
575 * done.
576 */
577 if (ImportEntry->ForwarderChain == -1)
578 {
579 /* Totally skip LdrpSnapIAT */
580 SkipSnap = TRUE;
581 }
582 else
583 {
584 /* Set this so LdrpSnapIAT will only do forwarders */
585 StaticEntriesValid = TRUE;
586 }
587 }
588 }
589
590 /* Check if it wasn't already loaded */
591 if (!AlreadyLoaded)
592 {
593 /* Add the DLL to our list */
594 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
595 &DllLdrEntry->InInitializationOrderModuleList);
596 }
597
598 /* Check if we should snap at all */
599 if (!SkipSnap)
600 {
601 /* Now snap the IAT Entry */
602 Status = LdrpSnapIAT(DllLdrEntry,
603 LdrEntry,
604 ImportEntry,
605 StaticEntriesValid);
606 if (!NT_SUCCESS(Status)) return Status;
607 }
608
609 SkipEntry:
610 return STATUS_SUCCESS;
611 }
612
613 NTSTATUS
614 NTAPI
615 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
616 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
617 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry)
618 {
619 NTSTATUS Status;
620
621 /* Check for Name and Thunk */
622 while (ImportEntry->Name && ImportEntry->FirstThunk)
623 {
624 /* Parse this descriptor */
625 Status = LdrpHandleOneOldFormatImportDescriptor(DllPath,
626 LdrEntry,
627 ImportEntry);
628 if (!NT_SUCCESS(Status)) return Status;
629
630 /* Move to the next entry */
631 ImportEntry++;
632 }
633
634 /* Done */
635 return STATUS_SUCCESS;
636 }
637
638 USHORT NTAPI
639 LdrpNameToOrdinal(LPSTR ImportName,
640 ULONG NumberOfNames,
641 PVOID ExportBase,
642 PULONG NameTable,
643 PUSHORT OrdinalTable)
644 {
645 UNIMPLEMENTED;
646 return 0;
647 }
648
649 NTSTATUS
650 NTAPI
651 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL,
652 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
653 {
654 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
655 PPEB Peb = NtCurrentPeb();
656 NTSTATUS Status = STATUS_SUCCESS;
657 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL;
658 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
659 ULONG BoundSize, IatSize;
660 DPRINT1("LdrpWalkImportDescriptor('%S' %x)\n", DllPath, LdrEntry);
661 /* Set up the Act Ctx */
662 ActCtx.Size = sizeof(ActCtx);
663 ActCtx.Frame.Flags = 1;
664 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
665
666 /* Check if we have a manifest prober routine */
667 if (LdrpManifestProberRoutine)
668 {
669 DPRINT1("We don't support manifests yet, much less prober routines\n");
670 }
671
672 /* Check if we failed above */
673 if (!NT_SUCCESS(Status)) return Status;
674
675 /* Get the Active ActCtx */
676 Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext);
677 if (!NT_SUCCESS(Status)) return Status;
678
679 /* Activate the ActCtx */
680 RtlActivateActivationContextUnsafeFast(&ActCtx,
681 LdrEntry->EntryPointActivationContext);
682
683 /* Check if we were directed */
684 if (!(LdrEntry->Flags & LDRP_REDIRECTED))
685 {
686 /* Get the Bound IAT */
687 BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
688 TRUE,
689 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
690 &BoundSize);
691 }
692
693 /* Get the regular IAT, for fallback */
694 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
695 TRUE,
696 IMAGE_DIRECTORY_ENTRY_IMPORT,
697 &IatSize);
698
699 /* Check if we got at least one */
700 if (BoundEntry || ImportEntry)
701 {
702 /* Do we have a Bound IAT */
703 if (BoundEntry)
704 {
705 /* Handle the descriptor */
706 Status = LdrpHandleNewFormatImportDescriptors(DllPath,
707 LdrEntry,
708 BoundEntry);
709 }
710 else
711 {
712 /* Handle the descriptor */
713 Status = LdrpHandleOldFormatImportDescriptors(DllPath,
714 LdrEntry,
715 ImportEntry);
716 }
717
718 /* Check the status of the handlers */
719 if (NT_SUCCESS(Status))
720 {
721 /* Check for Per-DLL Heap Tagging */
722 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL)
723 {
724 /* FIXME */
725 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
726 }
727
728 /* Check if Page Heap was enabled */
729 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
730 {
731 /* FIXME */
732 DPRINT1("We don't support Page Heaps yet!\n");
733 }
734
735 /* Check if Application Verifier was enabled */
736 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
737 {
738 /* FIXME */
739 DPRINT1("We don't support Application Verifier yet!\n");
740 }
741
742 /* Just to be safe */
743 Status = STATUS_SUCCESS;
744 }
745 }
746
747 /* Release the activation context */
748 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
749
750 /* Return status */
751 return Status;
752 }
753
754 NTSTATUS
755 NTAPI
756 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
757 IN LPSTR ImportName,
758 IN PVOID DllBase,
759 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
760 OUT PBOOLEAN Existing)
761 {
762 ANSI_STRING AnsiString;
763 PUNICODE_STRING ImpDescName;
764 NTSTATUS Status;
765 PPEB Peb = RtlGetCurrentPeb();
766 PTEB Teb = NtCurrentTeb();
767 DPRINT1("LdrpLoadImportModule('%S' '%s' %p %p %p)\n", DllPath, ImportName, DllBase, DataTableEntry, Existing);
768 /* Convert import descriptor name to unicode string */
769 ImpDescName = &Teb->StaticUnicodeString;
770 RtlInitAnsiString(&AnsiString, ImportName);
771 Status = RtlAnsiStringToUnicodeString(ImpDescName, &AnsiString, FALSE);
772 if (!NT_SUCCESS(Status)) return Status;
773
774 /* Check if it's loaded */
775 if (LdrpCheckForLoadedDll(DllPath,
776 ImpDescName,
777 TRUE,
778 FALSE,
779 DataTableEntry))
780 {
781 /* It's already existing in the list */
782 *Existing = TRUE;
783 return STATUS_SUCCESS;
784 }
785
786 /* We're loading it for the first time */
787 *Existing = FALSE;
788
789 /* Map it */
790 Status = LdrpMapDll(DllPath,
791 ImpDescName->Buffer,
792 NULL,
793 NULL,
794 TRUE,
795 FALSE,
796 DataTableEntry);
797
798 if (!NT_SUCCESS(Status)) return Status;
799
800 /* Walk its import descriptor table */
801 Status = LdrpWalkImportDescriptor(DllPath,
802 *DataTableEntry);
803 if (!NT_SUCCESS(Status))
804 {
805 /* Add it to the in-init-order list in case of failure */
806 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
807 &(*DataTableEntry)->InInitializationOrderModuleList);
808 }
809
810 return Status;
811 }
812
813 NTSTATUS
814 NTAPI
815 LdrpSnapThunk(IN PVOID ExportBase,
816 IN PVOID ImportBase,
817 IN PIMAGE_THUNK_DATA OriginalThunk,
818 IN OUT PIMAGE_THUNK_DATA Thunk,
819 IN PIMAGE_EXPORT_DIRECTORY ExportEntry,
820 IN ULONG ExportSize,
821 IN BOOLEAN Static,
822 IN LPSTR DllName)
823 {
824 BOOLEAN IsOrdinal;
825 USHORT Ordinal;
826 ULONG OriginalOrdinal = 0;
827 PIMAGE_IMPORT_BY_NAME AddressOfData;
828 PULONG NameTable;
829 PUSHORT OrdinalTable;
830 LPSTR ImportName = NULL;
831 USHORT Hint;
832 NTSTATUS Status;
833 ULONG_PTR HardErrorParameters[3];
834 UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
835 ANSI_STRING TempString;
836 ULONG Mask;
837 ULONG Response;
838 PULONG AddressOfFunctions;
839 UNICODE_STRING TempUString;
840 ANSI_STRING ForwarderName;
841 PANSI_STRING ForwardName;
842 PVOID ForwarderHandle;
843 ULONG ForwardOrdinal;
844
845 /* Check if the snap is by ordinal */
846 if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))
847 {
848 /* Get the ordinal number, and its normalized version */
849 OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
850 Ordinal = (USHORT)(OriginalOrdinal - ExportEntry->Base);
851 }
852 else
853 {
854 /* First get the data VA */
855 AddressOfData = (PIMAGE_IMPORT_BY_NAME)
856 ((ULONG_PTR)ImportBase +
857 ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
858
859 /* Get the name */
860 ImportName = (LPSTR)AddressOfData->Name;
861
862 /* Now get the VA of the Name and Ordinal Tables */
863 NameTable = (PULONG)((ULONG_PTR)ExportBase +
864 (ULONG_PTR)ExportEntry->AddressOfNames);
865 OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase +
866 (ULONG_PTR)ExportEntry->AddressOfNameOrdinals);
867
868 /* Get the hint */
869 Hint = AddressOfData->Hint;
870
871 /* Try to get a match by using the hint */
872 if (((ULONG)Hint < ExportEntry->NumberOfNames) &&
873 (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint])))))
874 {
875 /* We got a match, get the Ordinal from the hint */
876 Ordinal = OrdinalTable[Hint];
877 }
878 else
879 {
880 /* Well bummer, hint didn't work, do it the long way */
881 Ordinal = LdrpNameToOrdinal(ImportName,
882 ExportEntry->NumberOfNames,
883 ExportBase,
884 NameTable,
885 OrdinalTable);
886 }
887 }
888
889 /* Check if the ordinal is invalid */
890 if ((ULONG)Ordinal >= ExportEntry->NumberOfFunctions)
891 {
892 FailurePath:
893 /* Is this a static snap? */
894 if (Static)
895 {
896 /* These are critical errors. Setup a string for the DLL name */
897 RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown");
898 RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE);
899
900 /* Set it as the parameter */
901 HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName;
902 Mask = 2;
903
904 /* Check if we have an ordinal */
905 if (IsOrdinal)
906 {
907 /* Then set the ordinal as the 1st parameter */
908 HardErrorParameters[0] = OriginalOrdinal;
909 }
910 else
911 {
912 /* We don't, use the entrypoint. Set up a string for it */
913 RtlInitAnsiString(&TempString, ImportName);
914 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName,
915 &TempString,
916 TRUE);
917
918 /* Set it as the parameter */
919 HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName;
920 Mask = 3;
921 }
922
923 /* Raise the error */
924 NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
925 STATUS_ENTRYPOINT_NOT_FOUND,
926 2,
927 Mask,
928 HardErrorParameters,
929 OptionOk,
930 &Response);
931
932 /* Increase the error count */
933 if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
934
935 /* Free our string */
936 RtlFreeUnicodeString(&HardErrorDllName);
937 if (!IsOrdinal)
938 {
939 /* Free our second string. Return entrypoint error */
940 RtlFreeUnicodeString(&HardErrorEntryPointName);
941 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
942 }
943
944 /* Return ordinal error */
945 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
946 }
947
948 /* Set this as a bad DLL */
949 Thunk->u1.Function = (ULONG_PTR)0xffbadd11;
950
951 /* Return the right error code */
952 Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
953 STATUS_ENTRYPOINT_NOT_FOUND;
954 }
955 else
956 {
957 /* The ordinal seems correct, get the AddressOfFunctions VA */
958 AddressOfFunctions = (PULONG)
959 ((ULONG_PTR)ExportBase +
960 (ULONG_PTR)ExportEntry->AddressOfFunctions);
961
962 /* Write the function pointer*/
963 Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
964
965 /* Make sure it's within the exports */
966 if ((Thunk->u1.Function > (ULONG_PTR)ExportEntry) &&
967 (Thunk->u1.Function < ((ULONG_PTR)ExportEntry + ExportSize)))
968 {
969 /* Get the Import and Forwarder Names */
970 ImportName = (LPSTR)Thunk->u1.Function;
971 ForwarderName.Buffer = ImportName;
972 ForwarderName.Length = (USHORT)(strchr(ImportName, '.') - ImportName);
973 ForwarderName.MaximumLength = ForwarderName.Length;
974 Status = RtlAnsiStringToUnicodeString(&TempUString,
975 &ForwarderName,
976 TRUE);
977
978 /* Make sure the conversion was OK */
979 if (NT_SUCCESS(Status))
980 {
981 /* Load the forwarder, free the temp string */
982 Status = LdrpLoadDll(FALSE,
983 NULL,
984 NULL,
985 &TempUString,
986 &ForwarderHandle,
987 FALSE);
988 RtlFreeUnicodeString(&TempUString);
989 }
990
991 /* If the load or conversion failed, use the failure path */
992 if (!NT_SUCCESS(Status)) goto FailurePath;
993
994 /* Now set up a name for the actual forwarder dll */
995 RtlInitAnsiString(&ForwarderName,
996 ImportName + ForwarderName.Length + sizeof(CHAR));
997
998 /* Check if it's an ordinal forward */
999 if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
1000 {
1001 /* We don't have an actual function name */
1002 ForwardName = NULL;
1003
1004 /* Convert the string into an ordinal */
1005 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),
1006 0,
1007 &ForwardOrdinal);
1008
1009 /* If this fails, then error out */
1010 if (!NT_SUCCESS(Status)) goto FailurePath;
1011 }
1012 else
1013 {
1014 /* Import by name */
1015 ForwardName = &ForwarderName;
1016 }
1017
1018 /* Get the pointer */
1019 Status = LdrpGetProcedureAddress(ForwarderHandle,
1020 ForwardName,
1021 ForwardOrdinal,
1022 (PVOID*)&Thunk->u1.Function,
1023 FALSE);
1024 /* If this fails, then error out */
1025 if (!NT_SUCCESS(Status)) goto FailurePath;
1026 }
1027 else
1028 {
1029 /* It's not within the exports, let's hope it's valid */
1030 if (!AddressOfFunctions[Ordinal]) goto FailurePath;
1031 }
1032
1033 /* If we got here, then it's success */
1034 Status = STATUS_SUCCESS;
1035 }
1036
1037 /* Return status */
1038 return Status;
1039 }
1040
1041 /* EOF */