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