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