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