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