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