Sync to trunk r38200
[reactos.git] / reactos / dll / ntdll / ldr / utils.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/ntdll/ldr/utils.c
5 * PURPOSE: Process startup for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
8 */
9
10 /*
11 * TODO:
12 * - Handle loading flags correctly
13 * - Handle errors correctly (unload dll's)
14 * - Implement a faster way to find modules (hash table)
15 * - any more ??
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <ntdll.h>
21 #define NDEBUG
22 #include <debug.h>
23
24 #define LDRP_PROCESS_CREATION_TIME 0x8000000
25
26 /* GLOBALS *******************************************************************/
27
28 #ifdef NDEBUG
29 #if defined(__GNUC__)
30 #define TRACE_LDR(args...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); }
31 #elif defined(_MSC_VER)
32 #define TRACE_LDR(args, ...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
33 #endif /* __GNUC__ */
34 #else
35 #define TRACE_LDR(args...) do { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0)
36 #endif
37
38 typedef struct _TLS_DATA
39 {
40 PVOID StartAddressOfRawData;
41 DWORD TlsDataSize;
42 DWORD TlsZeroSize;
43 PIMAGE_TLS_CALLBACK *TlsAddressOfCallBacks;
44 PLDR_DATA_TABLE_ENTRY Module;
45 } TLS_DATA, *PTLS_DATA;
46
47 static BOOLEAN LdrpDllShutdownInProgress = FALSE;
48 static PTLS_DATA LdrpTlsArray = NULL;
49 static ULONG LdrpTlsCount = 0;
50 static ULONG LdrpTlsSize = 0;
51 static HANDLE LdrpKnownDllsDirHandle = NULL;
52 static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
53 static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL;
54 extern PLDR_DATA_TABLE_ENTRY ExeModule;
55
56 /* PROTOTYPES ****************************************************************/
57
58 static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref);
59 static PVOID LdrFixupForward(PCHAR ForwardName);
60 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
61 static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
62 IN ULONG LoadFlags,
63 IN PUNICODE_STRING Name,
64 OUT PLDR_DATA_TABLE_ENTRY *Module,
65 OUT PVOID *BaseAddress OPTIONAL);
66 static NTSTATUS LdrpAttachProcess(VOID);
67 static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
68
69 /* FUNCTIONS *****************************************************************/
70
71 #if defined(DBG) || defined(KDBG)
72
73 VOID
74 LdrpLoadUserModuleSymbols(PLDR_DATA_TABLE_ENTRY LdrModule)
75 {
76 NtSystemDebugControl(
77 SysDbgQueryVersion,
78 (PVOID)LdrModule,
79 0,
80 NULL,
81 0,
82 NULL);
83 }
84
85 #endif /* DBG || KDBG */
86
87 BOOLEAN
88 LdrMappedAsDataFile(PVOID *BaseAddress)
89 {
90 if (0 != ((DWORD_PTR) *BaseAddress & (PAGE_SIZE - 1)))
91 {
92 *BaseAddress = (PVOID) ((DWORD_PTR) *BaseAddress & ~ ((DWORD_PTR) PAGE_SIZE - 1));
93 return TRUE;
94 }
95
96 return FALSE;
97 }
98
99 static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
100 {
101 LONG LoadCount;
102 if (!Locked)
103 {
104 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
105 }
106 LoadCount = Module->LoadCount;
107 if (Module->LoadCount > 0 && Module->LoadCount != 0xFFFF)
108 {
109 Module->LoadCount--;
110 }
111 if (!Locked)
112 {
113 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
114 }
115 return LoadCount;
116 }
117
118 static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
119 {
120 LONG LoadCount;
121 if (!Locked)
122 {
123 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
124 }
125 LoadCount = Module->LoadCount;
126 if (Module->LoadCount != 0xFFFF)
127 {
128 Module->LoadCount++;
129 }
130 if (!Locked)
131 {
132 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
133 }
134 return LoadCount;
135 }
136
137 static __inline VOID LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module, ULONG Size, BOOLEAN Locked)
138 {
139 if (!Locked)
140 {
141 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
142 }
143 Module->TlsIndex = (SHORT)LdrpTlsCount;
144 LdrpTlsCount++;
145 LdrpTlsSize += Size;
146 if (!Locked)
147 {
148 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
149 }
150 }
151
152 static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
153 {
154 PIMAGE_TLS_CALLBACK *TlsCallback;
155 if (Module->TlsIndex != 0xFFFF && Module->LoadCount == 0xFFFF)
156 {
157 TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
158 if (TlsCallback)
159 {
160 while (*TlsCallback)
161 {
162 TRACE_LDR("%wZ - Calling tls callback at %x\n",
163 &Module->BaseDllName, *TlsCallback);
164 (*TlsCallback)(Module->DllBase, dwReason, NULL);
165 TlsCallback++;
166 }
167 }
168 }
169 }
170
171 static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PVOID lpReserved)
172 {
173 if (!(Module->Flags & LDRP_IMAGE_DLL) ||
174 Module->EntryPoint == 0)
175 {
176 return TRUE;
177 }
178 LdrpTlsCallback(Module, dwReason);
179 return ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);
180 }
181
182 static NTSTATUS
183 LdrpInitializeTlsForThread(VOID)
184 {
185 PVOID* TlsPointers;
186 PTLS_DATA TlsInfo;
187 PVOID TlsData;
188 ULONG i;
189 PTEB Teb = NtCurrentTeb();
190
191 DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
192
193 Teb->StaticUnicodeString.Length = 0;
194 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
195 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
196
197 if (LdrpTlsCount > 0)
198 {
199 TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),
200 0,
201 LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);
202 if (TlsPointers == NULL)
203 {
204 DPRINT1("failed to allocate thread tls data\n");
205 return STATUS_NO_MEMORY;
206 }
207
208 TlsData = (PVOID)((ULONG_PTR)TlsPointers + LdrpTlsCount * sizeof(PVOID));
209 Teb->ThreadLocalStoragePointer = TlsPointers;
210
211 TlsInfo = LdrpTlsArray;
212 for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)
213 {
214 TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo->Module->BaseDllName);
215 TlsPointers[i] = TlsData;
216 if (TlsInfo->TlsDataSize)
217 {
218 memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);
219 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsDataSize);
220 }
221 if (TlsInfo->TlsZeroSize)
222 {
223 memset(TlsData, 0, TlsInfo->TlsZeroSize);
224 TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsZeroSize);
225 }
226 }
227 }
228
229 DPRINT("LdrpInitializeTlsForThread() done\n");
230 return STATUS_SUCCESS;
231 }
232
233 static NTSTATUS
234 LdrpInitializeTlsForProccess(VOID)
235 {
236 PLIST_ENTRY ModuleListHead;
237 PLIST_ENTRY Entry;
238 PLDR_DATA_TABLE_ENTRY Module;
239 PIMAGE_TLS_DIRECTORY TlsDirectory;
240 PTLS_DATA TlsData;
241 ULONG Size;
242
243 DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule->BaseDllName);
244
245 if (LdrpTlsCount > 0)
246 {
247 LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
248 0,
249 LdrpTlsCount * sizeof(TLS_DATA));
250 if (LdrpTlsArray == NULL)
251 {
252 DPRINT1("Failed to allocate global tls data\n");
253 return STATUS_NO_MEMORY;
254 }
255
256 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
257 Entry = ModuleListHead->Flink;
258 while (Entry != ModuleListHead)
259 {
260 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
261 if (Module->LoadCount == 0xFFFF &&
262 Module->TlsIndex != 0xFFFF)
263 {
264 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
265 RtlImageDirectoryEntryToData(Module->DllBase,
266 TRUE,
267 IMAGE_DIRECTORY_ENTRY_TLS,
268 &Size);
269 ASSERT(Module->TlsIndex < LdrpTlsCount);
270 TlsData = &LdrpTlsArray[Module->TlsIndex];
271 TlsData->StartAddressOfRawData = (PVOID)(ULONG_PTR)TlsDirectory->StartAddressOfRawData;
272 TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
273 TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
274 if (TlsDirectory->AddressOfCallBacks)
275 TlsData->TlsAddressOfCallBacks = (PIMAGE_TLS_CALLBACK *)TlsDirectory->AddressOfCallBacks;
276 else
277 TlsData->TlsAddressOfCallBacks = NULL;
278 TlsData->Module = Module;
279 #if 0
280 DbgPrint("TLS directory for %wZ\n", &Module->BaseDllName);
281 DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory->StartAddressOfRawData);
282 DbgPrint("EndAddressOfRawData: %x\n", TlsDirectory->EndAddressOfRawData);
283 DbgPrint("SizeOfRawData: %d\n", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);
284 DbgPrint("AddressOfIndex: %x\n", TlsDirectory->AddressOfIndex);
285 DbgPrint("AddressOfCallBacks: %x\n", TlsDirectory->AddressOfCallBacks);
286 DbgPrint("SizeOfZeroFill: %d\n", TlsDirectory->SizeOfZeroFill);
287 DbgPrint("Characteristics: %x\n", TlsDirectory->Characteristics);
288 #endif
289 /*
290 * FIXME:
291 * Is this region allways writable ?
292 */
293 *(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;
294 }
295 Entry = Entry->Flink;
296 }
297 }
298
299 DPRINT("LdrpInitializeTlsForProccess() done\n");
300 return STATUS_SUCCESS;
301 }
302
303 VOID
304 LdrpInitLoader(VOID)
305 {
306 OBJECT_ATTRIBUTES ObjectAttributes;
307 UNICODE_STRING LinkTarget;
308 UNICODE_STRING Name;
309 HANDLE LinkHandle;
310 ULONG Length;
311 NTSTATUS Status;
312
313 DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule->BaseDllName);
314
315 /* Get handle to the 'KnownDlls' directory */
316 RtlInitUnicodeString(&Name,
317 L"\\KnownDlls");
318 InitializeObjectAttributes(&ObjectAttributes,
319 &Name,
320 OBJ_CASE_INSENSITIVE,
321 NULL,
322 NULL);
323 Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
324 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
325 &ObjectAttributes);
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
329 LdrpKnownDllsDirHandle = NULL;
330 return;
331 }
332
333 /* Allocate target name string */
334 LinkTarget.Length = 0;
335 LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
336 LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
337 0,
338 MAX_PATH * sizeof(WCHAR));
339 if (LinkTarget.Buffer == NULL)
340 {
341 NtClose(LdrpKnownDllsDirHandle);
342 LdrpKnownDllsDirHandle = NULL;
343 return;
344 }
345
346 RtlInitUnicodeString(&Name,
347 L"KnownDllPath");
348 InitializeObjectAttributes(&ObjectAttributes,
349 &Name,
350 OBJ_CASE_INSENSITIVE,
351 LdrpKnownDllsDirHandle,
352 NULL);
353 Status = NtOpenSymbolicLinkObject(&LinkHandle,
354 SYMBOLIC_LINK_ALL_ACCESS,
355 &ObjectAttributes);
356 if (!NT_SUCCESS(Status))
357 {
358 RtlFreeUnicodeString(&LinkTarget);
359 NtClose(LdrpKnownDllsDirHandle);
360 LdrpKnownDllsDirHandle = NULL;
361 return;
362 }
363
364 Status = NtQuerySymbolicLinkObject(LinkHandle,
365 &LinkTarget,
366 &Length);
367 NtClose(LinkHandle);
368 if (!NT_SUCCESS(Status))
369 {
370 RtlFreeUnicodeString(&LinkTarget);
371 NtClose(LdrpKnownDllsDirHandle);
372 LdrpKnownDllsDirHandle = NULL;
373 }
374
375 RtlCreateUnicodeString(&LdrpKnownDllPath,
376 LinkTarget.Buffer);
377
378 RtlFreeUnicodeString(&LinkTarget);
379
380 DPRINT("LdrpInitLoader() done\n");
381 }
382
383
384 /***************************************************************************
385 * NAME LOCAL
386 * LdrAdjustDllName
387 *
388 * DESCRIPTION
389 * Adjusts the name of a dll to a fully qualified name.
390 *
391 * ARGUMENTS
392 * FullDllName: Pointer to caller supplied storage for the fully
393 * qualified dll name.
394 * DllName: Pointer to the dll name.
395 * BaseName: TRUE: Only the file name is passed to FullDllName
396 * FALSE: The full path is preserved in FullDllName
397 *
398 * RETURN VALUE
399 * None
400 *
401 * REVISIONS
402 *
403 * NOTE
404 * A given path is not affected by the adjustment, but the file
405 * name only:
406 * ntdll --> ntdll.dll
407 * ntdll. --> ntdll
408 * ntdll.xyz --> ntdll.xyz
409 */
410 static VOID
411 LdrAdjustDllName (PUNICODE_STRING FullDllName,
412 PUNICODE_STRING DllName,
413 BOOLEAN BaseName)
414 {
415 WCHAR Buffer[MAX_PATH];
416 ULONG Length;
417 PWCHAR Extension;
418 PWCHAR Pointer;
419
420 Length = DllName->Length / sizeof(WCHAR);
421
422 if (BaseName)
423 {
424 /* get the base dll name */
425 Pointer = DllName->Buffer + Length;
426 Extension = Pointer;
427
428 do
429 {
430 --Pointer;
431 }
432 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
433
434 Pointer++;
435 Length = Extension - Pointer;
436 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
437 Buffer[Length] = L'\0';
438 }
439 else
440 {
441 /* get the full dll name */
442 memmove (Buffer, DllName->Buffer, DllName->Length);
443 Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
444 }
445
446 /* Build the DLL's absolute name */
447 Extension = wcsrchr (Buffer, L'.');
448 if ((Extension != NULL) && (*Extension == L'.'))
449 {
450 /* with extension - remove dot if it's the last character */
451 if (Buffer[Length - 1] == L'.')
452 Length--;
453 Buffer[Length] = 0;
454 }
455 else
456 {
457 /* name without extension - assume that it is .dll */
458 memmove (Buffer + Length, L".dll", 10);
459 }
460
461 RtlCreateUnicodeString(FullDllName, Buffer);
462 }
463
464 PLDR_DATA_TABLE_ENTRY
465 LdrAddModuleEntry(PVOID ImageBase,
466 PIMAGE_NT_HEADERS NTHeaders,
467 PWSTR FullDosName)
468 {
469 PLDR_DATA_TABLE_ENTRY Module;
470
471 Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY));
472 ASSERT(Module);
473 memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY));
474 Module->DllBase = (PVOID)ImageBase;
475 Module->EntryPoint = (PVOID)(ULONG_PTR)NTHeaders->OptionalHeader.AddressOfEntryPoint;
476 if (Module->EntryPoint != 0)
477 Module->EntryPoint = (PVOID)((ULONG_PTR)Module->EntryPoint + (ULONG_PTR)Module->DllBase);
478 Module->SizeOfImage = LdrpGetResidentSize(NTHeaders);
479 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
480 {
481 /* loading while app is running */
482 Module->LoadCount = 1;
483 } else {
484 /*
485 * loading while app is initializing
486 * dll must not be unloaded
487 */
488 Module->LoadCount = 0xFFFF;
489 }
490
491 Module->Flags = 0;
492 Module->TlsIndex = -1;
493 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
494 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
495
496 RtlCreateUnicodeString (&Module->FullDllName,
497 FullDosName);
498 RtlCreateUnicodeString (&Module->BaseDllName,
499 wcsrchr(FullDosName, L'\\') + 1);
500 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
501
502 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
503 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
504 &Module->InLoadOrderLinks);
505 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
506
507 return(Module);
508 }
509
510
511 static NTSTATUS
512 LdrpMapKnownDll(IN PUNICODE_STRING DllName,
513 OUT PUNICODE_STRING FullDosName,
514 OUT PHANDLE SectionHandle)
515 {
516 OBJECT_ATTRIBUTES ObjectAttributes;
517 NTSTATUS Status;
518
519 DPRINT("LdrpMapKnownDll() called\n");
520
521 if (LdrpKnownDllsDirHandle == NULL)
522 {
523 DPRINT("Invalid 'KnownDlls' directory\n");
524 return STATUS_UNSUCCESSFUL;
525 }
526
527 DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath);
528
529 InitializeObjectAttributes(&ObjectAttributes,
530 DllName,
531 OBJ_CASE_INSENSITIVE,
532 LdrpKnownDllsDirHandle,
533 NULL);
534 Status = NtOpenSection(SectionHandle,
535 SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
536 &ObjectAttributes);
537 if (!NT_SUCCESS(Status))
538 {
539 DPRINT("NtOpenSection() failed for '%wZ' (Status 0x%08lx)\n", DllName, Status);
540 return Status;
541 }
542
543 FullDosName->Length = LdrpKnownDllPath.Length + DllName->Length + sizeof(WCHAR);
544 FullDosName->MaximumLength = FullDosName->Length + sizeof(WCHAR);
545 FullDosName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
546 0,
547 FullDosName->MaximumLength);
548 if (FullDosName->Buffer == NULL)
549 {
550 FullDosName->Length = 0;
551 FullDosName->MaximumLength = 0;
552 return STATUS_SUCCESS;
553 }
554
555 wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer);
556 wcscat(FullDosName->Buffer, L"\\");
557 wcscat(FullDosName->Buffer, DllName->Buffer);
558
559 DPRINT("FullDosName '%wZ'\n", FullDosName);
560
561 DPRINT("LdrpMapKnownDll() done\n");
562
563 return STATUS_SUCCESS;
564 }
565
566
567 static NTSTATUS
568 LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
569 IN PUNICODE_STRING DllName,
570 OUT PUNICODE_STRING FullDosName,
571 IN BOOLEAN MapAsDataFile,
572 OUT PHANDLE SectionHandle)
573 {
574 WCHAR SearchPathBuffer[MAX_PATH];
575 WCHAR DosName[MAX_PATH];
576 UNICODE_STRING FullNtFileName;
577 OBJECT_ATTRIBUTES FileObjectAttributes;
578 HANDLE FileHandle;
579 char BlockBuffer [1024];
580 PIMAGE_DOS_HEADER DosHeader;
581 PIMAGE_NT_HEADERS NTHeaders;
582 IO_STATUS_BLOCK IoStatusBlock;
583 NTSTATUS Status;
584 ULONG len;
585
586 DPRINT("LdrpMapDllImageFile() called\n");
587
588 if (SearchPath == NULL)
589 {
590 /* get application running path */
591
592 wcscpy (SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer);
593
594 len = wcslen (SearchPathBuffer);
595
596 while (len && SearchPathBuffer[len - 1] != L'\\')
597 len--;
598
599 if (len) SearchPathBuffer[len-1] = L'\0';
600
601 wcscat (SearchPathBuffer, L";");
602
603 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
604 wcscat (SearchPathBuffer, L"\\system32;");
605 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
606 wcscat (SearchPathBuffer, L";.");
607
608 SearchPath = SearchPathBuffer;
609 }
610
611 if (RtlDosSearchPath_U (SearchPath,
612 DllName->Buffer,
613 NULL,
614 MAX_PATH,
615 DosName,
616 NULL) == 0)
617 return STATUS_DLL_NOT_FOUND;
618
619 if (!RtlDosPathNameToNtPathName_U (DosName,
620 &FullNtFileName,
621 NULL,
622 NULL))
623 return STATUS_DLL_NOT_FOUND;
624
625 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
626
627 InitializeObjectAttributes(&FileObjectAttributes,
628 &FullNtFileName,
629 0,
630 NULL,
631 NULL);
632
633 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
634
635 Status = NtOpenFile(&FileHandle,
636 GENERIC_READ|SYNCHRONIZE,
637 &FileObjectAttributes,
638 &IoStatusBlock,
639 FILE_SHARE_READ,
640 FILE_SYNCHRONOUS_IO_NONALERT);
641 if (!NT_SUCCESS(Status))
642 {
643 DPRINT1("Dll open of %wZ failed: Status = 0x%08lx\n",
644 &FullNtFileName, Status);
645 RtlFreeHeap (RtlGetProcessHeap (),
646 0,
647 FullNtFileName.Buffer);
648 return Status;
649 }
650 RtlFreeHeap (RtlGetProcessHeap (),
651 0,
652 FullNtFileName.Buffer);
653
654 if (!MapAsDataFile)
655 {
656
657 Status = NtReadFile(FileHandle,
658 NULL,
659 NULL,
660 NULL,
661 &IoStatusBlock,
662 BlockBuffer,
663 sizeof(BlockBuffer),
664 NULL,
665 NULL);
666 if (!NT_SUCCESS(Status))
667 {
668 DPRINT("Dll header read failed: Status = 0x%08lx\n", Status);
669 NtClose(FileHandle);
670 return Status;
671 }
672
673 /*
674 * Overlay DOS and NT headers structures to the
675 * buffer with DLL's header raw data.
676 */
677 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
678 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
679 /*
680 * Check it is a PE image file.
681 */
682 if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
683 || (DosHeader->e_lfanew == 0L)
684 || (*(PULONG)(NTHeaders) != IMAGE_NT_SIGNATURE))
685 {
686 DPRINT("NTDLL format invalid\n");
687 NtClose(FileHandle);
688
689 return STATUS_UNSUCCESSFUL;
690 }
691 }
692
693 /*
694 * Create a section for dll.
695 */
696 Status = NtCreateSection(SectionHandle,
697 SECTION_ALL_ACCESS,
698 NULL,
699 NULL,
700 PAGE_READONLY,
701 MapAsDataFile ? SEC_COMMIT : SEC_IMAGE,
702 FileHandle);
703 NtClose(FileHandle);
704
705 if (!NT_SUCCESS(Status))
706 {
707 DPRINT("NTDLL create section failed: Status = 0x%08lx\n", Status);
708 return Status;
709 }
710
711 RtlCreateUnicodeString(FullDosName,
712 DosName);
713
714 return Status;
715 }
716
717
718
719 /***************************************************************************
720 * NAME EXPORTED
721 * LdrLoadDll
722 *
723 * DESCRIPTION
724 *
725 * ARGUMENTS
726 *
727 * RETURN VALUE
728 *
729 * REVISIONS
730 *
731 * NOTE
732 *
733 * @implemented
734 */
735 NTSTATUS NTAPI
736 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
737 IN PULONG LoadFlags OPTIONAL,
738 IN PUNICODE_STRING Name,
739 OUT PVOID *BaseAddress /* also known as HMODULE*, and PHANDLE 'DllHandle' */)
740 {
741 NTSTATUS Status;
742 PLDR_DATA_TABLE_ENTRY Module;
743
744 PPEB Peb = NtCurrentPeb();
745
746 TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
747 Name,
748 SearchPath ? L" from " : L"",
749 SearchPath ? SearchPath : L"");
750
751 Status = LdrpLoadModule(SearchPath, LoadFlags ? *LoadFlags : 0, Name, &Module, BaseAddress);
752
753 if (NT_SUCCESS(Status) &&
754 (!LoadFlags || 0 == (*LoadFlags & LOAD_LIBRARY_AS_DATAFILE)))
755 {
756 if (!(Module->Flags & LDRP_PROCESS_ATTACH_CALLED))
757 {
758 RtlEnterCriticalSection(Peb->LoaderLock);
759 Status = LdrpAttachProcess();
760 RtlLeaveCriticalSection(Peb->LoaderLock);
761 }
762 }
763
764 if ((!Module) && (NT_SUCCESS(Status)))
765 return Status;
766
767 *BaseAddress = NT_SUCCESS(Status) ? Module->DllBase : NULL;
768
769 return Status;
770 }
771
772
773 /***************************************************************************
774 * NAME EXPORTED
775 * LdrFindEntryForAddress
776 *
777 * DESCRIPTION
778 *
779 * ARGUMENTS
780 *
781 * RETURN VALUE
782 *
783 * REVISIONS
784 *
785 * NOTE
786 *
787 * @implemented
788 */
789 NTSTATUS NTAPI
790 LdrFindEntryForAddress(PVOID Address,
791 PLDR_DATA_TABLE_ENTRY *Module)
792 {
793 PLIST_ENTRY ModuleListHead;
794 PLIST_ENTRY Entry;
795 PLDR_DATA_TABLE_ENTRY ModulePtr;
796
797 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
798
799 if (NtCurrentPeb()->Ldr == NULL)
800 return(STATUS_NO_MORE_ENTRIES);
801
802 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
803 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
804 Entry = ModuleListHead->Flink;
805 if (Entry == ModuleListHead)
806 {
807 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
808 return(STATUS_NO_MORE_ENTRIES);
809 }
810
811 while (Entry != ModuleListHead)
812 {
813 ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
814
815 DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->DllBase);
816
817 if ((Address >= ModulePtr->DllBase) &&
818 ((ULONG_PTR)Address <= ((ULONG_PTR)ModulePtr->DllBase + ModulePtr->SizeOfImage)))
819 {
820 *Module = ModulePtr;
821 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
822 return(STATUS_SUCCESS);
823 }
824
825 Entry = Entry->Flink;
826 }
827
828 DPRINT("Failed to find module entry.\n");
829
830 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
831 return(STATUS_NO_MORE_ENTRIES);
832 }
833
834
835 /***************************************************************************
836 * NAME LOCAL
837 * LdrFindEntryForName
838 *
839 * DESCRIPTION
840 *
841 * ARGUMENTS
842 *
843 * RETURN VALUE
844 *
845 * REVISIONS
846 *
847 * NOTE
848 *
849 */
850 static NTSTATUS
851 LdrFindEntryForName(PUNICODE_STRING Name,
852 PLDR_DATA_TABLE_ENTRY *Module,
853 BOOLEAN Ref)
854 {
855 PLIST_ENTRY ModuleListHead;
856 PLIST_ENTRY Entry;
857 PLDR_DATA_TABLE_ENTRY ModulePtr;
858 BOOLEAN ContainsPath;
859 UNICODE_STRING AdjustedName;
860 unsigned i;
861
862 DPRINT("LdrFindEntryForName(Name %wZ)\n", Name);
863
864 if (NtCurrentPeb()->Ldr == NULL)
865 return(STATUS_NO_MORE_ENTRIES);
866
867 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
868 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
869 Entry = ModuleListHead->Flink;
870 if (Entry == ModuleListHead)
871 {
872 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
873 return(STATUS_NO_MORE_ENTRIES);
874 }
875
876 // NULL is the current process
877 if (Name == NULL)
878 {
879 *Module = ExeModule;
880 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
881 return(STATUS_SUCCESS);
882 }
883
884 LdrAdjustDllName (&AdjustedName, Name, FALSE);
885
886 ContainsPath = (AdjustedName.Length >= 2 * sizeof(WCHAR) && L':' == AdjustedName.Buffer[1]);
887 for (i = 0; ! ContainsPath && i < AdjustedName.Length / sizeof(WCHAR); i++)
888 {
889 ContainsPath = L'\\' == AdjustedName.Buffer[i] ||
890 L'/' == AdjustedName.Buffer[i];
891 }
892
893 if (LdrpLastModule)
894 {
895 if ((! ContainsPath &&
896 0 == RtlCompareUnicodeString(&LdrpLastModule->BaseDllName, &AdjustedName, TRUE)) ||
897 (ContainsPath &&
898 0 == RtlCompareUnicodeString(&LdrpLastModule->FullDllName, &AdjustedName, TRUE)))
899 {
900 *Module = LdrpLastModule;
901 if (Ref && (*Module)->LoadCount != 0xFFFF)
902 {
903 (*Module)->LoadCount++;
904 }
905 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
906 RtlFreeUnicodeString(&AdjustedName);
907 return(STATUS_SUCCESS);
908 }
909 }
910 while (Entry != ModuleListHead)
911 {
912 ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
913
914 DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, &AdjustedName);
915
916 if ((! ContainsPath &&
917 0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, &AdjustedName, TRUE)) ||
918 (ContainsPath &&
919 0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, &AdjustedName, TRUE)))
920 {
921 *Module = LdrpLastModule = ModulePtr;
922 if (Ref && ModulePtr->LoadCount != 0xFFFF)
923 {
924 ModulePtr->LoadCount++;
925 }
926 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
927 RtlFreeUnicodeString(&AdjustedName);
928 return(STATUS_SUCCESS);
929 }
930
931 Entry = Entry->Flink;
932 }
933
934 DPRINT("Failed to find dll %wZ\n", Name);
935 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
936 RtlFreeUnicodeString(&AdjustedName);
937 return(STATUS_NO_MORE_ENTRIES);
938 }
939
940 /**********************************************************************
941 * NAME LOCAL
942 * LdrFixupForward
943 *
944 * DESCRIPTION
945 *
946 * ARGUMENTS
947 *
948 * RETURN VALUE
949 *
950 * REVISIONS
951 *
952 * NOTE
953 *
954 */
955 static PVOID
956 LdrFixupForward(PCHAR ForwardName)
957 {
958 CHAR NameBuffer[128];
959 UNICODE_STRING DllName;
960 NTSTATUS Status;
961 PCHAR p;
962 PLDR_DATA_TABLE_ENTRY Module;
963 PVOID BaseAddress;
964
965 strcpy(NameBuffer, ForwardName);
966 p = strchr(NameBuffer, '.');
967 if (p != NULL)
968 {
969 *p = 0;
970
971 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
972 RtlCreateUnicodeStringFromAsciiz (&DllName,
973 NameBuffer);
974
975 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
976 /* FIXME:
977 * The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
978 */
979 if (!NT_SUCCESS(Status))
980 {
981 ULONG Flags = LDRP_PROCESS_CREATION_TIME;
982 Status = LdrLoadDll(NULL,
983 &Flags,
984 &DllName,
985 &BaseAddress);
986 if (NT_SUCCESS(Status))
987 {
988 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
989 }
990 }
991 RtlFreeUnicodeString (&DllName);
992 if (!NT_SUCCESS(Status))
993 {
994 DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer);
995 return NULL;
996 }
997
998 DPRINT("BaseAddress: %p\n", Module->DllBase);
999
1000 return LdrGetExportByName(Module->DllBase, (PUCHAR)(p+1), -1);
1001 }
1002
1003 return NULL;
1004 }
1005
1006
1007 /**********************************************************************
1008 * NAME LOCAL
1009 * LdrGetExportByOrdinal
1010 *
1011 * DESCRIPTION
1012 *
1013 * ARGUMENTS
1014 *
1015 * RETURN VALUE
1016 *
1017 * REVISIONS
1018 *
1019 * NOTE
1020 *
1021 */
1022 static PVOID
1023 LdrGetExportByOrdinal (
1024 PVOID BaseAddress,
1025 ULONG Ordinal
1026 )
1027 {
1028 PIMAGE_EXPORT_DIRECTORY ExportDir;
1029 ULONG ExportDirSize;
1030 PDWORD * ExFunctions;
1031 PVOID Function;
1032
1033 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1034 RtlImageDirectoryEntryToData (BaseAddress,
1035 TRUE,
1036 IMAGE_DIRECTORY_ENTRY_EXPORT,
1037 &ExportDirSize);
1038
1039
1040 ExFunctions = (PDWORD *)
1041 RVA(
1042 BaseAddress,
1043 ExportDir->AddressOfFunctions
1044 );
1045 DPRINT(
1046 "LdrGetExportByOrdinal(Ordinal %lu) = %p\n",
1047 Ordinal,
1048 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1049 );
1050
1051 Function = (0 != ExFunctions[Ordinal - ExportDir->Base]
1052 ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
1053 : NULL);
1054
1055 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1056 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1057 {
1058 DPRINT("Forward: %s\n", (PCHAR)Function);
1059 Function = LdrFixupForward((PCHAR)Function);
1060 }
1061
1062 return Function;
1063 }
1064
1065
1066 /**********************************************************************
1067 * NAME LOCAL
1068 * LdrGetExportByName
1069 *
1070 * DESCRIPTION
1071 *
1072 * ARGUMENTS
1073 *
1074 * RETURN VALUE
1075 *
1076 * REVISIONS
1077 *
1078 * NOTE
1079 * AddressOfNames and AddressOfNameOrdinals are paralell tables,
1080 * both with NumberOfNames entries.
1081 *
1082 */
1083 static PVOID
1084 LdrGetExportByName(PVOID BaseAddress,
1085 PUCHAR SymbolName,
1086 WORD Hint)
1087 {
1088 PIMAGE_EXPORT_DIRECTORY ExportDir;
1089 PDWORD * ExFunctions;
1090 PDWORD * ExNames;
1091 USHORT * ExOrdinals;
1092 PVOID ExName;
1093 ULONG Ordinal;
1094 PVOID Function;
1095 LONG minn, maxn;
1096 ULONG ExportDirSize;
1097
1098 DPRINT("LdrGetExportByName %p %s %hu\n", BaseAddress, SymbolName, Hint);
1099
1100 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1101 RtlImageDirectoryEntryToData(BaseAddress,
1102 TRUE,
1103 IMAGE_DIRECTORY_ENTRY_EXPORT,
1104 &ExportDirSize);
1105 if (ExportDir == NULL)
1106 {
1107 DPRINT1("LdrGetExportByName(): no export directory, "
1108 "can't lookup %s/%hu!\n", SymbolName, Hint);
1109 return NULL;
1110 }
1111
1112
1113 //The symbol names may be missing entirely
1114 if (ExportDir->AddressOfNames == 0)
1115 {
1116 DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
1117 return NULL;
1118 }
1119
1120 /*
1121 * Get header pointers
1122 */
1123 ExNames = (PDWORD *)RVA(BaseAddress,
1124 ExportDir->AddressOfNames);
1125 ExOrdinals = (USHORT *)RVA(BaseAddress,
1126 ExportDir->AddressOfNameOrdinals);
1127 ExFunctions = (PDWORD *)RVA(BaseAddress,
1128 ExportDir->AddressOfFunctions);
1129
1130 /*
1131 * Check the hint first
1132 */
1133 if (Hint < ExportDir->NumberOfNames)
1134 {
1135 ExName = RVA(BaseAddress, ExNames[Hint]);
1136 if (strcmp(ExName, (PCHAR)SymbolName) == 0)
1137 {
1138 Ordinal = ExOrdinals[Hint];
1139 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1140 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1141 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1142 {
1143 DPRINT("Forward: %s\n", (PCHAR)Function);
1144 Function = LdrFixupForward((PCHAR)Function);
1145 if (Function == NULL)
1146 {
1147 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
1148 }
1149 return Function;
1150 }
1151 if (Function != NULL)
1152 return Function;
1153 }
1154 }
1155
1156 /*
1157 * Binary search
1158 */
1159 minn = 0;
1160 maxn = ExportDir->NumberOfNames - 1;
1161 while (minn <= maxn)
1162 {
1163 LONG mid;
1164 LONG res;
1165
1166 mid = (minn + maxn) / 2;
1167
1168 ExName = RVA(BaseAddress, ExNames[mid]);
1169 res = strcmp(ExName, (PCHAR)SymbolName);
1170 if (res == 0)
1171 {
1172 Ordinal = ExOrdinals[mid];
1173 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
1174 if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
1175 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
1176 {
1177 DPRINT("Forward: %s\n", (PCHAR)Function);
1178 Function = LdrFixupForward((PCHAR)Function);
1179 if (Function == NULL)
1180 {
1181 DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
1182 }
1183 return Function;
1184 }
1185 if (Function != NULL)
1186 return Function;
1187 }
1188 else if (minn == maxn)
1189 {
1190 DPRINT("LdrGetExportByName(): binary search failed\n");
1191 break;
1192 }
1193 else if (res > 0)
1194 {
1195 maxn = mid - 1;
1196 }
1197 else
1198 {
1199 minn = mid + 1;
1200 }
1201 }
1202
1203 DPRINT("LdrGetExportByName(): failed to find %s\n",SymbolName);
1204 return (PVOID)NULL;
1205 }
1206
1207
1208 /**********************************************************************
1209 * NAME LOCAL
1210 * LdrPerformRelocations
1211 *
1212 * DESCRIPTION
1213 * Relocate a DLL's memory image.
1214 *
1215 * ARGUMENTS
1216 *
1217 * RETURN VALUE
1218 *
1219 * REVISIONS
1220 *
1221 * NOTE
1222 *
1223 */
1224 static NTSTATUS
1225 LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
1226 PVOID ImageBase)
1227 {
1228 PIMAGE_DATA_DIRECTORY RelocationDDir;
1229 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
1230 ULONG Count, OldProtect, OldProtect2;
1231 SIZE_T ProtectSize;
1232 PVOID Page, ProtectPage, ProtectPage2;
1233 PUSHORT TypeOffset;
1234 ULONG_PTR Delta;
1235 NTSTATUS Status;
1236
1237 if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1238 {
1239 return STATUS_SUCCESS;
1240 }
1241
1242 RelocationDDir =
1243 &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1244
1245 if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
1246 {
1247 return STATUS_SUCCESS;
1248 }
1249
1250 ProtectSize = PAGE_SIZE;
1251 Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
1252 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1253 RelocationDDir->VirtualAddress);
1254 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
1255 RelocationDDir->VirtualAddress + RelocationDDir->Size);
1256
1257 while (RelocationDir < RelocationEnd &&
1258 RelocationDir->SizeOfBlock > 0)
1259 {
1260 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
1261 sizeof(USHORT);
1262 Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
1263 TypeOffset = (PUSHORT)(RelocationDir + 1);
1264
1265 /* Unprotect the page(s) we're about to relocate. */
1266 ProtectPage = Page;
1267 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1268 &ProtectPage,
1269 &ProtectSize,
1270 PAGE_READWRITE,
1271 &OldProtect);
1272 if (!NT_SUCCESS(Status))
1273 {
1274 DPRINT1("Failed to unprotect relocation target.\n");
1275 return Status;
1276 }
1277
1278 if (RelocationDir->VirtualAddress + PAGE_SIZE <
1279 NTHeaders->OptionalHeader.SizeOfImage)
1280 {
1281 ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
1282 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1283 &ProtectPage2,
1284 &ProtectSize,
1285 PAGE_READWRITE,
1286 &OldProtect2);
1287 if (!NT_SUCCESS(Status))
1288 {
1289 DPRINT1("Failed to unprotect relocation target (2).\n");
1290 NtProtectVirtualMemory(NtCurrentProcess(),
1291 &ProtectPage,
1292 &ProtectSize,
1293 OldProtect,
1294 &OldProtect);
1295 return Status;
1296 }
1297 }
1298 else
1299 {
1300 ProtectPage2 = NULL;
1301 }
1302
1303 RelocationDir = LdrProcessRelocationBlock((ULONG_PTR)Page,
1304 Count,
1305 TypeOffset,
1306 Delta);
1307 if (RelocationDir == NULL)
1308 return STATUS_UNSUCCESSFUL;
1309
1310 /* Restore old page protection. */
1311 NtProtectVirtualMemory(NtCurrentProcess(),
1312 &ProtectPage,
1313 &ProtectSize,
1314 OldProtect,
1315 &OldProtect);
1316
1317 if (ProtectPage2 != NULL)
1318 {
1319 NtProtectVirtualMemory(NtCurrentProcess(),
1320 &ProtectPage2,
1321 &ProtectSize,
1322 OldProtect2,
1323 &OldProtect2);
1324 }
1325 }
1326
1327 return STATUS_SUCCESS;
1328 }
1329
1330 static NTSTATUS
1331 LdrpGetOrLoadModule(PWCHAR SearchPath,
1332 PCHAR Name,
1333 PLDR_DATA_TABLE_ENTRY* Module,
1334 BOOLEAN Load)
1335 {
1336 ANSI_STRING AnsiDllName;
1337 UNICODE_STRING DllName;
1338 NTSTATUS Status;
1339
1340 DPRINT("LdrpGetOrLoadModule() called for %s\n", Name);
1341
1342 RtlInitAnsiString(&AnsiDllName, Name);
1343 Status = RtlAnsiStringToUnicodeString(&DllName, &AnsiDllName, TRUE);
1344 if (!NT_SUCCESS(Status))
1345 {
1346 return Status;
1347 }
1348
1349 Status = LdrFindEntryForName (&DllName, Module, Load);
1350 if (Load && !NT_SUCCESS(Status))
1351 {
1352 Status = LdrpLoadModule(SearchPath,
1353 NtCurrentPeb()->Ldr->Initialized ? 0 : LDRP_PROCESS_CREATION_TIME,
1354 &DllName,
1355 Module,
1356 NULL);
1357 if (NT_SUCCESS(Status))
1358 {
1359 Status = LdrFindEntryForName (&DllName, Module, FALSE);
1360 }
1361 if (!NT_SUCCESS(Status))
1362 {
1363 ULONG ErrorResponse;
1364 ULONG_PTR ErrorParameter = (ULONG_PTR)&DllName;
1365
1366 DPRINT1("failed to load %wZ\n", &DllName);
1367 NtRaiseHardError(STATUS_DLL_NOT_FOUND,
1368 1,
1369 1,
1370 &ErrorParameter,
1371 OptionOk,
1372 &ErrorResponse);
1373 }
1374 }
1375 RtlFreeUnicodeString (&DllName);
1376 return Status;
1377 }
1378
1379 void
1380 RtlpRaiseImportNotFound(CHAR *FuncName, ULONG Ordinal, PUNICODE_STRING DllName)
1381 {
1382 ULONG ErrorResponse;
1383 ULONG_PTR ErrorParameters[2];
1384 ANSI_STRING ProcNameAnsi;
1385 UNICODE_STRING ProcName;
1386 CHAR Buffer[8];
1387
1388 if (!FuncName)
1389 {
1390 _snprintf(Buffer, 8, "# %ld", Ordinal);
1391 FuncName = Buffer;
1392 }
1393
1394 RtlInitAnsiString(&ProcNameAnsi, FuncName);
1395 RtlAnsiStringToUnicodeString(&ProcName, &ProcNameAnsi, TRUE);
1396 ErrorParameters[0] = (ULONG_PTR)&ProcName;
1397 ErrorParameters[1] = (ULONG_PTR)DllName;
1398 NtRaiseHardError(STATUS_ENTRYPOINT_NOT_FOUND,
1399 2,
1400 3,
1401 ErrorParameters,
1402 OptionOk,
1403 &ErrorResponse);
1404 RtlFreeUnicodeString(&ProcName);
1405 }
1406
1407 static NTSTATUS
1408 LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
1409 PLDR_DATA_TABLE_ENTRY ImportedModule,
1410 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
1411 {
1412 NTSTATUS Status;
1413 PVOID* ImportAddressList;
1414 PULONG FunctionNameList;
1415 PVOID IATBase;
1416 ULONG OldProtect;
1417 ULONG Ordinal;
1418 SIZE_T IATSize;
1419
1420 if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
1421 {
1422 return STATUS_UNSUCCESSFUL;
1423 }
1424
1425 /* Get the import address list. */
1426 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1427
1428 /* Get the list of functions to import. */
1429 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1430 {
1431 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1432 }
1433 else
1434 {
1435 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1436 }
1437
1438 /* Get the size of IAT. */
1439 IATSize = 0;
1440 while (FunctionNameList[IATSize] != 0L)
1441 {
1442 IATSize++;
1443 }
1444
1445 /* Unprotect the region we are about to write into. */
1446 IATBase = (PVOID)ImportAddressList;
1447 IATSize *= sizeof(PVOID*);
1448 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1449 &IATBase,
1450 &IATSize,
1451 PAGE_READWRITE,
1452 &OldProtect);
1453 if (!NT_SUCCESS(Status))
1454 {
1455 DPRINT1("Failed to unprotect IAT.\n");
1456 return(Status);
1457 }
1458
1459 /* Walk through function list and fixup addresses. */
1460 while (*FunctionNameList != 0L)
1461 {
1462 if ((*FunctionNameList) & 0x80000000)
1463 {
1464 Ordinal = (*FunctionNameList) & 0x7fffffff;
1465 *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
1466 if ((*ImportAddressList) == NULL)
1467 {
1468 DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
1469 RtlpRaiseImportNotFound(NULL, Ordinal, &ImportedModule->FullDllName);
1470 return STATUS_ENTRYPOINT_NOT_FOUND;
1471 }
1472 }
1473 else
1474 {
1475 IMAGE_IMPORT_BY_NAME *pe_name;
1476 pe_name = RVA(Module->DllBase, *FunctionNameList);
1477 *ImportAddressList = LdrGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
1478 if ((*ImportAddressList) == NULL)
1479 {
1480 DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
1481 RtlpRaiseImportNotFound((CHAR*)pe_name->Name, 0, &ImportedModule->FullDllName);
1482 return STATUS_ENTRYPOINT_NOT_FOUND;
1483 }
1484 }
1485 ImportAddressList++;
1486 FunctionNameList++;
1487 }
1488
1489 /* Protect the region we are about to write into. */
1490 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1491 &IATBase,
1492 &IATSize,
1493 OldProtect,
1494 &OldProtect);
1495 if (!NT_SUCCESS(Status))
1496 {
1497 DPRINT1("Failed to protect IAT.\n");
1498 return(Status);
1499 }
1500
1501 return STATUS_SUCCESS;
1502 }
1503
1504 static NTSTATUS
1505 LdrpProcessImportDirectory(
1506 PLDR_DATA_TABLE_ENTRY Module,
1507 PLDR_DATA_TABLE_ENTRY ImportedModule,
1508 PCHAR ImportedName)
1509 {
1510 NTSTATUS Status;
1511 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1512 PCHAR Name;
1513 ULONG Size;
1514
1515 DPRINT("LdrpProcessImportDirectory(%p '%wZ', '%s')\n",
1516 Module, &Module->BaseDllName, ImportedName);
1517
1518
1519 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1520 RtlImageDirectoryEntryToData(Module->DllBase,
1521 TRUE,
1522 IMAGE_DIRECTORY_ENTRY_IMPORT,
1523 &Size);
1524 if (ImportModuleDirectory == NULL)
1525 {
1526 return STATUS_UNSUCCESSFUL;
1527 }
1528
1529 while (ImportModuleDirectory->Name)
1530 {
1531 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1532 if (0 == _stricmp(Name, ImportedName))
1533 {
1534 Status = LdrpProcessImportDirectoryEntry(Module,
1535 ImportedModule,
1536 ImportModuleDirectory);
1537 if (!NT_SUCCESS(Status))
1538 {
1539 return Status;
1540 }
1541 }
1542 ImportModuleDirectory++;
1543 }
1544
1545
1546 return STATUS_SUCCESS;
1547 }
1548
1549
1550 static NTSTATUS
1551 LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
1552 PLDR_DATA_TABLE_ENTRY ImportedModule,
1553 PCHAR ImportedName)
1554 {
1555 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1556 NTSTATUS Status;
1557 PVOID* ImportAddressList;
1558 PVOID Start;
1559 PVOID End;
1560 PULONG FunctionNameList;
1561 PVOID IATBase;
1562 ULONG OldProtect;
1563 ULONG Offset;
1564 SIZE_T IATSize;
1565 PIMAGE_NT_HEADERS NTHeaders;
1566 PCHAR Name;
1567 ULONG Size;
1568
1569 DPRINT("LdrpAdjustImportDirectory(Module %p '%wZ', %p '%wZ', '%s')\n",
1570 Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
1571
1572 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1573 RtlImageDirectoryEntryToData(Module->DllBase,
1574 TRUE,
1575 IMAGE_DIRECTORY_ENTRY_IMPORT,
1576 &Size);
1577 if (ImportModuleDirectory == NULL)
1578 {
1579 return STATUS_UNSUCCESSFUL;
1580 }
1581
1582 while (ImportModuleDirectory->Name)
1583 {
1584 Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
1585 if (0 == _stricmp(Name, (PCHAR)ImportedName))
1586 {
1587
1588 /* Get the import address list. */
1589 ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1590
1591 /* Get the list of functions to import. */
1592 if (ImportModuleDirectory->OriginalFirstThunk != 0)
1593 {
1594 FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
1595 }
1596 else
1597 {
1598 FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
1599 }
1600
1601 /* Get the size of IAT. */
1602 IATSize = 0;
1603 while (FunctionNameList[IATSize] != 0L)
1604 {
1605 IATSize++;
1606 }
1607
1608 /* Unprotect the region we are about to write into. */
1609 IATBase = (PVOID)ImportAddressList;
1610 IATSize *= sizeof(PVOID*);
1611 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1612 &IATBase,
1613 &IATSize,
1614 PAGE_READWRITE,
1615 &OldProtect);
1616 if (!NT_SUCCESS(Status))
1617 {
1618 DPRINT1("Failed to unprotect IAT.\n");
1619 return(Status);
1620 }
1621
1622 NTHeaders = RtlImageNtHeader (ImportedModule->DllBase);
1623 Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
1624 End = (PVOID)((ULONG_PTR)Start + ImportedModule->SizeOfImage);
1625 Offset = (ULONG)((ULONG_PTR)ImportedModule->DllBase - (ULONG_PTR)Start);
1626
1627 /* Walk through function list and fixup addresses. */
1628 while (*FunctionNameList != 0L)
1629 {
1630 if (*ImportAddressList >= Start && *ImportAddressList < End)
1631 {
1632 (*ImportAddressList) = (PVOID)((ULONG_PTR)(*ImportAddressList) + Offset);
1633 }
1634 ImportAddressList++;
1635 FunctionNameList++;
1636 }
1637
1638 /* Protect the region we are about to write into. */
1639 Status = NtProtectVirtualMemory(NtCurrentProcess(),
1640 &IATBase,
1641 &IATSize,
1642 OldProtect,
1643 &OldProtect);
1644 if (!NT_SUCCESS(Status))
1645 {
1646 DPRINT1("Failed to protect IAT.\n");
1647 return(Status);
1648 }
1649 }
1650 ImportModuleDirectory++;
1651 }
1652 return STATUS_SUCCESS;
1653 }
1654
1655
1656 /**********************************************************************
1657 * NAME LOCAL
1658 * LdrFixupImports
1659 *
1660 * DESCRIPTION
1661 * Compute the entry point for every symbol the DLL imports
1662 * from other modules.
1663 *
1664 * ARGUMENTS
1665 *
1666 * RETURN VALUE
1667 *
1668 * REVISIONS
1669 *
1670 * NOTE
1671 *
1672 */
1673 static NTSTATUS
1674 LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
1675 IN PLDR_DATA_TABLE_ENTRY Module)
1676 {
1677 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
1678 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent;
1679 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
1680 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
1681 PIMAGE_TLS_DIRECTORY TlsDirectory;
1682 ULONG TlsSize = 0;
1683 NTSTATUS Status;
1684 PLDR_DATA_TABLE_ENTRY ImportedModule;
1685 PCHAR ImportedName;
1686 ULONG Size;
1687
1688 DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
1689
1690 /* Check for tls data */
1691 TlsDirectory = (PIMAGE_TLS_DIRECTORY)
1692 RtlImageDirectoryEntryToData(Module->DllBase,
1693 TRUE,
1694 IMAGE_DIRECTORY_ENTRY_TLS,
1695 &Size);
1696 if (TlsDirectory)
1697 {
1698 TlsSize = TlsDirectory->EndAddressOfRawData
1699 - TlsDirectory->StartAddressOfRawData
1700 + TlsDirectory->SizeOfZeroFill;
1701
1702 if (TlsSize > 0 && NtCurrentPeb()->Ldr->Initialized)
1703 {
1704 TRACE_LDR("Trying to dynamically load %wZ which contains a TLS directory\n",
1705 &Module->BaseDllName);
1706 TlsDirectory = NULL;
1707 }
1708 }
1709
1710 /*
1711 * Process each import module.
1712 */
1713 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
1714 RtlImageDirectoryEntryToData(Module->DllBase,
1715 TRUE,
1716 IMAGE_DIRECTORY_ENTRY_IMPORT,
1717 &Size);
1718
1719 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
1720 RtlImageDirectoryEntryToData(Module->DllBase,
1721 TRUE,
1722 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
1723 &Size);
1724
1725 if (BoundImportDescriptor != NULL && ImportModuleDirectory == NULL)
1726 {
1727 DPRINT1("%wZ has only a bound import directory\n", &Module->BaseDllName);
1728 return STATUS_UNSUCCESSFUL;
1729 }
1730 if (BoundImportDescriptor)
1731 {
1732 DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor);
1733
1734 BoundImportDescriptorCurrent = BoundImportDescriptor;
1735 while (BoundImportDescriptorCurrent->OffsetModuleName)
1736 {
1737 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
1738 TRACE_LDR("%wZ bound to %s\n", &Module->BaseDllName, ImportedName);
1739 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
1740 if (!NT_SUCCESS(Status))
1741 {
1742 DPRINT1("failed to load %s\n", ImportedName);
1743 return Status;
1744 }
1745 if (Module == ImportedModule)
1746 {
1747 LdrpDecrementLoadCount(Module, FALSE);
1748 }
1749 if (ImportedModule->TimeDateStamp != BoundImportDescriptorCurrent->TimeDateStamp)
1750 {
1751 TRACE_LDR("%wZ has stale binding to %wZ\n",
1752 &Module->BaseDllName, &ImportedModule->BaseDllName);
1753 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1754 if (!NT_SUCCESS(Status))
1755 {
1756 DPRINT1("failed to import %s\n", ImportedName);
1757 return Status;
1758 }
1759 }
1760 else
1761 {
1762 BOOLEAN WrongForwarder;
1763 WrongForwarder = FALSE;
1764 if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1765 {
1766 TRACE_LDR("%wZ has stale binding to %s\n",
1767 &Module->BaseDllName, ImportedName);
1768 }
1769 else
1770 {
1771 TRACE_LDR("%wZ has correct binding to %wZ\n",
1772 &Module->BaseDllName, &ImportedModule->BaseDllName);
1773 }
1774 if (BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs)
1775 {
1776 PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef;
1777 ULONG i;
1778 PLDR_DATA_TABLE_ENTRY ForwarderModule;
1779 PCHAR ForwarderName;
1780
1781 BoundForwarderRef = (PIMAGE_BOUND_FORWARDER_REF)(BoundImportDescriptorCurrent + 1);
1782 for (i = 0; i < BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs; i++, BoundForwarderRef++)
1783 {
1784 ForwarderName = (PCHAR)BoundImportDescriptor + BoundForwarderRef->OffsetModuleName;
1785 TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
1786 &Module->BaseDllName, ForwarderName, ImportedName);
1787 Status = LdrpGetOrLoadModule(SearchPath, ForwarderName, &ForwarderModule, TRUE);
1788 if (!NT_SUCCESS(Status))
1789 {
1790 DPRINT1("failed to load %s\n", ForwarderName);
1791 return Status;
1792 }
1793 if (Module == ImportedModule)
1794 {
1795 LdrpDecrementLoadCount(Module, FALSE);
1796 }
1797 if (ForwarderModule->TimeDateStamp != BoundForwarderRef->TimeDateStamp ||
1798 ForwarderModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1799 {
1800 TRACE_LDR("%wZ has stale binding to %s\n",
1801 &Module->BaseDllName, ForwarderName);
1802 WrongForwarder = TRUE;
1803 }
1804 else
1805 {
1806 TRACE_LDR("%wZ has correct binding to %s\n",
1807 &Module->BaseDllName, ForwarderName);
1808 }
1809 }
1810 }
1811 if (WrongForwarder ||
1812 ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1813 {
1814 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1815 if (!NT_SUCCESS(Status))
1816 {
1817 DPRINT1("failed to import %s\n", ImportedName);
1818 return Status;
1819 }
1820 }
1821 else if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
1822 {
1823 TRACE_LDR("Adjust imports for %s from %wZ\n",
1824 ImportedName, &Module->BaseDllName);
1825 Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName);
1826 if (!NT_SUCCESS(Status))
1827 {
1828 DPRINT1("failed to adjust import entries for %s\n", ImportedName);
1829 return Status;
1830 }
1831 }
1832 else if (WrongForwarder)
1833 {
1834 /*
1835 * FIXME:
1836 * Update only forwarders
1837 */
1838 TRACE_LDR("Stale BIND %s from %wZ\n",
1839 ImportedName, &Module->BaseDllName);
1840 Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
1841 if (!NT_SUCCESS(Status))
1842 {
1843 DPRINT1("faild to import %s\n", ImportedName);
1844 return Status;
1845 }
1846 }
1847 else
1848 {
1849 /* nothing to do */
1850 }
1851 }
1852 BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1;
1853 }
1854 }
1855 else if (ImportModuleDirectory)
1856 {
1857 DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory);
1858
1859 ImportModuleDirectoryCurrent = ImportModuleDirectory;
1860 while (ImportModuleDirectoryCurrent->Name)
1861 {
1862 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
1863 TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName);
1864
1865 Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
1866 if (!NT_SUCCESS(Status))
1867 {
1868 DPRINT1("failed to load %s\n", ImportedName);
1869 return Status;
1870 }
1871 if (Module == ImportedModule)
1872 {
1873 LdrpDecrementLoadCount(Module, FALSE);
1874 }
1875
1876 TRACE_LDR("Initializing imports for %wZ from %s\n",
1877 &Module->BaseDllName, ImportedName);
1878 Status = LdrpProcessImportDirectoryEntry(Module, ImportedModule, ImportModuleDirectoryCurrent);
1879 if (!NT_SUCCESS(Status))
1880 {
1881 DPRINT1("failed to import %s\n", ImportedName);
1882 return Status;
1883 }
1884 ImportModuleDirectoryCurrent++;
1885 }
1886 }
1887
1888 if (TlsDirectory && TlsSize > 0)
1889 {
1890 LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
1891 }
1892
1893 return STATUS_SUCCESS;
1894 }
1895
1896
1897 /**********************************************************************
1898 * NAME
1899 * LdrPEStartup
1900 *
1901 * DESCRIPTION
1902 * 1. Relocate, if needed the EXE.
1903 * 2. Fixup any imported symbol.
1904 * 3. Compute the EXE's entry point.
1905 *
1906 * ARGUMENTS
1907 * ImageBase
1908 * Address at which the EXE's image
1909 * is loaded.
1910 *
1911 * SectionHandle
1912 * Handle of the section that contains
1913 * the EXE's image.
1914 *
1915 * RETURN VALUE
1916 * NULL on error; otherwise the entry point
1917 * to call for initializing the DLL.
1918 *
1919 * REVISIONS
1920 *
1921 * NOTE
1922 * 04.01.2004 hb Previous this function was used for all images (dll + exe).
1923 * Currently the function is only used for the exe.
1924 */
1925 PEPFUNC LdrPEStartup (PVOID ImageBase,
1926 HANDLE SectionHandle,
1927 PLDR_DATA_TABLE_ENTRY* Module,
1928 PWSTR FullDosName)
1929 {
1930 NTSTATUS Status;
1931 PEPFUNC EntryPoint = NULL;
1932 PIMAGE_DOS_HEADER DosHeader;
1933 PIMAGE_NT_HEADERS NTHeaders;
1934 PLDR_DATA_TABLE_ENTRY tmpModule;
1935
1936 DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
1937 ImageBase, SectionHandle);
1938
1939 /*
1940 * Overlay DOS and WNT headers structures
1941 * to the DLL's image.
1942 */
1943 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1944 NTHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR)ImageBase + DosHeader->e_lfanew);
1945
1946 /*
1947 * If the base address is different from the
1948 * one the DLL is actually loaded, perform any
1949 * relocation.
1950 */
1951 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1952 {
1953 DPRINT("LDR: Performing relocations\n");
1954 Status = LdrPerformRelocations(NTHeaders, ImageBase);
1955 if (!NT_SUCCESS(Status))
1956 {
1957 DPRINT1("LdrPerformRelocations() failed\n");
1958 return NULL;
1959 }
1960 }
1961
1962 if (Module != NULL)
1963 {
1964 *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
1965 (*Module)->SectionPointer = SectionHandle;
1966 }
1967 else
1968 {
1969 Module = &tmpModule;
1970 Status = LdrFindEntryForAddress(ImageBase, Module);
1971 if (!NT_SUCCESS(Status))
1972 {
1973 return NULL;
1974 }
1975 }
1976
1977 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1978 {
1979 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
1980 }
1981
1982 /*
1983 * If the DLL's imports symbols from other
1984 * modules, fixup the imported calls entry points.
1985 */
1986 DPRINT("About to fixup imports\n");
1987 Status = LdrFixupImports(NULL, *Module);
1988 if (!NT_SUCCESS(Status))
1989 {
1990 DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName);
1991 return NULL;
1992 }
1993 DPRINT("Fixup done\n");
1994 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
1995 Status = LdrpInitializeTlsForProccess();
1996 if (NT_SUCCESS(Status))
1997 {
1998 Status = LdrpAttachProcess();
1999 }
2000 if (NT_SUCCESS(Status))
2001 {
2002 LdrpTlsCallback(*Module, DLL_PROCESS_ATTACH);
2003 }
2004
2005
2006 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
2007 if (!NT_SUCCESS(Status))
2008 {
2009 return NULL;
2010 }
2011
2012 /*
2013 * Compute the DLL's entry point's address.
2014 */
2015 DPRINT("ImageBase = %p\n", ImageBase);
2016 DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
2017 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
2018 {
2019 EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase
2020 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
2021 }
2022 DPRINT("LdrPEStartup() = %p\n",EntryPoint);
2023 return EntryPoint;
2024 }
2025
2026 static NTSTATUS
2027 LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
2028 IN ULONG LoadFlags,
2029 IN PUNICODE_STRING Name,
2030 PLDR_DATA_TABLE_ENTRY *Module,
2031 PVOID *BaseAddress OPTIONAL)
2032 {
2033 UNICODE_STRING AdjustedName;
2034 UNICODE_STRING FullDosName;
2035 NTSTATUS Status;
2036 PLDR_DATA_TABLE_ENTRY tmpModule;
2037 HANDLE SectionHandle;
2038 SIZE_T ViewSize;
2039 PVOID ImageBase;
2040 PIMAGE_NT_HEADERS NtHeaders;
2041 BOOLEAN MappedAsDataFile;
2042 PVOID ArbitraryUserPointer;
2043
2044 if (Module == NULL)
2045 {
2046 Module = &tmpModule;
2047 }
2048 /* adjust the full dll name */
2049 LdrAdjustDllName(&AdjustedName, Name, FALSE);
2050
2051 DPRINT("%wZ\n", &AdjustedName);
2052
2053 MappedAsDataFile = FALSE;
2054 /* Test if dll is already loaded */
2055 Status = LdrFindEntryForName(&AdjustedName, Module, TRUE);
2056 if (NT_SUCCESS(Status))
2057 {
2058 RtlFreeUnicodeString(&AdjustedName);
2059 if (NULL != BaseAddress)
2060 {
2061 *BaseAddress = (*Module)->DllBase;
2062 }
2063 }
2064 else
2065 {
2066 /* Open or create dll image section */
2067 Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle);
2068 if (!NT_SUCCESS(Status))
2069 {
2070 MappedAsDataFile = (0 != (LoadFlags & LOAD_LIBRARY_AS_DATAFILE));
2071 Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName,
2072 MappedAsDataFile, &SectionHandle);
2073 }
2074 if (!NT_SUCCESS(Status))
2075 {
2076 DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName, Status);
2077 RtlFreeUnicodeString(&AdjustedName);
2078 return Status;
2079 }
2080 RtlFreeUnicodeString(&AdjustedName);
2081 /* Map the dll into the process */
2082 ViewSize = 0;
2083 ImageBase = 0;
2084 ArbitraryUserPointer = NtCurrentTeb()->Tib.ArbitraryUserPointer;
2085 NtCurrentTeb()->Tib.ArbitraryUserPointer = FullDosName.Buffer;
2086 Status = NtMapViewOfSection(SectionHandle,
2087 NtCurrentProcess(),
2088 &ImageBase,
2089 0,
2090 0,
2091 NULL,
2092 &ViewSize,
2093 ViewShare,
2094 0,
2095 PAGE_READONLY);
2096 NtCurrentTeb()->Tib.ArbitraryUserPointer = ArbitraryUserPointer;
2097 if (!NT_SUCCESS(Status))
2098 {
2099 DPRINT1("map view of section failed (Status 0x%08lx)\n", Status);
2100 RtlFreeUnicodeString(&FullDosName);
2101 NtClose(SectionHandle);
2102 return(Status);
2103 }
2104 if (NULL != BaseAddress)
2105 {
2106 *BaseAddress = ImageBase;
2107 }
2108 if (!MappedAsDataFile)
2109 {
2110 /* Get and check the NT headers */
2111 NtHeaders = RtlImageNtHeader(ImageBase);
2112 if (NtHeaders == NULL)
2113 {
2114 DPRINT1("RtlImageNtHeaders() failed\n");
2115 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2116 NtClose (SectionHandle);
2117 RtlFreeUnicodeString(&FullDosName);
2118 return STATUS_UNSUCCESSFUL;
2119 }
2120 }
2121 DPRINT("Mapped %wZ at %x\n", &FullDosName, ImageBase);
2122 if (MappedAsDataFile)
2123 {
2124 ASSERT(NULL != BaseAddress);
2125 if (NULL != BaseAddress)
2126 {
2127 *BaseAddress = (PVOID) ((char *) *BaseAddress + 1);
2128 }
2129 *Module = NULL;
2130 RtlFreeUnicodeString(&FullDosName);
2131 NtClose(SectionHandle);
2132 return STATUS_SUCCESS;
2133 }
2134 /* If the base address is different from the
2135 * one the DLL is actually loaded, perform any
2136 * relocation. */
2137 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2138 {
2139 DPRINT1("Relocating (%lx -> %p) %wZ\n",
2140 NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
2141 Status = LdrPerformRelocations(NtHeaders, ImageBase);
2142 if (!NT_SUCCESS(Status))
2143 {
2144 DPRINT1("LdrPerformRelocations() failed\n");
2145 NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
2146 NtClose (SectionHandle);
2147 RtlFreeUnicodeString(&FullDosName);
2148 return STATUS_UNSUCCESSFUL;
2149 }
2150 }
2151 *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer);
2152 (*Module)->SectionPointer = SectionHandle;
2153 if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
2154 {
2155 (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
2156 }
2157 if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
2158 {
2159 (*Module)->Flags |= LDRP_IMAGE_DLL;
2160 }
2161 /* fixup the imported calls entry points */
2162 Status = LdrFixupImports(SearchPath, *Module);
2163 if (!NT_SUCCESS(Status))
2164 {
2165 DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
2166 return Status;
2167 }
2168 #if defined(DBG) || defined(KDBG)
2169 LdrpLoadUserModuleSymbols(*Module);
2170 #endif /* DBG || KDBG */
2171 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2172 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
2173 &(*Module)->InInitializationOrderModuleList);
2174 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2175 }
2176 return STATUS_SUCCESS;
2177 }
2178
2179 static NTSTATUS
2180 LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
2181 BOOLEAN Unload)
2182 {
2183 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
2184 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
2185 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
2186 PCHAR ImportedName;
2187 PLDR_DATA_TABLE_ENTRY ImportedModule;
2188 NTSTATUS Status;
2189 LONG LoadCount;
2190 ULONG Size;
2191
2192 if (Unload)
2193 {
2194 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
2195 }
2196
2197 LoadCount = LdrpDecrementLoadCount(Module, Unload);
2198
2199 TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
2200
2201 if (LoadCount == 0)
2202 {
2203 /* ?????????????????? */
2204 }
2205 else if (!(Module->Flags & LDRP_STATIC_LINK) && LoadCount == 1)
2206 {
2207 BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
2208 RtlImageDirectoryEntryToData(Module->DllBase,
2209 TRUE,
2210 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
2211 &Size);
2212 if (BoundImportDescriptor)
2213 {
2214 /* dereferencing all imported modules, use the bound import descriptor */
2215 BoundImportDescriptorCurrent = BoundImportDescriptor;
2216 while (BoundImportDescriptorCurrent->OffsetModuleName)
2217 {
2218 ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
2219 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2220 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2221 if (!NT_SUCCESS(Status))
2222 {
2223 DPRINT1("unable to found imported modul %s\n", ImportedName);
2224 }
2225 else
2226 {
2227 if (Module != ImportedModule)
2228 {
2229 Status = LdrpUnloadModule(ImportedModule, FALSE);
2230 if (!NT_SUCCESS(Status))
2231 {
2232 DPRINT1("unable to unload %s\n", ImportedName);
2233 }
2234 }
2235 }
2236 BoundImportDescriptorCurrent++;
2237 }
2238 }
2239 else
2240 {
2241 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
2242 RtlImageDirectoryEntryToData(Module->DllBase,
2243 TRUE,
2244 IMAGE_DIRECTORY_ENTRY_IMPORT,
2245 &Size);
2246 if (ImportModuleDirectory)
2247 {
2248 /* dereferencing all imported modules, use the import descriptor */
2249 while (ImportModuleDirectory->Name)
2250 {
2251 ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
2252 TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
2253 Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
2254 if (!NT_SUCCESS(Status))
2255 {
2256 DPRINT1("unable to found imported modul %s\n", ImportedName);
2257 }
2258 else
2259 {
2260 if (Module != ImportedModule)
2261 {
2262 Status = LdrpUnloadModule(ImportedModule, FALSE);
2263 if (!NT_SUCCESS(Status))
2264 {
2265 DPRINT1("unable to unload %s\n", ImportedName);
2266 }
2267 }
2268 }
2269 ImportModuleDirectory++;
2270 }
2271 }
2272 }
2273 }
2274
2275 if (Unload)
2276 {
2277 if (!(Module->Flags & LDRP_STATIC_LINK))
2278 {
2279 LdrpDetachProcess(FALSE);
2280 }
2281
2282 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2283 }
2284 return STATUS_SUCCESS;
2285
2286 }
2287
2288 /*
2289 * @implemented
2290 */
2291 NTSTATUS NTAPI
2292 LdrUnloadDll (IN PVOID BaseAddress)
2293 {
2294 PLDR_DATA_TABLE_ENTRY Module;
2295 NTSTATUS Status;
2296
2297 if (BaseAddress == NULL)
2298 return STATUS_SUCCESS;
2299
2300 if (LdrMappedAsDataFile(&BaseAddress))
2301 {
2302 Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
2303 }
2304 else
2305 {
2306 Status = LdrFindEntryForAddress(BaseAddress, &Module);
2307 if (NT_SUCCESS(Status))
2308 {
2309 TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
2310 Status = LdrpUnloadModule(Module, TRUE);
2311 }
2312 }
2313
2314 return Status;
2315 }
2316
2317 /*
2318 * @implemented
2319 */
2320 NTSTATUS NTAPI
2321 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
2322 {
2323 PLIST_ENTRY ModuleListHead;
2324 PLIST_ENTRY Entry;
2325 PLDR_DATA_TABLE_ENTRY Module;
2326 NTSTATUS Status;
2327
2328 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
2329
2330 Status = STATUS_DLL_NOT_FOUND;
2331 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2332 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2333 Entry = ModuleListHead->Flink;
2334 while (Entry != ModuleListHead)
2335 {
2336 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2337
2338 DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module->BaseDllName, Module->DllBase);
2339
2340 if (Module->DllBase == BaseAddress)
2341 {
2342 if (Module->TlsIndex == 0xFFFF)
2343 {
2344 Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
2345 Status = STATUS_SUCCESS;
2346 }
2347 break;
2348 }
2349 Entry = Entry->Flink;
2350 }
2351 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2352 return Status;
2353 }
2354
2355 /*
2356 * @implemented
2357 */
2358 NTSTATUS NTAPI
2359 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
2360 IN PULONG DllCharacteristics,
2361 IN PUNICODE_STRING DllName,
2362 OUT PVOID *DllHandle)
2363 {
2364 PLDR_DATA_TABLE_ENTRY Module;
2365 NTSTATUS Status;
2366
2367 TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
2368 DllName, DllPath ? DllPath : L"");
2369
2370 /* NULL is the current executable */
2371 if (DllName == NULL)
2372 {
2373 *DllHandle = ExeModule->DllBase;
2374 DPRINT("BaseAddress 0x%lx\n", *DllHandle);
2375 return STATUS_SUCCESS;
2376 }
2377
2378 Status = LdrFindEntryForName(DllName, &Module, FALSE);
2379 if (NT_SUCCESS(Status))
2380 {
2381 *DllHandle = Module->DllBase;
2382 return STATUS_SUCCESS;
2383 }
2384
2385 DPRINT("Failed to find dll %wZ\n", DllName);
2386 *DllHandle = NULL;
2387 return STATUS_DLL_NOT_FOUND;
2388 }
2389
2390 /*
2391 * @implemented
2392 */
2393 NTSTATUS NTAPI
2394 LdrAddRefDll(IN ULONG Flags,
2395 IN PVOID BaseAddress)
2396 {
2397 PLIST_ENTRY ModuleListHead;
2398 PLIST_ENTRY Entry;
2399 PLDR_DATA_TABLE_ENTRY Module;
2400 NTSTATUS Status;
2401
2402 if (Flags & ~(LDR_PIN_MODULE))
2403 {
2404 return STATUS_INVALID_PARAMETER;
2405 }
2406
2407 Status = STATUS_DLL_NOT_FOUND;
2408 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2409 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2410 Entry = ModuleListHead->Flink;
2411 while (Entry != ModuleListHead)
2412 {
2413 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2414
2415 if (Module->DllBase == BaseAddress)
2416 {
2417 if (Flags & LDR_PIN_MODULE)
2418 {
2419 Module->Flags |= LDRP_STATIC_LINK;
2420 }
2421 else
2422 {
2423 LdrpIncrementLoadCount(Module,
2424 FALSE);
2425 }
2426 Status = STATUS_SUCCESS;
2427 break;
2428 }
2429 Entry = Entry->Flink;
2430 }
2431 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2432 return Status;
2433 }
2434
2435 /*
2436 * @implemented
2437 */
2438 PVOID NTAPI
2439 RtlPcToFileHeader(IN PVOID PcValue,
2440 PVOID* BaseOfImage)
2441 {
2442 PLIST_ENTRY ModuleListHead;
2443 PLIST_ENTRY Entry;
2444 PLDR_DATA_TABLE_ENTRY Module;
2445 PVOID ImageBase = NULL;
2446
2447 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2448 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2449 Entry = ModuleListHead->Flink;
2450 while (Entry != ModuleListHead)
2451 {
2452 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2453
2454 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
2455 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
2456 {
2457 ImageBase = Module->DllBase;
2458 break;
2459 }
2460 Entry = Entry->Flink;
2461 }
2462 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2463
2464 *BaseOfImage = ImageBase;
2465 return ImageBase;
2466 }
2467
2468 /*
2469 * @implemented
2470 */
2471 NTSTATUS NTAPI
2472 LdrGetProcedureAddress (IN PVOID BaseAddress,
2473 IN PANSI_STRING Name,
2474 IN ULONG Ordinal,
2475 OUT PVOID *ProcedureAddress)
2476 {
2477 if (Name && Name->Length)
2478 {
2479 TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
2480 }
2481 else
2482 {
2483 TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
2484 }
2485
2486 DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
2487 BaseAddress, Name, Ordinal, ProcedureAddress);
2488
2489 if (Name && Name->Length)
2490 {
2491 /* by name */
2492 *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
2493 if (*ProcedureAddress != NULL)
2494 {
2495 return STATUS_SUCCESS;
2496 }
2497 DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
2498 }
2499 else
2500 {
2501 /* by ordinal */
2502 Ordinal &= 0x0000FFFF;
2503 *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
2504 if (*ProcedureAddress)
2505 {
2506 return STATUS_SUCCESS;
2507 }
2508 DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal);
2509 }
2510 return STATUS_PROCEDURE_NOT_FOUND;
2511 }
2512
2513 /**********************************************************************
2514 * NAME LOCAL
2515 * LdrpDetachProcess
2516 *
2517 * DESCRIPTION
2518 * Unload dll's which are no longer referenced from others dll's
2519 *
2520 * ARGUMENTS
2521 * none
2522 *
2523 * RETURN VALUE
2524 * none
2525 *
2526 * REVISIONS
2527 *
2528 * NOTE
2529 * The loader lock must be held on enty.
2530 */
2531 static VOID
2532 LdrpDetachProcess(BOOLEAN UnloadAll)
2533 {
2534 PLIST_ENTRY ModuleListHead;
2535 PLIST_ENTRY Entry;
2536 PLDR_DATA_TABLE_ENTRY Module;
2537 static ULONG CallingCount = 0;
2538
2539 DPRINT("LdrpDetachProcess() called for %wZ\n",
2540 &ExeModule->BaseDllName);
2541
2542 if (UnloadAll)
2543 LdrpDllShutdownInProgress = TRUE;
2544
2545 CallingCount++;
2546
2547 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2548 Entry = ModuleListHead->Blink;
2549 while (Entry != ModuleListHead)
2550 {
2551 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2552 if (((UnloadAll && Module->LoadCount == 0xFFFF) || Module->LoadCount == 0) &&
2553 Module->Flags & LDRP_ENTRY_PROCESSED &&
2554 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2555 {
2556 Module->Flags |= LDRP_UNLOAD_IN_PROGRESS;
2557 if (Module == LdrpLastModule)
2558 {
2559 LdrpLastModule = NULL;
2560 }
2561 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED)
2562 {
2563 TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
2564 &Module->BaseDllName, Module->EntryPoint);
2565 LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(INT_PTR)(Module->LoadCount == 0xFFFF ? 1 : 0));
2566 }
2567 else
2568 {
2569 TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
2570 }
2571 Entry = ModuleListHead->Blink;
2572 }
2573 else
2574 {
2575 Entry = Entry->Blink;
2576 }
2577 }
2578
2579 if (CallingCount == 1)
2580 {
2581 Entry = ModuleListHead->Blink;
2582 while (Entry != ModuleListHead)
2583 {
2584 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2585 Entry = Entry->Blink;
2586 if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
2587 ((UnloadAll && Module->LoadCount != 0xFFFF) || Module->LoadCount == 0))
2588 {
2589 /* remove the module entry from the list */
2590 RemoveEntryList (&Module->InLoadOrderLinks);
2591 RemoveEntryList (&Module->InInitializationOrderModuleList);
2592
2593 NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase);
2594 NtClose (Module->SectionPointer);
2595
2596 TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
2597
2598 RtlFreeUnicodeString (&Module->FullDllName);
2599 RtlFreeUnicodeString (&Module->BaseDllName);
2600
2601 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
2602 }
2603 }
2604 }
2605 CallingCount--;
2606 DPRINT("LdrpDetachProcess() done\n");
2607 }
2608
2609 /**********************************************************************
2610 * NAME LOCAL
2611 * LdrpAttachProcess
2612 *
2613 * DESCRIPTION
2614 * Initialize all dll's which are prepered for loading
2615 *
2616 * ARGUMENTS
2617 * none
2618 *
2619 * RETURN VALUE
2620 * status
2621 *
2622 * REVISIONS
2623 *
2624 * NOTE
2625 * The loader lock must be held on entry.
2626 *
2627 */
2628 static NTSTATUS
2629 LdrpAttachProcess(VOID)
2630 {
2631 PLIST_ENTRY ModuleListHead;
2632 PLIST_ENTRY Entry;
2633 PLDR_DATA_TABLE_ENTRY Module;
2634 BOOLEAN Result;
2635 NTSTATUS Status = STATUS_SUCCESS;
2636
2637 DPRINT("LdrpAttachProcess() called for %wZ\n",
2638 &ExeModule->BaseDllName);
2639
2640 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2641 Entry = ModuleListHead->Flink;
2642 while (Entry != ModuleListHead)
2643 {
2644 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2645 if (!(Module->Flags & (LDRP_LOAD_IN_PROGRESS|LDRP_UNLOAD_IN_PROGRESS|LDRP_ENTRY_PROCESSED)))
2646 {
2647 Module->Flags |= LDRP_LOAD_IN_PROGRESS;
2648 TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
2649 &Module->BaseDllName, Module->EntryPoint);
2650 Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(INT_PTR)(Module->LoadCount == 0xFFFF ? 1 : 0));
2651 if (!Result)
2652 {
2653 Status = STATUS_DLL_INIT_FAILED;
2654 break;
2655 }
2656 if (Module->Flags & LDRP_IMAGE_DLL && Module->EntryPoint != 0)
2657 {
2658 Module->Flags |= LDRP_PROCESS_ATTACH_CALLED|LDRP_ENTRY_PROCESSED;
2659 }
2660 else
2661 {
2662 Module->Flags |= LDRP_ENTRY_PROCESSED;
2663 }
2664 Module->Flags &= ~LDRP_LOAD_IN_PROGRESS;
2665 }
2666 Entry = Entry->Flink;
2667 }
2668
2669 DPRINT("LdrpAttachProcess() done\n");
2670
2671 return Status;
2672 }
2673
2674 /*
2675 * @implemented
2676 */
2677 BOOLEAN NTAPI
2678 RtlDllShutdownInProgress (VOID)
2679 {
2680 return LdrpDllShutdownInProgress;
2681 }
2682
2683 /*
2684 * @implemented
2685 */
2686 NTSTATUS NTAPI
2687 LdrShutdownProcess (VOID)
2688 {
2689 LdrpDetachProcess(TRUE);
2690 return STATUS_SUCCESS;
2691 }
2692
2693 /*
2694 * @implemented
2695 */
2696
2697 NTSTATUS
2698 LdrpAttachThread (VOID)
2699 {
2700 PLIST_ENTRY ModuleListHead;
2701 PLIST_ENTRY Entry;
2702 PLDR_DATA_TABLE_ENTRY Module;
2703 NTSTATUS Status;
2704
2705 DPRINT("LdrpAttachThread() called for %wZ\n",
2706 &ExeModule->BaseDllName);
2707
2708 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2709
2710 Status = LdrpInitializeTlsForThread();
2711
2712 if (NT_SUCCESS(Status))
2713 {
2714 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2715 Entry = ModuleListHead->Flink;
2716
2717 while (Entry != ModuleListHead)
2718 {
2719 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2720 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2721 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2722 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2723 {
2724 TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
2725 &Module->BaseDllName, Module->EntryPoint);
2726 LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);
2727 }
2728 Entry = Entry->Flink;
2729 }
2730
2731 Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
2732 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2733 LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
2734 }
2735
2736 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2737
2738 DPRINT("LdrpAttachThread() done\n");
2739
2740 return Status;
2741 }
2742
2743
2744 /*
2745 * @implemented
2746 */
2747 NTSTATUS NTAPI
2748 LdrShutdownThread (VOID)
2749 {
2750 PLIST_ENTRY ModuleListHead;
2751 PLIST_ENTRY Entry;
2752 PLDR_DATA_TABLE_ENTRY Module;
2753
2754 DPRINT("LdrShutdownThread() called for %wZ\n",
2755 &ExeModule->BaseDllName);
2756
2757 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2758
2759 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
2760 Entry = ModuleListHead->Blink;
2761 while (Entry != ModuleListHead)
2762 {
2763 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
2764
2765 if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
2766 !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
2767 !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
2768 {
2769 TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
2770 &Module->BaseDllName, Module->EntryPoint);
2771 LdrpCallDllEntry(Module, DLL_THREAD_DETACH, NULL);
2772 }
2773 Entry = Entry->Blink;
2774 }
2775
2776 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2777
2778 if (LdrpTlsArray)
2779 {
2780 RtlFreeHeap (RtlGetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer);
2781 }
2782
2783 DPRINT("LdrShutdownThread() done\n");
2784
2785 return STATUS_SUCCESS;
2786 }
2787
2788
2789 /***************************************************************************
2790 * NAME EXPORTED
2791 * LdrQueryProcessModuleInformation
2792 *
2793 * DESCRIPTION
2794 *
2795 * ARGUMENTS
2796 *
2797 * RETURN VALUE
2798 *
2799 * REVISIONS
2800 *
2801 * NOTE
2802 *
2803 * @implemented
2804 */
2805 NTSTATUS NTAPI
2806 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
2807 IN ULONG Size OPTIONAL,
2808 OUT PULONG ReturnedSize)
2809 {
2810 PLIST_ENTRY ModuleListHead;
2811 PLIST_ENTRY Entry;
2812 PLDR_DATA_TABLE_ENTRY Module;
2813 PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
2814 NTSTATUS Status = STATUS_SUCCESS;
2815 ULONG UsedSize = sizeof(ULONG);
2816 ANSI_STRING AnsiString;
2817 PCHAR p;
2818
2819 DPRINT("LdrQueryProcessModuleInformation() called\n");
2820 // FIXME: This code is ultra-duplicated. see lib\rtl\dbgbuffer.c
2821 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
2822
2823 if (ModuleInformation == NULL || Size == 0)
2824 {
2825 Status = STATUS_INFO_LENGTH_MISMATCH;
2826 }
2827 else
2828 {
2829 ModuleInformation->NumberOfModules = 0;
2830 ModulePtr = &ModuleInformation->Modules[0];
2831 Status = STATUS_SUCCESS;
2832 }
2833
2834 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
2835 Entry = ModuleListHead->Flink;
2836
2837 while (Entry != ModuleListHead)
2838 {
2839 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2840
2841 DPRINT(" Module %wZ\n",
2842 &Module->FullDllName);
2843
2844 if (UsedSize > Size)
2845 {
2846 Status = STATUS_INFO_LENGTH_MISMATCH;
2847 }
2848 else if (ModuleInformation != NULL)
2849 {
2850 ModulePtr->Section = 0;
2851 ModulePtr->MappedBase = NULL; // FIXME: ??
2852 ModulePtr->ImageBase = Module->DllBase;
2853 ModulePtr->ImageSize = Module->SizeOfImage;
2854 ModulePtr->Flags = Module->Flags;
2855 ModulePtr->LoadOrderIndex = 0; // FIXME: ??
2856 ModulePtr->InitOrderIndex = 0; // FIXME: ??
2857 ModulePtr->LoadCount = Module->LoadCount;
2858
2859 AnsiString.Length = 0;
2860 AnsiString.MaximumLength = 256;
2861 AnsiString.Buffer = ModulePtr->FullPathName;
2862 RtlUnicodeStringToAnsiString(&AnsiString,
2863 &Module->FullDllName,
2864 FALSE);
2865
2866 p = strrchr(ModulePtr->FullPathName, '\\');
2867 if (p != NULL)
2868 ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
2869 else
2870 ModulePtr->OffsetToFileName = 0;
2871
2872 ModulePtr++;
2873 ModuleInformation->NumberOfModules++;
2874 }
2875 UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
2876
2877 Entry = Entry->Flink;
2878 }
2879
2880 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
2881
2882 if (ReturnedSize != 0)
2883 *ReturnedSize = UsedSize;
2884
2885 DPRINT("LdrQueryProcessModuleInformation() done\n");
2886
2887 return(Status);
2888 }
2889
2890
2891 static BOOLEAN
2892 LdrpCheckImageChecksum (IN PVOID BaseAddress,
2893 IN ULONG ImageSize)
2894 {
2895 PIMAGE_NT_HEADERS Header;
2896 PUSHORT Ptr;
2897 ULONG Sum;
2898 ULONG CalcSum;
2899 ULONG HeaderSum;
2900 ULONG i;
2901
2902 Header = RtlImageNtHeader (BaseAddress);
2903 if (Header == NULL)
2904 return FALSE;
2905
2906 HeaderSum = Header->OptionalHeader.CheckSum;
2907 if (HeaderSum == 0)
2908 return TRUE;
2909
2910 Sum = 0;
2911 Ptr = (PUSHORT) BaseAddress;
2912 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
2913 {
2914 Sum += (ULONG)*Ptr;
2915 if (HIWORD(Sum) != 0)
2916 {
2917 Sum = LOWORD(Sum) + HIWORD(Sum);
2918 }
2919 Ptr++;
2920 }
2921
2922 if (ImageSize & 1)
2923 {
2924 Sum += (ULONG)*((PUCHAR)Ptr);
2925 if (HIWORD(Sum) != 0)
2926 {
2927 Sum = LOWORD(Sum) + HIWORD(Sum);
2928 }
2929 }
2930
2931 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
2932
2933 /* Subtract image checksum from calculated checksum. */
2934 /* fix low word of checksum */
2935 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
2936 {
2937 CalcSum -= LOWORD(HeaderSum);
2938 }
2939 else
2940 {
2941 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
2942 }
2943
2944 /* fix high word of checksum */
2945 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
2946 {
2947 CalcSum -= HIWORD(HeaderSum);
2948 }
2949 else
2950 {
2951 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
2952 }
2953
2954 /* add file length */
2955 CalcSum += ImageSize;
2956
2957 return (BOOLEAN)(CalcSum == HeaderSum);
2958 }
2959
2960 /*
2961 * Compute size of an image as it is actually present in virt memory
2962 * (i.e. excluding NEVER_LOAD sections)
2963 */
2964 ULONG
2965 LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders)
2966 {
2967 PIMAGE_SECTION_HEADER SectionHeader;
2968 unsigned SectionIndex;
2969 ULONG ResidentSize;
2970
2971 SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader
2972 + NTHeaders->FileHeader.SizeOfOptionalHeader);
2973 ResidentSize = 0;
2974 for (SectionIndex = 0; SectionIndex < NTHeaders->FileHeader.NumberOfSections; SectionIndex++)
2975 {
2976 if (0 == (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE)
2977 && ResidentSize < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)
2978 {
2979 ResidentSize = SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize;
2980 }
2981 SectionHeader++;
2982 }
2983
2984 return ResidentSize;
2985 }
2986
2987
2988 /***************************************************************************
2989 * NAME EXPORTED
2990 * LdrVerifyImageMatchesChecksum
2991 *
2992 * DESCRIPTION
2993 *
2994 * ARGUMENTS
2995 *
2996 * RETURN VALUE
2997 *
2998 * REVISIONS
2999 *
3000 * NOTE
3001 *
3002 * @implemented
3003 */
3004 NTSTATUS NTAPI
3005 LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
3006 ULONG Unknown1,
3007 ULONG Unknown2,
3008 ULONG Unknown3)
3009 {
3010 FILE_STANDARD_INFORMATION FileInfo;
3011 IO_STATUS_BLOCK IoStatusBlock;
3012 HANDLE SectionHandle;
3013 SIZE_T ViewSize;
3014 PVOID BaseAddress;
3015 BOOLEAN Result;
3016 NTSTATUS Status;
3017
3018 DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
3019
3020 Status = NtCreateSection (&SectionHandle,
3021 SECTION_MAP_READ,
3022 NULL,
3023 NULL,
3024 PAGE_READONLY,
3025 SEC_COMMIT,
3026 FileHandle);
3027 if (!NT_SUCCESS(Status))
3028 {
3029 DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
3030 return Status;
3031 }
3032
3033 ViewSize = 0;
3034 BaseAddress = NULL;
3035 Status = NtMapViewOfSection (SectionHandle,
3036 NtCurrentProcess (),
3037 &BaseAddress,
3038 0,
3039 0,
3040 NULL,
3041 &ViewSize,
3042 ViewShare,
3043 0,
3044 PAGE_READONLY);
3045 if (!NT_SUCCESS(Status))
3046 {
3047 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3048 NtClose (SectionHandle);
3049 return Status;
3050 }
3051
3052 Status = NtQueryInformationFile (FileHandle,
3053 &IoStatusBlock,
3054 &FileInfo,
3055 sizeof (FILE_STANDARD_INFORMATION),
3056 FileStandardInformation);
3057 if (!NT_SUCCESS(Status))
3058 {
3059 DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
3060 NtUnmapViewOfSection (NtCurrentProcess (),
3061 BaseAddress);
3062 NtClose (SectionHandle);
3063 return Status;
3064 }
3065
3066 Result = LdrpCheckImageChecksum (BaseAddress,
3067 FileInfo.EndOfFile.u.LowPart);
3068 if (Result == FALSE)
3069 {
3070 Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
3071 }
3072
3073 NtUnmapViewOfSection (NtCurrentProcess (),
3074 BaseAddress);
3075
3076 NtClose (SectionHandle);
3077
3078 return Status;
3079 }
3080
3081
3082 /***************************************************************************
3083 * NAME EXPORTED
3084 * LdrQueryImageFileExecutionOptions
3085 *
3086 * DESCRIPTION
3087 *
3088 * ARGUMENTS
3089 *
3090 * RETURN VALUE
3091 *
3092 * REVISIONS
3093 *
3094 * NOTE
3095 *
3096 * @implemented
3097 */
3098 NTSTATUS NTAPI
3099 LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
3100 IN PCWSTR ValueName,
3101 IN ULONG Type,
3102 OUT PVOID Buffer,
3103 IN ULONG BufferSize,
3104 OUT PULONG ReturnedLength OPTIONAL)
3105 {
3106 PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
3107 OBJECT_ATTRIBUTES ObjectAttributes;
3108 UNICODE_STRING ValueNameString;
3109 UNICODE_STRING KeyName;
3110 WCHAR NameBuffer[256];
3111 HANDLE KeyHandle;
3112 ULONG KeyInfoSize;
3113 ULONG ResultSize;
3114 PWCHAR Ptr;
3115 NTSTATUS Status;
3116
3117 wcscpy (NameBuffer,
3118 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
3119 Ptr = wcsrchr (SubKey->Buffer, L'\\');
3120 if (Ptr == NULL)
3121 {
3122 Ptr = SubKey->Buffer;
3123 }
3124 else
3125 {
3126 Ptr++;
3127 }
3128 wcscat (NameBuffer, Ptr);
3129 RtlInitUnicodeString (&KeyName,
3130 NameBuffer);
3131
3132 InitializeObjectAttributes (&ObjectAttributes,
3133 &KeyName,
3134 OBJ_CASE_INSENSITIVE,
3135 NULL,
3136 NULL);
3137
3138 Status = NtOpenKey (&KeyHandle,
3139 KEY_READ,
3140 &ObjectAttributes);
3141 if (!NT_SUCCESS(Status))
3142 {
3143 DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
3144 return Status;
3145 }
3146
3147 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
3148 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3149 HEAP_ZERO_MEMORY,
3150 KeyInfoSize);
3151 if (KeyInfo == NULL)
3152 {
3153 NtClose (KeyHandle);
3154 return STATUS_INSUFFICIENT_RESOURCES;
3155 }
3156
3157 RtlInitUnicodeString (&ValueNameString,
3158 (PWSTR)ValueName);
3159 Status = NtQueryValueKey (KeyHandle,
3160 &ValueNameString,
3161 KeyValuePartialInformation,
3162 KeyInfo,
3163 KeyInfoSize,
3164 &ResultSize);
3165 if (Status == STATUS_BUFFER_OVERFLOW)
3166 {
3167 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
3168 RtlFreeHeap (RtlGetProcessHeap(),
3169 0,
3170 KeyInfo);
3171 KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
3172 HEAP_ZERO_MEMORY,
3173 KeyInfoSize);
3174 if (KeyInfo == NULL)
3175 {
3176 NtClose (KeyHandle);
3177 return STATUS_INSUFFICIENT_RESOURCES;
3178 }
3179
3180 Status = NtQueryValueKey (KeyHandle,
3181 &ValueNameString,
3182 KeyValuePartialInformation,
3183 KeyInfo,
3184 KeyInfoSize,
3185 &ResultSize);
3186 }
3187 NtClose (KeyHandle);
3188
3189 if (!NT_SUCCESS(Status))
3190 {
3191 if (KeyInfo != NULL)
3192 {
3193 RtlFreeHeap (RtlGetProcessHeap(),
3194 0,
3195 KeyInfo);
3196 }
3197 return Status;
3198 }
3199
3200 if (KeyInfo->Type != Type)
3201 {
3202 RtlFreeHeap (RtlGetProcessHeap(),
3203 0,
3204 KeyInfo);
3205 return STATUS_OBJECT_TYPE_MISMATCH;
3206 }
3207
3208 ResultSize = BufferSize;
3209 if (ResultSize < KeyInfo->DataLength)
3210 {
3211 Status = STATUS_BUFFER_OVERFLOW;
3212 }
3213 else
3214 {
3215 ResultSize = KeyInfo->DataLength;
3216 }
3217 RtlCopyMemory (Buffer,
3218 &KeyInfo->Data,
3219 ResultSize);
3220
3221 RtlFreeHeap (RtlGetProcessHeap(),
3222 0,
3223 KeyInfo);
3224
3225 if (ReturnedLength != NULL)
3226 {
3227 *ReturnedLength = ResultSize;
3228 }
3229
3230 return Status;
3231 }
3232
3233
3234 PIMAGE_BASE_RELOCATION NTAPI
3235 LdrProcessRelocationBlock(IN ULONG_PTR Address,
3236 IN ULONG Count,
3237 IN PUSHORT TypeOffset,
3238 IN LONG_PTR Delta)
3239 {
3240 SHORT Offset;
3241 USHORT Type;
3242 USHORT i;
3243 PUSHORT ShortPtr;
3244 PULONG LongPtr;
3245
3246 for (i = 0; i < Count; i++)
3247 {
3248 Offset = *TypeOffset & 0xFFF;
3249 Type = *TypeOffset >> 12;
3250
3251 switch (Type)
3252 {
3253 case IMAGE_REL_BASED_ABSOLUTE:
3254 break;
3255
3256 case IMAGE_REL_BASED_HIGH:
3257 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3258 *ShortPtr += HIWORD(Delta);
3259 break;
3260
3261 case IMAGE_REL_BASED_LOW:
3262 ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
3263 *ShortPtr += LOWORD(Delta);
3264 break;
3265
3266 case IMAGE_REL_BASED_HIGHLOW:
3267 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3268 *LongPtr += Delta;
3269 break;
3270 #ifdef _WIN64
3271 case IMAGE_REL_BASED_DIR64:
3272 LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
3273 *LongPtr += Delta;
3274 break;
3275 #endif
3276
3277 case IMAGE_REL_BASED_HIGHADJ:
3278 case IMAGE_REL_BASED_MIPS_JMPADDR:
3279 default:
3280 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
3281 return NULL;
3282 }
3283
3284 TypeOffset++;
3285 }
3286
3287 return (PIMAGE_BASE_RELOCATION)TypeOffset;
3288 }
3289
3290 NTSTATUS
3291 NTAPI
3292 LdrLockLoaderLock(IN ULONG Flags,
3293 OUT PULONG Disposition OPTIONAL,
3294 OUT PULONG Cookie OPTIONAL)
3295 {
3296 UNIMPLEMENTED;
3297 return STATUS_NOT_IMPLEMENTED;
3298 }
3299
3300 NTSTATUS
3301 NTAPI
3302 LdrUnlockLoaderLock(IN ULONG Flags,
3303 IN ULONG Cookie OPTIONAL)
3304 {
3305 UNIMPLEMENTED;
3306 return STATUS_NOT_IMPLEMENTED;
3307 }
3308
3309 BOOLEAN
3310 NTAPI
3311 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
3312 {
3313 UNIMPLEMENTED;
3314 return FALSE;
3315 }