- Merge the remaining portion of the wlan-bringup branch
[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 /* 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 ASSERT(TestName.Length < TestName.MaximumLength);
1864
1865 /* Check if the file exists */
1866 #if 0
1867 if (RtlDoesFileExists_UstrEx(&TestName, FALSE))
1868 #endif
1869 {
1870 /* It does. Reallocate the buffer */
1871 TestName.MaximumLength = (USHORT)ALIGN_DOWN((BufEnd - Buffer), WCHAR) + sizeof(WCHAR);
1872 TestName.Buffer = RtlReAllocateHeap(RtlGetProcessHeap(),
1873 0,
1874 Buffer,
1875 TestName.MaximumLength);
1876 if (!TestName.Buffer)
1877 {
1878 /* Keep the old one */
1879 TestName.Buffer = Buffer;
1880 }
1881 else
1882 {
1883 /* Update buffer */
1884 Buffer = TestName.Buffer;
1885 }
1886
1887 /* Make sure we have a buffer at least */
1888 ASSERT(TestName.Buffer);
1889
1890 /* Resolve the name */
1891 *SearchPath = ActualSearchPath++;
1892 Status = LdrpResolveFullName(&TestName,
1893 PathName,
1894 FullPathName,
1895 ExpandedName);
1896 break;
1897 }
1898
1899 /* Update buffer end */
1900 BufEnd = Buffer;
1901
1902 /* Update string position */
1903 //pp = ActualSearchPath++;
1904 }
1905 else
1906 {
1907 /* Otherwise, write the character */
1908 *BufEnd = p;
1909 BufEnd++;
1910 }
1911
1912 /* Check if the string is empty, meaning we're done */
1913 if (!(*ActualSearchPath)) TryAgain = TRUE;
1914
1915 /* Advance in the string */
1916 ActualSearchPath++;
1917 } while (!TryAgain);
1918
1919 /* Check if we had a buffer and free it */
1920 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1921
1922 Quickie:
1923 /* Check if we got here through failure */
1924 if (!NT_SUCCESS(Status)) *ExpandedName = NULL;
1925
1926 /* Display debug output if snaps are on */
1927 if (ShowSnaps)
1928 {
1929 /* Check which output to use -- failure or success */
1930 if (NT_SUCCESS(Status))
1931 {
1932 DbgPrintEx(81, //DPFLTR_LDR_ID,
1933 0,
1934 "LDR: %s - Returning %wZ\n",
1935 __FUNCTION__,
1936 *ExpandedName);
1937 }
1938 else
1939 {
1940 DbgPrintEx(81, //DPFLTR_LDR_ID,
1941 0,
1942 "LDR: %s - Unable to locate %ws in %ws: 0x%08x\n",
1943 __FUNCTION__,
1944 DllName,
1945 ActualSearchPath,
1946 Status);
1947 }
1948 }
1949
1950 /* Return status */
1951 return Status;
1952 }
1953
1954
1955 /* NOTE: This function is b0rked and in the process of being slowly unf*cked */
1956 BOOLEAN
1957 NTAPI
1958 LdrpCheckForLoadedDll(IN PWSTR DllPath,
1959 IN PUNICODE_STRING DllName,
1960 IN BOOLEAN Flag,
1961 IN BOOLEAN RedirectedDll,
1962 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
1963 {
1964 ULONG HashIndex;
1965 PLIST_ENTRY ListHead, ListEntry;
1966 PLDR_DATA_TABLE_ENTRY CurEntry;
1967 BOOLEAN FullPath = FALSE;
1968 PWCHAR wc;
1969 WCHAR NameBuf[266];
1970 UNICODE_STRING FullDllName, NtPathName;
1971 ULONG Length;
1972 OBJECT_ATTRIBUTES ObjectAttributes;
1973 NTSTATUS Status;
1974 HANDLE FileHandle, SectionHandle;
1975 IO_STATUS_BLOCK Iosb;
1976 PVOID ViewBase = NULL;
1977 SIZE_T ViewSize = 0;
1978 PIMAGE_NT_HEADERS NtHeader, NtHeader2;
1979 DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"", DllName, Flag, RedirectedDll, LdrEntry);
1980
1981 /* Check if a dll name was provided */
1982 if (!(DllName->Buffer) || !(DllName->Buffer[0])) return FALSE;
1983
1984 /* FIXME: Warning, "Flag" is used as magic instead of "Static" */
1985 /* FIXME: Warning, code does not support redirection at all */
1986
1987 /* Look in the hash table if flag was set */
1988 lookinhash:
1989 if (Flag)
1990 {
1991 /* Get hash index */
1992 HashIndex = LDR_GET_HASH_ENTRY(DllName->Buffer[0]);
1993
1994 /* Traverse that list */
1995 ListHead = &LdrpHashTable[HashIndex];
1996 ListEntry = ListHead->Flink;
1997 while (ListEntry != ListHead)
1998 {
1999 /* Get the current entry */
2000 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
2001
2002 /* Check base name of that module */
2003 if (RtlEqualUnicodeString(DllName, &CurEntry->BaseDllName, TRUE))
2004 {
2005 /* It matches, return it */
2006 *LdrEntry = CurEntry;
2007 return TRUE;
2008 }
2009
2010 /* Advance to the next entry */
2011 ListEntry = ListEntry->Flink;
2012 }
2013
2014 /* Module was not found, return failure */
2015 return FALSE;
2016 }
2017
2018 /* Check if there is a full path in this DLL */
2019 wc = DllName->Buffer;
2020 while (*wc)
2021 {
2022 /* Check for a slash in the current position*/
2023 if ((*wc == L'\\') || (*wc == L'/'))
2024 {
2025 /* Found the slash, so dll name contains path */
2026 FullPath = TRUE;
2027
2028 /* Setup full dll name string */
2029 FullDllName.Buffer = NameBuf;
2030
2031 /* FIXME: This is from the Windows 2000 loader, not XP/2003, we should call LdrpSearchPath */
2032 Length = RtlDosSearchPath_U(DllPath ? DllPath : LdrpDefaultPath.Buffer,
2033 DllName->Buffer,
2034 NULL,
2035 sizeof(NameBuf) - sizeof(UNICODE_NULL),
2036 FullDllName.Buffer,
2037 NULL);
2038
2039 /* Check if that was successful */
2040 if (!(Length) || (Length > (sizeof(NameBuf) - sizeof(UNICODE_NULL))))
2041 {
2042 /* HACK: Try to find active context dll */
2043 Status = find_actctx_dll(DllName->Buffer, FullDllName.Buffer);
2044 if(Status == STATUS_SUCCESS)
2045 {
2046 Length = wcslen(FullDllName.Buffer) * sizeof(WCHAR);
2047 DPRINT1("found %S for %S\n", FullDllName.Buffer, DllName->Buffer);
2048 }
2049 else
2050 {
2051
2052 if (ShowSnaps)
2053 {
2054 DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n",
2055 DllName->Buffer, Length);
2056 }
2057
2058 /* Return failure */
2059 return FALSE;
2060 }
2061 }
2062
2063 /* Full dll name is found */
2064 FullDllName.Length = Length;
2065 FullDllName.MaximumLength = FullDllName.Length + sizeof(UNICODE_NULL);
2066 break;
2067 }
2068
2069 wc++;
2070 }
2071
2072 /* Go check the hash table */
2073 if (!FullPath)
2074 {
2075 Flag = TRUE;
2076 goto lookinhash;
2077 }
2078
2079 /* FIXME: Warning, activation context missing */
2080 /* NOTE: From here on down, everything looks good */
2081
2082 /* Loop the module list */
2083 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2084 ListEntry = ListHead->Flink;
2085 while (ListEntry != ListHead)
2086 {
2087 /* Get the current entry and advance to the next one */
2088 CurEntry = CONTAINING_RECORD(ListEntry,
2089 LDR_DATA_TABLE_ENTRY,
2090 InLoadOrderLinks);
2091 ListEntry = ListEntry->Flink;
2092
2093 /* Check if it's being unloaded */
2094 if (!CurEntry->InMemoryOrderModuleList.Flink) continue;
2095
2096 /* Check if name matches */
2097 if (RtlEqualUnicodeString(&FullDllName,
2098 &CurEntry->FullDllName,
2099 TRUE))
2100 {
2101 /* Found it */
2102 *LdrEntry = CurEntry;
2103 return TRUE;
2104 }
2105 }
2106
2107 /* Convert given path to NT path */
2108 if (!RtlDosPathNameToNtPathName_U(FullDllName.Buffer,
2109 &NtPathName,
2110 NULL,
2111 NULL))
2112 {
2113 /* Fail if conversion failed */
2114 return FALSE;
2115 }
2116
2117 /* Initialize object attributes and open it */
2118 InitializeObjectAttributes(&ObjectAttributes,
2119 &NtPathName,
2120 OBJ_CASE_INSENSITIVE,
2121 NULL,
2122 NULL);
2123 Status = NtOpenFile(&FileHandle,
2124 SYNCHRONIZE | FILE_EXECUTE,
2125 &ObjectAttributes,
2126 &Iosb,
2127 FILE_SHARE_READ | FILE_SHARE_DELETE,
2128 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
2129
2130 /* Free NT path name */
2131 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
2132
2133 /* If opening the file failed - return failure */
2134 if (!NT_SUCCESS(Status)) return FALSE;
2135
2136 /* Create a section for this file */
2137 Status = NtCreateSection(&SectionHandle,
2138 SECTION_MAP_READ |
2139 SECTION_MAP_EXECUTE |
2140 SECTION_MAP_WRITE,
2141 NULL,
2142 NULL,
2143 PAGE_EXECUTE,
2144 SEC_COMMIT,
2145 FileHandle);
2146
2147 /* Close file handle */
2148 NtClose(FileHandle);
2149
2150 /* If creating section failed - return failure */
2151 if (!NT_SUCCESS(Status)) return FALSE;
2152
2153 /* Map view of this section */
2154 Status = ZwMapViewOfSection(SectionHandle,
2155 NtCurrentProcess(),
2156 &ViewBase,
2157 0,
2158 0,
2159 NULL,
2160 &ViewSize,
2161 ViewShare,
2162 0,
2163 PAGE_EXECUTE);
2164
2165 /* Close section handle */
2166 NtClose(SectionHandle);
2167
2168 /* If section mapping failed - return failure */
2169 if (!NT_SUCCESS(Status)) return FALSE;
2170
2171 /* Get pointer to the NT header of this section */
2172 Status = RtlImageNtHeaderEx(0, ViewBase, ViewSize, &NtHeader);
2173 if (!(NT_SUCCESS(Status)) || !(NtHeader))
2174 {
2175 /* Unmap the section and fail */
2176 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2177 return FALSE;
2178 }
2179
2180 /* Go through the list of modules again */
2181 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2182 ListEntry = ListHead->Flink;
2183 while (ListEntry != ListHead)
2184 {
2185 /* Get the current entry and advance to the next one */
2186 CurEntry = CONTAINING_RECORD(ListEntry,
2187 LDR_DATA_TABLE_ENTRY,
2188 InLoadOrderLinks);
2189 ListEntry = ListEntry->Flink;
2190
2191 /* Check if it's in the process of being unloaded */
2192 if (!CurEntry->InMemoryOrderModuleList.Flink) continue;
2193
2194 /* The header is untrusted, use SEH */
2195 _SEH2_TRY
2196 {
2197 /* Check if timedate stamp and sizes match */
2198 if ((CurEntry->TimeDateStamp == NtHeader->FileHeader.TimeDateStamp) &&
2199 (CurEntry->SizeOfImage == NtHeader->OptionalHeader.SizeOfImage))
2200 {
2201 /* Time, date and size match. Let's compare their headers */
2202 NtHeader2 = RtlImageNtHeader(CurEntry->DllBase);
2203 if (RtlCompareMemory(NtHeader2, NtHeader, sizeof(IMAGE_NT_HEADERS)))
2204 {
2205 /* Headers match too! Finally ask the kernel to compare mapped files */
2206 Status = ZwAreMappedFilesTheSame(CurEntry->DllBase, ViewBase);
2207 if (!NT_SUCCESS(Status))
2208 {
2209 /* Almost identical, but not quite, keep trying */
2210 _SEH2_YIELD(continue;)
2211 }
2212 else
2213 {
2214 /* This is our entry!, unmap and return success */
2215 *LdrEntry = CurEntry;
2216 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2217 _SEH2_YIELD(return TRUE;)
2218 }
2219 }
2220 }
2221 }
2222 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
2223 {
2224 _SEH2_YIELD(break;)
2225 }
2226 _SEH2_END;
2227 }
2228
2229 /* Unmap the section and fail */
2230 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
2231 return FALSE;
2232 }
2233
2234 NTSTATUS
2235 NTAPI
2236 LdrpGetProcedureAddress(IN PVOID BaseAddress,
2237 IN PANSI_STRING Name,
2238 IN ULONG Ordinal,
2239 OUT PVOID *ProcedureAddress,
2240 IN BOOLEAN ExecuteInit)
2241 {
2242 NTSTATUS Status = STATUS_SUCCESS;
2243 UCHAR ImportBuffer[64];
2244 PLDR_DATA_TABLE_ENTRY LdrEntry;
2245 IMAGE_THUNK_DATA Thunk;
2246 PVOID ImageBase;
2247 PIMAGE_IMPORT_BY_NAME ImportName = NULL;
2248 PIMAGE_EXPORT_DIRECTORY ExportDir;
2249 ULONG ExportDirSize, Length;
2250 PLIST_ENTRY Entry;
2251
2252 /* Show debug message */
2253 if (ShowSnaps) DPRINT1("LDR: LdrGetProcedureAddress by ");
2254
2255 /* Check if we got a name */
2256 if (Name)
2257 {
2258 /* Show debug message */
2259 if (ShowSnaps) DbgPrint("NAME - %s\n", Name->Buffer);
2260
2261 /* Make sure it's not too long */
2262 Length = Name->Length +
2263 sizeof(CHAR) +
2264 FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name);
2265 if (Length > UNICODE_STRING_MAX_BYTES)
2266 {
2267 /* Won't have enough space to add the hint */
2268 return STATUS_NAME_TOO_LONG;
2269 }
2270
2271 /* Check if our buffer is large enough */
2272 if (Name->Length > sizeof(ImportBuffer))
2273 {
2274 /* Allocate from heap, plus 2 bytes for the Hint */
2275 ImportName = RtlAllocateHeap(RtlGetProcessHeap(),
2276 0,
2277 Length);
2278 }
2279 else
2280 {
2281 /* Use our internal buffer */
2282 ImportName = (PIMAGE_IMPORT_BY_NAME)ImportBuffer;
2283 }
2284
2285 /* Clear the hint */
2286 ImportName->Hint = 0;
2287
2288 /* Copy the name and null-terminate it */
2289 RtlCopyMemory(ImportName->Name, Name->Buffer, Name->Length);
2290 ImportName->Name[Name->Length] = ANSI_NULL;
2291
2292 /* Clear the high bit */
2293 ImageBase = ImportName;
2294 Thunk.u1.AddressOfData = 0;
2295 }
2296 else
2297 {
2298 /* Do it by ordinal */
2299 ImageBase = NULL;
2300
2301 /* Show debug message */
2302 if (ShowSnaps) DbgPrint("ORDINAL - %lx\n", Ordinal);
2303
2304 /* Make sure an ordinal was given */
2305 if (!Ordinal)
2306 {
2307 /* No ordinal */
2308 DPRINT1("No ordinal and no name\n");
2309 return STATUS_INVALID_PARAMETER;
2310 }
2311
2312 /* Set the orginal flag in the thunk */
2313 Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG;
2314 }
2315
2316 /* Acquire lock unless we are initting */
2317 if (!LdrpInLdrInit) RtlEnterCriticalSection(&LdrpLoaderLock);
2318
2319 _SEH2_TRY
2320 {
2321 /* Try to find the loaded DLL */
2322 if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
2323 {
2324 /* Invalid base */
2325 DPRINT1("Invalid base address %p\n", BaseAddress);
2326 Status = STATUS_DLL_NOT_FOUND;
2327 _SEH2_YIELD(goto Quickie;)
2328 }
2329
2330 /* Get the pointer to the export directory */
2331 ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
2332 TRUE,
2333 IMAGE_DIRECTORY_ENTRY_EXPORT,
2334 &ExportDirSize);
2335
2336 if (!ExportDir)
2337 {
2338 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);
2339 Status = STATUS_PROCEDURE_NOT_FOUND;
2340 _SEH2_YIELD(goto Quickie;)
2341 }
2342
2343 /* Now get the thunk */
2344 Status = LdrpSnapThunk(LdrEntry->DllBase,
2345 ImageBase,
2346 &Thunk,
2347 &Thunk,
2348 ExportDir,
2349 ExportDirSize,
2350 FALSE,
2351 NULL);
2352
2353 /* Finally, see if we're supposed to run the init routines */
2354 if ((NT_SUCCESS(Status)) && (ExecuteInit))
2355 {
2356 /*
2357 * It's possible a forwarded entry had us load the DLL. In that case,
2358 * then we will call its DllMain. Use the last loaded DLL for this.
2359 */
2360 Entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink;
2361 LdrEntry = CONTAINING_RECORD(Entry,
2362 LDR_DATA_TABLE_ENTRY,
2363 InInitializationOrderModuleList);
2364
2365 /* Make sure we didn't process it yet*/
2366 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
2367 {
2368 /* Call the init routine */
2369 _SEH2_TRY
2370 {
2371 Status = LdrpRunInitializeRoutines(NULL);
2372 }
2373 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2374 {
2375 /* Get the exception code */
2376 Status = _SEH2_GetExceptionCode();
2377 }
2378 _SEH2_END;
2379 }
2380 }
2381
2382 /* Make sure we're OK till here */
2383 if (NT_SUCCESS(Status))
2384 {
2385 /* Return the address */
2386 *ProcedureAddress = (PVOID)Thunk.u1.Function;
2387 }
2388 }
2389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2390 {
2391 /* Just ignore exceptions */
2392 }
2393 _SEH2_END;
2394
2395 Quickie:
2396 /* Cleanup */
2397 if (ImportName && (ImportName != (PIMAGE_IMPORT_BY_NAME)ImportBuffer))
2398 {
2399 /* We allocated from heap, free it */
2400 RtlFreeHeap(RtlGetProcessHeap(), 0, ImportName);
2401 }
2402
2403 /* Release the CS if we entered it */
2404 if (!LdrpInLdrInit) RtlLeaveCriticalSection(&LdrpLoaderLock);
2405
2406 /* We're done */
2407 return Status;
2408 }
2409
2410 NTSTATUS
2411 NTAPI
2412 LdrpLoadDll(IN BOOLEAN Redirected,
2413 IN PWSTR DllPath OPTIONAL,
2414 IN PULONG DllCharacteristics OPTIONAL,
2415 IN PUNICODE_STRING DllName,
2416 OUT PVOID *BaseAddress,
2417 IN BOOLEAN CallInit)
2418 {
2419 PPEB Peb = NtCurrentPeb();
2420 NTSTATUS Status = STATUS_SUCCESS;
2421 PWCHAR p1, p2;
2422 WCHAR c;
2423 WCHAR NameBuffer[266];
2424 LPWSTR RawDllName;
2425 UNICODE_STRING RawDllNameString;
2426 PLDR_DATA_TABLE_ENTRY LdrEntry;
2427 BOOLEAN InInit = LdrpInLdrInit;
2428
2429 /* Find the name without the extension */
2430 p1 = DllName->Buffer;
2431 p2 = NULL;
2432 while (*p1)
2433 {
2434 c = *p1++;
2435 if (c == L'.')
2436 {
2437 p2 = p1;
2438 }
2439 else if (c == L'\\')
2440 {
2441 p2 = NULL;
2442 }
2443 }
2444
2445 /* Save the Raw DLL Name */
2446 RawDllName = NameBuffer;
2447 if (DllName->Length >= sizeof(NameBuffer)) return STATUS_NAME_TOO_LONG;
2448 RtlMoveMemory(RawDllName, DllName->Buffer, DllName->Length);
2449
2450 /* Check if no extension was found or if we got a slash */
2451 if (!(p2) || (*p2 == '\\'))
2452 {
2453 /* Check that we have space to add one */
2454 if ((DllName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >=
2455 sizeof(NameBuffer))
2456 {
2457 /* No space to add the extension */
2458 DbgPrintEx(81, //DPFLTR_LDR_ID,
2459 0,
2460 "LDR: %s - Dll name missing extension; with extension "
2461 "added the name is too long\n"
2462 " DllName: (@ %p) \"%wZ\"\n"
2463 " DllName->Length: %u\n",
2464 __FUNCTION__,
2465 DllName,
2466 DllName,
2467 DllName->Length);
2468 return STATUS_NAME_TOO_LONG;
2469 }
2470
2471 /* FIXME: CLEAN THIS UP WITH Rtl String Functions */
2472 /* Add it */
2473 RtlMoveMemory((PVOID)((ULONG_PTR)RawDllName + DllName->Length),
2474 LdrApiDefaultExtension.Buffer,
2475 LdrApiDefaultExtension.Length);
2476
2477 /* Save the length to a unicode string */
2478 RawDllNameString.Length = DllName->Length + LdrApiDefaultExtension.Length;
2479
2480 /* Null terminate it */
2481 RawDllName[RawDllNameString.Length / sizeof(WCHAR)] = 0;
2482 }
2483 else
2484 {
2485 /* Null terminate it */
2486 RawDllName[DllName->Length / sizeof(WCHAR)] = 0;
2487
2488 /* Save the length to a unicode string */
2489 RawDllNameString.Length = DllName->Length;
2490 }
2491
2492 /* Now create a unicode string for the DLL's name */
2493 RawDllNameString.MaximumLength = sizeof(NameBuffer);
2494 RawDllNameString.Buffer = NameBuffer;
2495
2496 /* Check for init flag and acquire lock */
2497 if (!InInit) RtlEnterCriticalSection(&LdrpLoaderLock);
2498
2499 /* Show debug message */
2500 if (ShowSnaps)
2501 {
2502 DPRINT1("LDR: LdrLoadDll, loading %ws from %ws\n",
2503 RawDllName,
2504 DllPath ? DllPath : L"");
2505 }
2506
2507 /* Check if the DLL is already loaded */
2508 if (!LdrpCheckForLoadedDll(DllPath,
2509 &RawDllNameString,
2510 FALSE,
2511 Redirected,
2512 &LdrEntry))
2513 {
2514 /* Map it */
2515 Status = LdrpMapDll(DllPath,
2516 DllPath,
2517 NameBuffer,
2518 DllCharacteristics,
2519 FALSE,
2520 Redirected,
2521 &LdrEntry);
2522 if (!NT_SUCCESS(Status)) goto Quickie;
2523
2524 /* FIXME: Need to mark the DLL range for the stack DB */
2525 //RtlpStkMarkDllRange(LdrEntry);
2526
2527 /* Check if IMAGE_FILE_EXECUTABLE_IMAGE was provided */
2528 if ((DllCharacteristics) &&
2529 (*DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
2530 {
2531 /* This is not a DLL, so remove such data */
2532 LdrEntry->EntryPoint = NULL;
2533 LdrEntry->Flags &= ~LDRP_IMAGE_DLL;
2534 }
2535
2536 /* Make sure it's a DLL */
2537 if (LdrEntry->Flags & LDRP_IMAGE_DLL)
2538 {
2539 /* Check if this is a .NET Image */
2540 if (!(LdrEntry->Flags & LDRP_COR_IMAGE))
2541 {
2542 /* Walk the Import Descriptor */
2543 Status = LdrpWalkImportDescriptor(DllPath, LdrEntry);
2544 }
2545
2546 /* Update load count, unless it's locked */
2547 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++;
2548 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
2549
2550 /* Check if we failed */
2551 if (!NT_SUCCESS(Status))
2552 {
2553 /* Clear entrypoint, and insert into list */
2554 LdrEntry->EntryPoint = NULL;
2555 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
2556 &LdrEntry->InInitializationOrderModuleList);
2557
2558 /* Cancel the load */
2559 LdrpClearLoadInProgress();
2560
2561 /* Unload the DLL */
2562 if (ShowSnaps)
2563 {
2564 DbgPrint("LDR: Unloading %wZ due to error %x walking "
2565 "import descriptors",
2566 DllName,
2567 Status);
2568 }
2569 LdrUnloadDll(LdrEntry->DllBase);
2570
2571 /* Return the error */
2572 goto Quickie;
2573 }
2574 }
2575 else if (LdrEntry->LoadCount != 0xFFFF)
2576 {
2577 /* Increase load count */
2578 LdrEntry->LoadCount++;
2579 }
2580
2581 /* Insert it into the list */
2582 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
2583 &LdrEntry->InInitializationOrderModuleList);
2584
2585 /* If we have to run the entrypoint, make sure the DB is ready */
2586 if (CallInit && LdrpLdrDatabaseIsSetup)
2587 {
2588 /* FIXME: Notify Shim Engine */
2589 if (g_ShimsEnabled)
2590 {
2591 /* Call it */
2592 //ShimLoadCallback = RtlDecodeSystemPointer(g_pfnSE_DllLoaded);
2593 //ShimLoadCallback(LdrEntry);
2594 }
2595
2596 /* Run the init routine */
2597 Status = LdrpRunInitializeRoutines(NULL);
2598 if (!NT_SUCCESS(Status))
2599 {
2600 /* Failed, unload the DLL */
2601 if (ShowSnaps)
2602 {
2603 DbgPrint("LDR: Unloading %wZ because either its init "
2604 "routine or one of its static imports failed; "
2605 "status = 0x%08lx\n",
2606 DllName,
2607 Status);
2608 }
2609 LdrUnloadDll(LdrEntry->DllBase);
2610 }
2611 }
2612 else
2613 {
2614 /* The DB isn't ready, which means we were loaded because of a forwarder */
2615 Status = STATUS_SUCCESS;
2616 }
2617 }
2618 else
2619 {
2620 /* We were already loaded. Are we a DLL? */
2621 if ((LdrEntry->Flags & LDRP_IMAGE_DLL) && (LdrEntry->LoadCount != 0xFFFF))
2622 {
2623 /* Increase load count */
2624 LdrEntry->LoadCount++;
2625 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
2626
2627 /* Clear the load in progress */
2628 LdrpClearLoadInProgress();
2629 }
2630 else
2631 {
2632 /* Not a DLL, just increase the load count */
2633 if (LdrEntry->LoadCount != 0xFFFF) LdrEntry->LoadCount++;
2634 }
2635 }
2636
2637 Quickie:
2638 /* Release the lock */
2639 if (!InInit) RtlLeaveCriticalSection(Peb->LoaderLock);
2640
2641 /* Check for success */
2642 if (NT_SUCCESS(Status))
2643 {
2644 /* Return the base address */
2645 *BaseAddress = LdrEntry->DllBase;
2646 }
2647 else
2648 {
2649 /* Nothing found */
2650 *BaseAddress = NULL;
2651 }
2652
2653 /* Return status */
2654 return Status;
2655 }
2656
2657 ULONG
2658 NTAPI
2659 LdrpClearLoadInProgress(VOID)
2660 {
2661 PLIST_ENTRY ListHead, Entry;
2662 PLDR_DATA_TABLE_ENTRY LdrEntry;
2663 ULONG ModulesCount = 0;
2664
2665 /* Traverse the init list */
2666 ListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2667 Entry = ListHead->Flink;
2668 while (Entry != ListHead)
2669 {
2670 /* Get the loader entry */
2671 LdrEntry = CONTAINING_RECORD(Entry,
2672 LDR_DATA_TABLE_ENTRY,
2673 InInitializationOrderModuleList);
2674
2675 /* Clear load in progress flag */
2676 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2677
2678 /* Check for modules with entry point count but not processed yet */
2679 if ((LdrEntry->EntryPoint) &&
2680 !(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
2681 {
2682 /* Increase counter */
2683 ModulesCount++;
2684 }
2685
2686 /* Advance to the next entry */
2687 Entry = Entry->Flink;
2688 }
2689
2690 /* Return final count */
2691 return ModulesCount;
2692 }
2693
2694 /* EOF */