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