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