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