Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

ldrinit.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 ldrinit.c 00008 00009 Abstract: 00010 00011 This module implements loader initialization. 00012 00013 Author: 00014 00015 Mike O'Leary (mikeol) 26-Mar-1990 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include <ntos.h> 00022 #include <nt.h> 00023 #include <ntrtl.h> 00024 #include <nturtl.h> 00025 #include <heap.h> 00026 #include <apcompat.h> 00027 #include "ldrp.h" 00028 #include <ctype.h> 00029 00030 00031 BOOLEAN LdrpShutdownInProgress = FALSE; 00032 BOOLEAN LdrpImageHasTls = FALSE; 00033 BOOLEAN LdrpVerifyDlls = FALSE; 00034 BOOLEAN LdrpLdrDatabaseIsSetup = FALSE; 00035 BOOLEAN LdrpInLdrInit = FALSE; 00036 00037 #if defined(_WIN64) 00038 PVOID Wow64Handle; 00039 ULONG UseWOW64; 00040 typedef VOID (*tWOW64LdrpInitialize)(IN PCONTEXT Context); 00041 tWOW64LdrpInitialize Wow64LdrpInitialize; 00042 PVOID Wow64PrepareForException; 00043 #endif 00044 00045 PVOID NtDllBase; 00046 00047 extern ULONG RtlpDisableHeapLookaside; // defined in rtl\heap.c 00048 00049 #if defined(_ALPHA_) 00050 ULONG_PTR LdrpGpValue; 00051 #endif // ALPHA 00052 00053 #if defined (_X86_) 00054 void 00055 LdrpValidateImageForMp( 00056 IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry 00057 ); 00058 #endif 00059 00060 #if defined (_ALPHA_) 00061 VOID 00062 AlphaFindArchitectureFixups( 00063 PIMAGE_NT_HEADERS NtHeaders, 00064 PVOID ViewBase, 00065 BOOLEAN StaticLink 00066 ); 00067 #endif 00068 00069 VOID 00070 LdrpRelocateStartContext ( 00071 IN PCONTEXT Context, 00072 IN LONG_PTR Diff 00073 ); 00074 00075 NTSTATUS 00076 LdrpForkProcess( VOID ); 00077 00078 VOID 00079 LdrpInitializeThread( 00080 IN PCONTEXT Context 00081 ); 00082 00083 BOOLEAN 00084 NtdllOkayToLockRoutine( 00085 IN PVOID Lock 00086 ); 00087 00088 VOID 00089 RtlpInitDeferedCriticalSection( VOID ); 00090 00091 VOID 00092 LdrQueryApplicationCompatibilityGoo( 00093 IN PUNICODE_STRING UnicodeImageName 00094 ); 00095 00096 NTSTATUS 00097 LdrFindAppCompatVariableInfo( 00098 IN ULONG dwTypeSeeking, 00099 OUT PAPP_VARIABLE_INFO *AppVariableInfo 00100 ); 00101 00102 NTSTATUS 00103 LdrpSearchResourceSection_U( 00104 IN PVOID DllHandle, 00105 IN PULONG_PTR ResourceIdPath, 00106 IN ULONG ResourceIdPathLength, 00107 IN BOOLEAN FindDirectoryEntry, 00108 IN BOOLEAN ExactLangMatchOnly, 00109 OUT PVOID *ResourceDirectoryOrData 00110 ); 00111 00112 NTSTATUS 00113 LdrpAccessResourceData( 00114 IN PVOID DllHandle, 00115 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, 00116 OUT PVOID *Address OPTIONAL, 00117 OUT PULONG Size OPTIONAL 00118 ); 00119 00120 PVOID 00121 NtdllpAllocateStringRoutine( 00122 SIZE_T NumberOfBytes 00123 ) 00124 { 00125 return RtlAllocateHeap(RtlProcessHeap(), 0, NumberOfBytes); 00126 } 00127 00128 VOID 00129 NtdllpFreeStringRoutine( 00130 PVOID Buffer 00131 ) 00132 { 00133 RtlFreeHeap(RtlProcessHeap(), 0, Buffer); 00134 } 00135 00136 PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine; 00137 PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine; 00138 RTL_BITMAP TlsBitMap; 00139 RTL_BITMAP TlsExpansionBitMap; 00140 00141 RTL_CRITICAL_SECTION_DEBUG LoaderLockDebug; 00142 RTL_CRITICAL_SECTION LoaderLock = { 00143 &LoaderLockDebug, 00144 -1 00145 }; 00146 BOOLEAN LoaderLockInitialized; 00147 00148 00149 #if defined(_ALPHA_) 00150 VOID 00151 LdrpSetGp( 00152 IN ULONG_PTR GpValue 00153 ); 00154 #endif // ALPHA 00155 00156 VOID 00157 LdrpInitializationFailure( 00158 IN NTSTATUS FailureCode 00159 ) 00160 { 00161 00162 NTSTATUS ErrorStatus; 00163 ULONG_PTR ErrorParameter; 00164 ULONG ErrorResponse; 00165 00166 if ( LdrpFatalHardErrorCount ) { 00167 return; 00168 } 00169 00170 // 00171 // Its error time... 00172 // 00173 ErrorParameter = (ULONG_PTR)FailureCode; 00174 ErrorStatus = NtRaiseHardError( 00175 STATUS_APP_INIT_FAILURE, 00176 1, 00177 0, 00178 &ErrorParameter, 00179 OptionOk, 00180 &ErrorResponse 00181 ); 00182 } 00183 00184 00185 VOID 00186 LdrpInitialize ( 00187 IN PCONTEXT Context, 00188 IN PVOID SystemArgument1, 00189 IN PVOID SystemArgument2 00190 ) 00191 00192 /*++ 00193 00194 Routine Description: 00195 00196 This function is called as a User-Mode APC routine as the first 00197 user-mode code executed by a new thread. It's function is to initialize 00198 loader context, perform module initialization callouts... 00199 00200 Arguments: 00201 00202 Context - Supplies an optional context buffer that will be restore 00203 after all DLL initialization has been completed. If this 00204 parameter is NULL then this is a dynamic snap of this module. 00205 Otherwise this is a static snap prior to the user process 00206 gaining control. 00207 00208 SystemArgument1 - Supplies the base address of the System Dll. 00209 00210 SystemArgument2 - not used. 00211 00212 Return Value: 00213 00214 None. 00215 00216 --*/ 00217 00218 { 00219 NTSTATUS st, InitStatus; 00220 PPEB Peb; 00221 PTEB Teb; 00222 UNICODE_STRING UnicodeImageName; 00223 MEMORY_BASIC_INFORMATION MemInfo; 00224 BOOLEAN AlreadyFailed; 00225 LARGE_INTEGER DelayValue; 00226 #if defined(_WIN64) 00227 PIMAGE_NT_HEADERS NtHeader; 00228 #endif 00229 00230 SystemArgument2; 00231 00232 AlreadyFailed = FALSE; 00233 Peb = NtCurrentPeb(); 00234 Teb = NtCurrentTeb(); 00235 00236 if (!Peb->Ldr) { 00237 #if defined(_ALPHA_) 00238 ULONG temp; 00239 00240 // 00241 // Set GP register 00242 // 00243 00244 LdrpGpValue = (ULONG_PTR)RtlImageDirectoryEntryToData( 00245 Peb->ImageBaseAddress, 00246 TRUE, 00247 IMAGE_DIRECTORY_ENTRY_GLOBALPTR, 00248 &temp 00249 ); 00250 if (Context != NULL) { 00251 LdrpSetGp( LdrpGpValue ); 00252 Context->IntGp = LdrpGpValue; 00253 } 00254 #endif // ALPHA 00255 00256 //#if DBG 00257 if (TRUE) 00258 //#else 00259 // if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions) 00260 //#endif 00261 { 00262 PWSTR pw; 00263 00264 pw = (PWSTR)Peb->ProcessParameters->ImagePathName.Buffer; 00265 if (!(Peb->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) { 00266 pw = (PWSTR)((PCHAR)pw + (ULONG_PTR)(Peb->ProcessParameters)); 00267 } 00268 UnicodeImageName.Buffer = pw; 00269 UnicodeImageName.Length = Peb->ProcessParameters->ImagePathName.Length; 00270 UnicodeImageName.MaximumLength = UnicodeImageName.Length; 00271 00272 // 00273 // Hack for NT4 SP4. So we don't overload another GlobalFlag 00274 // bit that we have to be "compatible" with for NT5, look for 00275 // another value named "DisableHeapLookaside". 00276 // 00277 00278 LdrQueryImageFileExecutionOptions( &UnicodeImageName, 00279 L"DisableHeapLookaside", 00280 REG_DWORD, 00281 &RtlpDisableHeapLookaside, 00282 sizeof( RtlpDisableHeapLookaside ), 00283 NULL 00284 ); 00285 00286 st = LdrQueryImageFileExecutionOptions( &UnicodeImageName, 00287 L"GlobalFlag", 00288 REG_DWORD, 00289 &Peb->NtGlobalFlag, 00290 sizeof( Peb->NtGlobalFlag ), 00291 NULL 00292 ); 00293 if (!NT_SUCCESS( st )) { 00294 00295 if (Peb->BeingDebugged) { 00296 Peb->NtGlobalFlag |= FLG_HEAP_ENABLE_FREE_CHECK | 00297 FLG_HEAP_ENABLE_TAIL_CHECK | 00298 FLG_HEAP_VALIDATE_PARAMETERS; 00299 } 00300 } 00301 00302 #if defined(_WIN64) 00303 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress); 00304 if (NtHeader && NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 00305 UseWOW64 = TRUE; 00306 } 00307 #endif 00308 } 00309 00310 if ( Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS ) { 00311 00312 // 00313 // We will enable page heap (RtlpDebugPageHeap) only after 00314 // all other initializations for page heap are finished. 00315 // 00316 00317 // 00318 // If page heap is enabled we need to disable any flag that 00319 // might force creation of debug heaps for normal NT heaps. 00320 // This is due to a dependency between page heap and NT heap 00321 // where the page heap within PageHeapCreate tries to create 00322 // a normal NT heap to accomodate some of the allocations. 00323 // If we do not disable these flags we will get an infinite 00324 // recursion between RtlpDebugPageHeapCreate and RtlCreateHeap. 00325 // 00326 00327 Peb->NtGlobalFlag &= ~( FLG_HEAP_ENABLE_TAGGING | 00328 FLG_HEAP_ENABLE_TAG_BY_DLL | 00329 FLG_HEAP_ENABLE_TAIL_CHECK | 00330 FLG_HEAP_ENABLE_FREE_CHECK | 00331 FLG_HEAP_VALIDATE_PARAMETERS | 00332 FLG_HEAP_VALIDATE_ALL | 00333 FLG_USER_STACK_TRACE_DB ); 00334 00335 // 00336 // Read page heap per process global flags. If we fail 00337 // to read a value, the default ones are kept. 00338 // 00339 00340 LdrQueryImageFileExecutionOptions( 00341 &UnicodeImageName, 00342 L"PageHeapFlags", 00343 REG_DWORD, 00344 &RtlpDphGlobalFlags, 00345 sizeof(RtlpDphGlobalFlags), 00346 NULL 00347 ); 00348 00349 // 00350 // Read several page heap parameters. 00351 // 00352 00353 LdrQueryImageFileExecutionOptions( 00354 &UnicodeImageName, 00355 L"PageHeapSizeRangeStart", 00356 REG_DWORD, 00357 &RtlpDphSizeRangeStart, 00358 sizeof(RtlpDphSizeRangeStart), 00359 NULL 00360 ); 00361 00362 LdrQueryImageFileExecutionOptions( 00363 &UnicodeImageName, 00364 L"PageHeapSizeRangeEnd", 00365 REG_DWORD, 00366 &RtlpDphSizeRangeEnd, 00367 sizeof(RtlpDphSizeRangeEnd), 00368 NULL 00369 ); 00370 00371 LdrQueryImageFileExecutionOptions( 00372 &UnicodeImageName, 00373 L"PageHeapRandomProbability", 00374 REG_DWORD, 00375 &RtlpDphRandomProbability, 00376 sizeof(RtlpDphRandomProbability), 00377 NULL 00378 ); 00379 00380 // 00381 // The two values below should be read as PVOIDs so that 00382 // this works on 64-bit architetures. However since this 00383 // feature relies on good stack traces and since we can get 00384 // reliable stack traces only on X86 architectures we will 00385 // leave it as it is. 00386 // 00387 00388 LdrQueryImageFileExecutionOptions( 00389 &UnicodeImageName, 00390 L"PageHeapDllRangeStart", 00391 REG_DWORD, 00392 &RtlpDphDllRangeStart, 00393 sizeof(RtlpDphDllRangeStart), 00394 NULL 00395 ); 00396 00397 LdrQueryImageFileExecutionOptions( 00398 &UnicodeImageName, 00399 L"PageHeapDllRangeEnd", 00400 REG_DWORD, 00401 &RtlpDphDllRangeEnd, 00402 sizeof(RtlpDphDllRangeEnd), 00403 NULL 00404 ); 00405 00406 LdrQueryImageFileExecutionOptions( 00407 &UnicodeImageName, 00408 L"PageHeapTargetDlls", 00409 REG_SZ, 00410 &RtlpDphTargetDlls, 00411 512, 00412 NULL 00413 ); 00414 00415 // 00416 // Turn on BOOLEAN RtlpDebugPageHeap to indicate that 00417 // new heaps should be created with debug page heap manager 00418 // when possible. 00419 // 00420 00421 RtlpDebugPageHeap = TRUE; 00422 } 00423 } 00424 #if defined(_ALPHA_) 00425 else 00426 if (Context != NULL) { 00427 LdrpSetGp( LdrpGpValue ); 00428 Context->IntGp = LdrpGpValue; 00429 } 00430 #endif // ALPHA 00431 00432 // 00433 // Serialize for here on out 00434 // 00435 00436 Peb->LoaderLock = (PVOID)&LoaderLock; 00437 00438 if ( !RtlTryEnterCriticalSection(&LoaderLock) ) { 00439 if ( LoaderLockInitialized ) { 00440 RtlEnterCriticalSection(&LoaderLock); 00441 } 00442 else { 00443 00444 // 00445 // drop into a 30ms delay loop 00446 // 00447 00448 DelayValue.QuadPart = Int32x32To64( 30, -10000 ); 00449 while ( !LoaderLockInitialized ) { 00450 NtDelayExecution(FALSE,&DelayValue); 00451 } 00452 RtlEnterCriticalSection(&LoaderLock); 00453 } 00454 } 00455 00456 if (Teb->DeallocationStack == NULL) { 00457 st = NtQueryVirtualMemory( 00458 NtCurrentProcess(), 00459 Teb->NtTib.StackLimit, 00460 MemoryBasicInformation, 00461 (PVOID)&MemInfo, 00462 sizeof(MemInfo), 00463 NULL 00464 ); 00465 if ( !NT_SUCCESS(st) ) { 00466 LdrpInitializationFailure(st); 00467 RtlRaiseStatus(st); 00468 return; 00469 } 00470 else { 00471 Teb->DeallocationStack = MemInfo.AllocationBase; 00472 #if defined(_IA64_) 00473 Teb->DeallocationBStore = (PVOID)((ULONG_PTR)MemInfo.AllocationBase + MemInfo.RegionSize); 00474 #endif // defined(_IA64_) 00475 } 00476 } 00477 00478 InitStatus = STATUS_SUCCESS; 00479 try { 00480 if (!Peb->Ldr) { 00481 LdrpInLdrInit = TRUE; 00482 #if DBG 00483 // 00484 // Time the load. 00485 // 00486 00487 if (LdrpDisplayLoadTime) { 00488 NtQueryPerformanceCounter(&BeginTime, NULL); 00489 } 00490 #endif // DBG 00491 00492 try { 00493 InitStatus = LdrpInitializeProcess( Context, 00494 SystemArgument1, 00495 &UnicodeImageName 00496 ); 00497 } 00498 except ( EXCEPTION_EXECUTE_HANDLER ) { 00499 InitStatus = GetExceptionCode(); 00500 AlreadyFailed = TRUE; 00501 LdrpInitializationFailure(GetExceptionCode()); 00502 } 00503 00504 #if DBG 00505 if (LdrpDisplayLoadTime) { 00506 NtQueryPerformanceCounter(&EndTime, NULL); 00507 NtQueryPerformanceCounter(&ElapsedTime, &Interval); 00508 ElapsedTime.QuadPart = EndTime.QuadPart - BeginTime.QuadPart; 00509 DbgPrint("\nLoadTime %ld In units of %ld cycles/second \n", 00510 ElapsedTime.LowPart, 00511 Interval.LowPart 00512 ); 00513 00514 ElapsedTime.QuadPart = EndTime.QuadPart - InitbTime.QuadPart; 00515 DbgPrint("InitTime %ld\n", 00516 ElapsedTime.LowPart 00517 ); 00518 DbgPrint("Compares %d Bypasses %d Normal Snaps %d\nSecOpens %d SecCreates %d Maps %d Relocates %d\n", 00519 LdrpCompareCount, 00520 LdrpSnapBypass, 00521 LdrpNormalSnap, 00522 LdrpSectionOpens, 00523 LdrpSectionCreates, 00524 LdrpSectionMaps, 00525 LdrpSectionRelocates 00526 ); 00527 } 00528 #endif // DBG 00529 00530 00531 } else { 00532 if ( Peb->InheritedAddressSpace ) { 00533 InitStatus = LdrpForkProcess(); 00534 } 00535 else { 00536 00537 #if defined (WX86) 00538 if (Teb->Vdm) { 00539 InitStatus = LdrpInitWx86(Teb->Vdm, Context, TRUE); 00540 } 00541 #endif 00542 00543 #if defined(_WIN64) 00544 // 00545 // Load in WOW64 if the image is supposed to run simulated 00546 // 00547 if (UseWOW64) { 00548 RtlLeaveCriticalSection(&LoaderLock); 00549 (*Wow64LdrpInitialize)(Context); 00550 // This never returns. It will destroy the process. 00551 } 00552 #endif 00553 LdrpInitializeThread(Context); 00554 } 00555 } 00556 } finally { 00557 LdrpInLdrInit = FALSE; 00558 RtlLeaveCriticalSection(&LoaderLock); 00559 } 00560 00561 NtTestAlert(); 00562 00563 if (!NT_SUCCESS(InitStatus)) { 00564 00565 if ( AlreadyFailed == FALSE ) { 00566 LdrpInitializationFailure(InitStatus); 00567 } 00568 RtlRaiseStatus(InitStatus); 00569 } 00570 00571 00572 } 00573 00574 NTSTATUS 00575 LdrpForkProcess( VOID ) 00576 { 00577 NTSTATUS st; 00578 PPEB Peb; 00579 00580 Peb = NtCurrentPeb(); 00581 00582 // 00583 // Initialize the critical section package. 00584 // 00585 00586 RtlpInitDeferedCriticalSection(); 00587 00588 InsertTailList(&RtlCriticalSectionList, &LoaderLock.DebugInfo->ProcessLocksList); 00589 LoaderLock.DebugInfo->CriticalSection = &LoaderLock; 00590 LoaderLockInitialized = TRUE; 00591 00592 st = RtlInitializeCriticalSection(&FastPebLock); 00593 if ( !NT_SUCCESS(st) ) { 00594 RtlRaiseStatus(st); 00595 } 00596 Peb->FastPebLock = &FastPebLock; 00597 Peb->FastPebLockRoutine = (PVOID)&RtlEnterCriticalSection; 00598 Peb->FastPebUnlockRoutine = (PVOID)&RtlLeaveCriticalSection; 00599 Peb->InheritedAddressSpace = FALSE; 00600 RtlInitializeHeapManager(); 00601 Peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, // Flags 00602 NULL, // HeapBase 00603 64 * 1024, // ReserveSize 00604 4096, // CommitSize 00605 NULL, // Lock to use for serialization 00606 NULL // GrowthThreshold 00607 ); 00608 if (Peb->ProcessHeap == NULL) { 00609 return STATUS_NO_MEMORY; 00610 } 00611 00612 return st; 00613 } 00614 00615 NTSTATUS 00616 LdrpInitializeProcess ( 00617 IN PCONTEXT Context OPTIONAL, 00618 IN PVOID SystemDllBase, 00619 IN PUNICODE_STRING UnicodeImageName 00620 ) 00621 00622 /*++ 00623 00624 Routine Description: 00625 00626 This function initializes the loader for the process. 00627 This includes: 00628 00629 - Initializing the loader data table 00630 00631 - Connecting to the loader subsystem 00632 00633 - Initializing all staticly linked DLLs 00634 00635 Arguments: 00636 00637 Context - Supplies an optional context buffer that will be restore 00638 after all DLL initialization has been completed. If this 00639 parameter is NULL then this is a dynamic snap of this module. 00640 Otherwise this is a static snap prior to the user process 00641 gaining control. 00642 00643 SystemDllBase - Supplies the base address of the system dll. 00644 00645 Return Value: 00646 00647 Status value 00648 00649 --*/ 00650 00651 { 00652 PPEB Peb; 00653 NTSTATUS st; 00654 PWCH p, pp; 00655 UNICODE_STRING CurDir; 00656 UNICODE_STRING FullImageName; 00657 UNICODE_STRING CommandLine; 00658 ULONG DebugProcessHeapOnly = 0 ; 00659 HANDLE LinkHandle; 00660 WCHAR SystemDllPathBuffer[DOS_MAX_PATH_LENGTH]; 00661 UNICODE_STRING SystemDllPath; 00662 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 00663 PRTL_USER_PROCESS_PARAMETERS ProcessParameters; 00664 UNICODE_STRING Unicode; 00665 OBJECT_ATTRIBUTES Obja; 00666 BOOLEAN StaticCurDir = FALSE; 00667 ULONG i; 00668 PIMAGE_NT_HEADERS NtHeader = RtlImageNtHeader( NtCurrentPeb()->ImageBaseAddress ); 00669 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; 00670 ULONG ProcessHeapFlags; 00671 RTL_HEAP_PARAMETERS HeapParameters; 00672 NLSTABLEINFO InitTableInfo; 00673 LARGE_INTEGER LongTimeout; 00674 UNICODE_STRING NtSystemRoot; 00675 LONG_PTR Diff; 00676 ULONG_PTR OldBase; 00677 00678 NtDllBase = SystemDllBase; 00679 00680 if ( 00681 #if defined(_WIN64) 00682 NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC && 00683 #endif 00684 NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE ) { 00685 00686 // 00687 // Native subsystems load slower, but validate their DLLs 00688 // This is to help CSR detect bad images faster 00689 // 00690 00691 LdrpVerifyDlls = TRUE; 00692 00693 } 00694 00695 00696 Peb = NtCurrentPeb(); 00697 00698 #if defined(BUILD_WOW6432) 00699 { 00700 // 00701 // The process is running in WOW64. Sort out the optional header 00702 // format and reformat the image if its page size is smaller than 00703 // the native page size. 00704 // 00705 PIMAGE_NT_HEADERS32 NtHeader32 = (PIMAGE_NT_HEADERS32)NtHeader; 00706 00707 if (NtHeader32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 && 00708 NtHeader32->OptionalHeader.SectionAlignment < NATIVE_PAGE_SIZE && 00709 !NT_SUCCESS(st = LdrpWx86FormatVirtualImage(NtHeader32, 00710 NtCurrentPeb()->ImageBaseAddress 00711 //bugbug: should be: (PVOID)NtHeader32->OptionalHeader.ImageBase 00712 ))) { 00713 return st; 00714 } 00715 } 00716 #elif defined (_ALPHA_) && defined (WX86) 00717 // 00718 // Deal with the native page size which is larger than x86 00719 // This needs to be done before any code reads beyond the file headers. 00720 // 00721 if (NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 && 00722 NtHeader->OptionalHeader.SectionAlignment < PAGE_SIZE && 00723 !NT_SUCCESS(st = LdrpWx86FormatVirtualImage((PIMAGE_NT_HEADERS32)NtHeader, 00724 (PVOID)NtHeader->OptionalHeader.ImageBase 00725 ))) 00726 { 00727 return st; 00728 } 00729 #endif 00730 00731 00732 LdrpNumberOfProcessors = Peb->NumberOfProcessors; 00733 RtlpTimeout = Peb->CriticalSectionTimeout; 00734 LongTimeout.QuadPart = Int32x32To64( 3600, -10000000 ); 00735 00736 if (ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters)) { 00737 FullImageName = *(PUNICODE_STRING)&ProcessParameters->ImagePathName; 00738 CommandLine = *(PUNICODE_STRING)&ProcessParameters->CommandLine; 00739 } 00740 else { 00741 RtlInitUnicodeString( &FullImageName, NULL ); 00742 RtlInitUnicodeString( &CommandLine, NULL ); 00743 } 00744 00745 00746 RtlInitNlsTables( 00747 Peb->AnsiCodePageData, 00748 Peb->OemCodePageData, 00749 Peb->UnicodeCaseTableData, 00750 &InitTableInfo 00751 ); 00752 00753 RtlResetRtlTranslations(&InitTableInfo); 00754 00755 #if defined(_WIN64) 00756 if (UseWOW64) { 00757 // 00758 // Ignore image config data when initializing the 64-bit loader. 00759 // The 32-bit loader in ntdll32 will look at the config data 00760 // and do the right thing. 00761 // 00762 ImageConfigData = NULL; 00763 } else 00764 #endif 00765 { 00766 00767 ImageConfigData = RtlImageDirectoryEntryToData( Peb->ImageBaseAddress, 00768 TRUE, 00769 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, 00770 &i 00771 ); 00772 } 00773 00774 RtlZeroMemory( &HeapParameters, sizeof( HeapParameters ) ); 00775 ProcessHeapFlags = HEAP_GROWABLE | HEAP_CLASS_0; 00776 HeapParameters.Length = sizeof( HeapParameters ); 00777 if (ImageConfigData != NULL && i == sizeof( *ImageConfigData )) { 00778 Peb->NtGlobalFlag &= ~ImageConfigData->GlobalFlagsClear; 00779 Peb->NtGlobalFlag |= ImageConfigData->GlobalFlagsSet; 00780 00781 if (ImageConfigData->CriticalSectionDefaultTimeout != 0) { 00782 // 00783 // Convert from milliseconds to NT time scale (100ns) 00784 // 00785 RtlpTimeout.QuadPart = Int32x32To64( (LONG)ImageConfigData->CriticalSectionDefaultTimeout, 00786 -10000 00787 ); 00788 00789 } 00790 00791 if (ImageConfigData->ProcessHeapFlags != 0) { 00792 ProcessHeapFlags = ImageConfigData->ProcessHeapFlags; 00793 } 00794 00795 if (ImageConfigData->DeCommitFreeBlockThreshold != 0) { 00796 HeapParameters.DeCommitFreeBlockThreshold = ImageConfigData->DeCommitFreeBlockThreshold; 00797 } 00798 00799 if (ImageConfigData->DeCommitTotalFreeThreshold != 0) { 00800 HeapParameters.DeCommitTotalFreeThreshold = ImageConfigData->DeCommitTotalFreeThreshold; 00801 } 00802 00803 if (ImageConfigData->MaximumAllocationSize != 0) { 00804 HeapParameters.MaximumAllocationSize = ImageConfigData->MaximumAllocationSize; 00805 } 00806 00807 if (ImageConfigData->VirtualMemoryThreshold != 0) { 00808 HeapParameters.VirtualMemoryThreshold = ImageConfigData->VirtualMemoryThreshold; 00809 } 00810 } 00811 00812 // // 00813 // // Check if the image has the fast heap flag set 00814 // // 00815 // 00816 // if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FAST_HEAP) { 00817 // RtlpDisableHeapLookaside = 0; 00818 // } else { 00819 // RtlpDisableHeapLookaside = 1; 00820 // } 00821 00822 ShowSnaps = (BOOLEAN)(FLG_SHOW_LDR_SNAPS & Peb->NtGlobalFlag); 00823 00824 00825 00826 // 00827 // This field is non-zero if the image file that was used to create this 00828 // process contained a non-zero value in its image header. If so, then 00829 // set the affinity mask for the process using this value. It could also 00830 // be non-zero if the parent process created us suspended and poked our 00831 // PEB with a non-zero value before resuming. 00832 // 00833 if (Peb->ImageProcessAffinityMask) { 00834 st = NtSetInformationProcess( NtCurrentProcess(), 00835 ProcessAffinityMask, 00836 &Peb->ImageProcessAffinityMask, 00837 sizeof( Peb->ImageProcessAffinityMask ) 00838 ); 00839 if (NT_SUCCESS( st )) { 00840 KdPrint(( "LDR: Using ProcessAffinityMask of 0x%x from image.\n", 00841 Peb->ImageProcessAffinityMask 00842 )); 00843 } 00844 else { 00845 KdPrint(( "LDR: Failed to set ProcessAffinityMask of 0x%x from image (Status == %08x).\n", 00846 Peb->ImageProcessAffinityMask, st 00847 )); 00848 } 00849 } 00850 00851 if (RtlpTimeout.QuadPart < LongTimeout.QuadPart) { 00852 RtlpTimoutDisable = TRUE; 00853 } 00854 00855 if (ShowSnaps) { 00856 DbgPrint( "LDR: PID: 0x%x started - '%wZ'\n", 00857 NtCurrentTeb()->ClientId.UniqueProcess, 00858 &CommandLine 00859 ); 00860 } 00861 00862 for(i=0;i<LDRP_HASH_TABLE_SIZE;i++) { 00863 InitializeListHead(&LdrpHashTable[i]); 00864 } 00865 00866 // 00867 // Initialize the critical section package. 00868 // 00869 00870 RtlpInitDeferedCriticalSection(); 00871 00872 Peb->TlsBitmap = (PVOID)&TlsBitMap; 00873 Peb->TlsExpansionBitmap = (PVOID)&TlsExpansionBitMap; 00874 00875 RtlInitializeBitMap ( 00876 &TlsBitMap, 00877 &Peb->TlsBitmapBits[0], 00878 TLS_MINIMUM_AVAILABLE 00879 ); 00880 00881 RtlInitializeBitMap ( 00882 &TlsExpansionBitMap, 00883 &Peb->TlsExpansionBitmapBits[0], 00884 TLS_EXPANSION_SLOTS 00885 ); 00886 00887 InsertTailList(&RtlCriticalSectionList, &LoaderLock.DebugInfo->ProcessLocksList); 00888 LoaderLock.DebugInfo->CriticalSection = &LoaderLock; 00889 LoaderLockInitialized = TRUE; 00890 00891 // 00892 // Initialize the stack trace data base if requested 00893 // 00894 00895 #if i386 00896 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB) { 00897 PVOID BaseAddress = NULL; 00898 ULONG ReserveSize = 2 * 1024 * 1024; 00899 00900 st = NtAllocateVirtualMemory( NtCurrentProcess(), 00901 (PVOID *)&BaseAddress, 00902 0, 00903 &ReserveSize, 00904 MEM_RESERVE, 00905 PAGE_READWRITE 00906 ); 00907 if ( NT_SUCCESS( st ) ) { 00908 st = RtlInitializeStackTraceDataBase( BaseAddress, 00909 0, 00910 ReserveSize 00911 ); 00912 if ( !NT_SUCCESS( st ) ) { 00913 NtFreeVirtualMemory( NtCurrentProcess(), 00914 (PVOID *)&BaseAddress, 00915 &ReserveSize, 00916 MEM_RELEASE 00917 ); 00918 } 00919 else { 00920 Peb->NtGlobalFlag |= FLG_HEAP_VALIDATE_PARAMETERS; 00921 } 00922 } 00923 } 00924 #endif // i386 00925 00926 // 00927 // Initialize the loader data based in the PEB. 00928 // 00929 00930 st = RtlInitializeCriticalSection(&FastPebLock); 00931 if ( !NT_SUCCESS(st) ) { 00932 return st; 00933 } 00934 Peb->FastPebLock = &FastPebLock; 00935 Peb->FastPebLockRoutine = (PVOID)&RtlEnterCriticalSection; 00936 Peb->FastPebUnlockRoutine = (PVOID)&RtlLeaveCriticalSection; 00937 00938 RtlInitializeHeapManager(); 00939 #if defined(_WIN64) 00940 if (UseWOW64) { 00941 // 00942 // Create a heap using all defaults. The 32-bit process heap 00943 // will be created later by ntdll32 using the parameters from the exe. 00944 // 00945 Peb->ProcessHeap = RtlCreateHeap( ProcessHeapFlags, 00946 NULL, 00947 0, 00948 0, 00949 NULL, 00950 &HeapParameters 00951 ); 00952 } else 00953 #endif 00954 { 00955 00956 if (NtHeader->OptionalHeader.MajorSubsystemVersion <= 3 && 00957 NtHeader->OptionalHeader.MinorSubsystemVersion < 51 00958 ) { 00959 ProcessHeapFlags |= HEAP_CREATE_ALIGN_16; 00960 } 00961 00962 Peb->ProcessHeap = RtlCreateHeap( ProcessHeapFlags, 00963 NULL, 00964 NtHeader->OptionalHeader.SizeOfHeapReserve, 00965 NtHeader->OptionalHeader.SizeOfHeapCommit, 00966 NULL, // Lock to use for serialization 00967 &HeapParameters 00968 ); 00969 } 00970 if (Peb->ProcessHeap == NULL) { 00971 return STATUS_NO_MEMORY; 00972 } 00973 00974 NtdllBaseTag = RtlCreateTagHeap( Peb->ProcessHeap, 00975 0, 00976 L"NTDLL!", 00977 L"!Process\0" // Heap Name 00978 L"CSRSS Client\0" 00979 L"LDR Database\0" 00980 L"Current Directory\0" 00981 L"TLS Storage\0" 00982 L"DBGSS Client\0" 00983 L"SE Temporary\0" 00984 L"Temporary\0" 00985 L"LocalAtom\0" 00986 ); 00987 00988 RtlAllocateStringRoutine = NtdllpAllocateStringRoutine; 00989 RtlFreeStringRoutine = NtdllpFreeStringRoutine; 00990 00991 RtlInitializeAtomPackage( MAKE_TAG( ATOM_TAG ) ); 00992 00993 // 00994 // Allow only the process heap to have page allocations turned on 00995 // 00996 00997 st = LdrQueryImageFileExecutionOptions( UnicodeImageName, 00998 L"DebugProcessHeapOnly", 00999 REG_DWORD, 01000 &DebugProcessHeapOnly, 01001 sizeof( DebugProcessHeapOnly ), 01002 NULL 01003 ); 01004 if (NT_SUCCESS( st )) { 01005 01006 if ( RtlpDebugPageHeap && 01007 ( DebugProcessHeapOnly != 0 ) ) { 01008 01009 RtlpDebugPageHeap = FALSE ; 01010 01011 } 01012 01013 } 01014 01015 SystemDllPath.Buffer = SystemDllPathBuffer; 01016 SystemDllPath.Length = 0; 01017 SystemDllPath.MaximumLength = sizeof( SystemDllPathBuffer ); 01018 RtlInitUnicodeString( &NtSystemRoot, USER_SHARED_DATA->NtSystemRoot ); 01019 RtlAppendUnicodeStringToString( &SystemDllPath, &NtSystemRoot ); 01020 RtlAppendUnicodeToString( &SystemDllPath, L"\\System32\\" ); 01021 01022 RtlInitUnicodeString(&Unicode,L"\\KnownDlls"); 01023 InitializeObjectAttributes( &Obja, 01024 &Unicode, 01025 OBJ_CASE_INSENSITIVE, 01026 NULL, 01027 NULL 01028 ); 01029 st = NtOpenDirectoryObject( 01030 &LdrpKnownDllObjectDirectory, 01031 DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 01032 &Obja 01033 ); 01034 if ( !NT_SUCCESS(st) ) { 01035 LdrpKnownDllObjectDirectory = NULL; 01036 // KnownDlls directory doesn't exist - assume it's system32. 01037 RtlInitUnicodeString(&LdrpKnownDllPath, SystemDllPath.Buffer); 01038 LdrpKnownDllPath.Length -= sizeof(WCHAR); // remove trailing '\' 01039 } 01040 else { 01041 01042 // 01043 // Open up the known dll pathname link 01044 // and query its value 01045 // 01046 01047 RtlInitUnicodeString(&Unicode,L"KnownDllPath"); 01048 InitializeObjectAttributes( &Obja, 01049 &Unicode, 01050 OBJ_CASE_INSENSITIVE, 01051 LdrpKnownDllObjectDirectory, 01052 NULL 01053 ); 01054 st = NtOpenSymbolicLinkObject( &LinkHandle, 01055 SYMBOLIC_LINK_QUERY, 01056 &Obja 01057 ); 01058 if (NT_SUCCESS( st )) { 01059 LdrpKnownDllPath.Length = 0; 01060 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer); 01061 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer; 01062 st = NtQuerySymbolicLinkObject( LinkHandle, 01063 &LdrpKnownDllPath, 01064 NULL 01065 ); 01066 NtClose(LinkHandle); 01067 if ( !NT_SUCCESS(st) ) { 01068 return st; 01069 } 01070 } 01071 else { 01072 return st; 01073 } 01074 } 01075 01076 if (ProcessParameters) { 01077 01078 // 01079 // If the process was created with process parameters, 01080 // than extract: 01081 // 01082 // - Library Search Path 01083 // 01084 // - Starting Current Directory 01085 // 01086 01087 if (ProcessParameters->DllPath.Length) { 01088 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath; 01089 } 01090 else { 01091 LdrpInitializationFailure( STATUS_INVALID_PARAMETER ); 01092 } 01093 01094 StaticCurDir = TRUE; 01095 CurDir = ProcessParameters->CurrentDirectory.DosPath; 01096 if (CurDir.Buffer == NULL || CurDir.Buffer[ 0 ] == UNICODE_NULL || CurDir.Length == 0) { 01097 CurDir.Buffer = (RtlAllocateStringRoutine)( (3+1) * sizeof( WCHAR ) ); 01098 ASSERT(CurDir.Buffer != NULL); 01099 RtlMoveMemory( CurDir.Buffer, 01100 USER_SHARED_DATA->NtSystemRoot, 01101 3 * sizeof( WCHAR ) 01102 ); 01103 CurDir.Buffer[ 3 ] = UNICODE_NULL; 01104 } 01105 } 01106 01107 // 01108 // Make sure the module data base is initialized before we take any 01109 // exceptions. 01110 // 01111 01112 Peb->Ldr = RtlAllocateHeap(Peb->ProcessHeap, MAKE_TAG( LDR_TAG ), sizeof(PEB_LDR_DATA)); 01113 if ( !Peb->Ldr ) { 01114 RtlRaiseStatus(STATUS_NO_MEMORY); 01115 } 01116 01117 Peb->Ldr->Length = sizeof(PEB_LDR_DATA); 01118 Peb->Ldr->Initialized = TRUE; 01119 Peb->Ldr->SsHandle = NULL; 01120 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList); 01121 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList); 01122 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList); 01123 01124 // 01125 // Allocate the first data table entry for the image. Since we 01126 // have already mapped this one, we need to do the allocation by hand. 01127 // Its characteristics identify it as not a Dll, but it is linked 01128 // into the table so that pc correlation searching doesn't have to 01129 // be special cased. 01130 // 01131 01132 LdrDataTableEntry = LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress); 01133 LdrDataTableEntry->LoadCount = (USHORT)0xffff; 01134 LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase); 01135 LdrDataTableEntry->FullDllName = FullImageName; 01136 LdrDataTableEntry->Flags = 0; 01137 01138 // p = strrchr(FullImageName, '\\'); 01139 pp = UNICODE_NULL; 01140 p = FullImageName.Buffer; 01141 while (*p) { 01142 if (*p++ == (WCHAR)'\\') { 01143 pp = p; 01144 } 01145 } 01146 01147 LdrDataTableEntry->FullDllName.Length = (USHORT)((ULONG_PTR)p - (ULONG_PTR)FullImageName.Buffer); 01148 LdrDataTableEntry->FullDllName.MaximumLength = LdrDataTableEntry->FullDllName.Length + (USHORT)sizeof(UNICODE_NULL); 01149 01150 if (pp) { 01151 LdrDataTableEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)p - (ULONG_PTR)pp); 01152 LdrDataTableEntry->BaseDllName.MaximumLength = LdrDataTableEntry->BaseDllName.Length + (USHORT)sizeof(UNICODE_NULL); 01153 LdrDataTableEntry->BaseDllName.Buffer = RtlAllocateHeap(Peb->ProcessHeap, MAKE_TAG( LDR_TAG ), 01154 LdrDataTableEntry->BaseDllName.MaximumLength 01155 ); 01156 RtlMoveMemory(LdrDataTableEntry->BaseDllName.Buffer, 01157 pp, 01158 LdrDataTableEntry->BaseDllName.MaximumLength 01159 ); 01160 } else { 01161 LdrDataTableEntry->BaseDllName = LdrDataTableEntry->FullDllName; 01162 } 01163 LdrpInsertMemoryTableEntry(LdrDataTableEntry); 01164 LdrDataTableEntry->Flags |= LDRP_ENTRY_PROCESSED; 01165 01166 if (ShowSnaps) { 01167 DbgPrint( "LDR: NEW PROCESS\n" ); 01168 DbgPrint( " Image Path: %wZ (%wZ)\n", 01169 &LdrDataTableEntry->FullDllName, 01170 &LdrDataTableEntry->BaseDllName 01171 ); 01172 DbgPrint( " Current Directory: %wZ\n", &CurDir ); 01173 DbgPrint( " Search Path: %wZ\n", &LdrpDefaultPath ); 01174 } 01175 01176 // 01177 // The process references the system DLL, so map this one next. Since 01178 // we have already mapped this one, we need to do the allocation by 01179 // hand. Since every application will be statically linked to the 01180 // system Dll, we'll keep the LoadCount initialized to 0. 01181 // 01182 01183 LdrDataTableEntry = LdrpAllocateDataTableEntry(SystemDllBase); 01184 LdrDataTableEntry->Flags = (USHORT)LDRP_IMAGE_DLL; 01185 LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase); 01186 LdrDataTableEntry->LoadCount = (USHORT)0xffff; 01187 01188 LdrDataTableEntry->BaseDllName.Length = SystemDllPath.Length; 01189 RtlAppendUnicodeToString( &SystemDllPath, L"ntdll.dll" ); 01190 LdrDataTableEntry->BaseDllName.Length = SystemDllPath.Length - LdrDataTableEntry->BaseDllName.Length; 01191 LdrDataTableEntry->BaseDllName.MaximumLength = LdrDataTableEntry->BaseDllName.Length + sizeof( UNICODE_NULL ); 01192 01193 LdrDataTableEntry->FullDllName.Buffer = 01194 (RtlAllocateStringRoutine)( SystemDllPath.Length + sizeof( UNICODE_NULL ) ); 01195 ASSERT(LdrDataTableEntry->FullDllName.Buffer != NULL); 01196 RtlMoveMemory( LdrDataTableEntry->FullDllName.Buffer, 01197 SystemDllPath.Buffer, 01198 SystemDllPath.Length 01199 ); 01200 LdrDataTableEntry->FullDllName.Buffer[ SystemDllPath.Length / sizeof( WCHAR ) ] = UNICODE_NULL; 01201 LdrDataTableEntry->FullDllName.Length = SystemDllPath.Length; 01202 LdrDataTableEntry->FullDllName.MaximumLength = SystemDllPath.Length + sizeof( UNICODE_NULL ); 01203 LdrDataTableEntry->BaseDllName.Buffer = (PWSTR) 01204 ((PCHAR)(LdrDataTableEntry->FullDllName.Buffer) + 01205 LdrDataTableEntry->FullDllName.Length - 01206 LdrDataTableEntry->BaseDllName.Length 01207 ); 01208 LdrpInsertMemoryTableEntry(LdrDataTableEntry); 01209 01210 // 01211 // Add init routine to list 01212 // 01213 01214 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList, 01215 &LdrDataTableEntry->InInitializationOrderLinks); 01216 01217 // 01218 // Inherit the current directory 01219 // 01220 01221 st = RtlSetCurrentDirectory_U(&CurDir); 01222 if (!NT_SUCCESS(st)) { 01223 if ( !StaticCurDir ) { 01224 RtlFreeUnicodeString(&CurDir); 01225 } 01226 CurDir = NtSystemRoot; 01227 st = RtlSetCurrentDirectory_U(&CurDir); 01228 } 01229 else { 01230 if ( !StaticCurDir ) { 01231 RtlFreeUnicodeString(&CurDir); 01232 } 01233 } 01234 01235 #if defined(WX86) 01236 01237 // 01238 // Load in x86 emulator for risc (Wx86.dll) 01239 // 01240 01241 if (NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { 01242 st = LdrpLoadWx86Dll(Context); 01243 if (!NT_SUCCESS(st)) { 01244 return st; 01245 } 01246 } 01247 01248 #endif 01249 01250 #if defined(_WIN64) 01251 // 01252 // Load in WOW64 if the image is supposed to run simulated 01253 // 01254 if (UseWOW64) { 01255 UNICODE_STRING Wow64Name; 01256 ANSI_STRING ProcName; 01257 RtlInitUnicodeString(&Wow64Name, L"wow64.dll"); 01258 st = LdrLoadDll(NULL, NULL, &Wow64Name, &Wow64Handle); 01259 if (!NT_SUCCESS(st)) { 01260 if (ShowSnaps) { 01261 DbgPrint("wow64.dll not found. Status=%x\n", st); 01262 } 01263 return st; 01264 } 01265 01266 // 01267 // Get the entrypoints. They are roughly cloned from ntos\ps\psinit.c 01268 // PspInitSystemDll(). 01269 // 01270 RtlInitAnsiString(&ProcName, "Wow64LdrpInitialize"); 01271 st = LdrGetProcedureAddress(Wow64Handle, 01272 &ProcName, 01273 0, 01274 (PVOID *)&Wow64LdrpInitialize); 01275 if (!NT_SUCCESS(st)) { 01276 if (ShowSnaps) { 01277 DbgPrint("Wow64LdrpInitialize not found. Status=%x\n", st); 01278 } 01279 return st; 01280 } 01281 01282 RtlInitAnsiString(&ProcName, "Wow64PrepareForException"); 01283 st = LdrGetProcedureAddress(Wow64Handle, 01284 &ProcName, 01285 0, 01286 (PVOID *)&Wow64PrepareForException); 01287 if (!NT_SUCCESS(st)) { 01288 if (ShowSnaps) { 01289 DbgPrint("Wow64PrepareForException not found. Status=%x\n", st); 01290 } 01291 return st; 01292 } 01293 01294 DbgPrint("WARNING: PROCESS HAS BEEN CONVERTED TO WOW64!!!\n"); 01295 if (Peb->ProcessParameters) { 01296 DbgPrint("CommandLine: %wZ\n", &Peb->ProcessParameters->CommandLine); 01297 DbgPrint("ImagePathName: %wZ\n", &Peb->ProcessParameters->ImagePathName); 01298 } 01299 01300 // 01301 // Now that all DLLs are loaded, if the process is being debugged, 01302 // signal the debugger with an exception 01303 // 01304 01305 if ( Peb->BeingDebugged ) { 01306 DbgBreakPoint(); 01307 } 01308 01309 // 01310 // Release the loaderlock now - this thread doesn't need it any more. 01311 // 01312 RtlLeaveCriticalSection(&LoaderLock); 01313 01314 // 01315 // Call wow64 to load and run 32-bit ntdll.dll. 01316 // 01317 (*Wow64LdrpInitialize)(Context); 01318 // This never returns. It will destroy the process. 01319 } 01320 #endif 01321 01322 01323 st = LdrpWalkImportDescriptor( 01324 LdrpDefaultPath.Buffer, 01325 LdrpImageEntry 01326 ); 01327 01328 if ((PVOID)NtHeader->OptionalHeader.ImageBase != NtCurrentPeb()->ImageBaseAddress ) { 01329 01330 // 01331 // The executable is not at its original address. It must be 01332 // relocated now. 01333 // 01334 01335 PVOID ViewBase; 01336 NTSTATUS status; 01337 01338 ViewBase = NtCurrentPeb()->ImageBaseAddress; 01339 01340 status = LdrpSetProtection(ViewBase, FALSE, TRUE); 01341 01342 if (!NT_SUCCESS(status)) { 01343 return status; 01344 } 01345 01346 status = (NTSTATUS)LdrRelocateImage(ViewBase, 01347 "LDR", 01348 (ULONG)STATUS_SUCCESS, 01349 (ULONG)STATUS_CONFLICTING_ADDRESSES, 01350 (ULONG)STATUS_INVALID_IMAGE_FORMAT 01351 ); 01352 01353 if (!NT_SUCCESS(status)) { 01354 return status; 01355 } 01356 01357 // 01358 // Update the initial thread context record as per the relocation. 01359 // 01360 01361 if (Context) { 01362 01363 OldBase = NtHeader->OptionalHeader.ImageBase; 01364 Diff = (PCHAR)ViewBase - (PCHAR)OldBase; 01365 01366 LdrpRelocateStartContext(Context, Diff); 01367 } 01368 01369 status = LdrpSetProtection(ViewBase, TRUE, TRUE); 01370 01371 if (!NT_SUCCESS(status)) { 01372 return status; 01373 } 01374 } 01375 01376 #if defined (_ALPHA_) 01377 01378 // 01379 // Find and apply Alpha architecture fixups for this image 01380 // 01381 01382 AlphaFindArchitectureFixups(NtHeader, NtCurrentPeb()->ImageBaseAddress, TRUE); 01383 #endif 01384 01385 LdrpReferenceLoadedDll(LdrpImageEntry); 01386 01387 // 01388 // Lock the loaded DLLs to prevent dlls that back link to the exe to 01389 // cause problems when they are unloaded. 01390 // 01391 01392 { 01393 PLDR_DATA_TABLE_ENTRY Entry; 01394 PLIST_ENTRY Head,Next; 01395 01396 Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 01397 Next = Head->Flink; 01398 01399 while ( Next != Head ) { 01400 Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 01401 Entry->LoadCount = 0xffff; 01402 Next = Next->Flink; 01403 } 01404 } 01405 01406 // 01407 // All static DLLs are now pinned in place. No init routines have been run yet 01408 // 01409 01410 LdrpLdrDatabaseIsSetup = TRUE; 01411 01412 01413 if (!NT_SUCCESS(st)) { 01414 #if DBG 01415 DbgPrint("LDR: Initialize of image failed. Returning Error Status\n"); 01416 #endif 01417 return st; 01418 } 01419 01420 if ( !NT_SUCCESS(LdrpInitializeTls()) ) { 01421 return st; 01422 } 01423 01424 // 01425 // Now that all DLLs are loaded, if the process is being debugged, 01426 // signal the debugger with an exception 01427 // 01428 01429 if ( Peb->BeingDebugged ) { 01430 DbgBreakPoint(); 01431 ShowSnaps = (BOOLEAN)(FLG_SHOW_LDR_SNAPS & Peb->NtGlobalFlag); 01432 } 01433 01434 #if defined (_X86_) 01435 if ( LdrpNumberOfProcessors > 1 ) { 01436 LdrpValidateImageForMp(LdrDataTableEntry); 01437 } 01438 #endif 01439 01440 #if DBG 01441 if (LdrpDisplayLoadTime) { 01442 NtQueryPerformanceCounter(&InitbTime, NULL); 01443 } 01444 #endif // DBG 01445 01446 // 01447 // Get all application goo here (hacks, flags, etc.) 01448 // 01449 LdrQueryApplicationCompatibilityGoo(UnicodeImageName); 01450 01451 st = LdrpRunInitializeRoutines(Context); 01452 01453 if ( NT_SUCCESS(st) && Peb->PostProcessInitRoutine ) { 01454 (Peb->PostProcessInitRoutine)(); 01455 } 01456 01457 return st; 01458 } 01459 01460 01461 VOID 01462 LdrShutdownProcess ( 01463 VOID 01464 ) 01465 01466 /*++ 01467 01468 Routine Description: 01469 01470 This function is called by a process that is terminating cleanly. 01471 It's purpose is to call all of the processes DLLs to notify them 01472 that the process is detaching. 01473 01474 Arguments: 01475 01476 None 01477 01478 Return Value: 01479 01480 None. 01481 01482 --*/ 01483 01484 { 01485 PPEB Peb; 01486 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 01487 PDLL_INIT_ROUTINE InitRoutine; 01488 PLIST_ENTRY Next; 01489 01490 // 01491 // only unload once ! DllTerm routines might call exit process in fatal situations 01492 // 01493 01494 if ( LdrpShutdownInProgress ) { 01495 return; 01496 } 01497 01498 Peb = NtCurrentPeb(); 01499 01500 if (ShowSnaps) { 01501 UNICODE_STRING CommandLine; 01502 01503 CommandLine = Peb->ProcessParameters->CommandLine; 01504 if (!(Peb->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) { 01505 CommandLine.Buffer = (PWSTR)((PCHAR)CommandLine.Buffer + (ULONG_PTR)(Peb->ProcessParameters)); 01506 } 01507 01508 DbgPrint( "LDR: PID: 0x%x finished - '%wZ'\n", 01509 NtCurrentTeb()->ClientId.UniqueProcess, 01510 &CommandLine 01511 ); 01512 } 01513 01514 LdrpShutdownThreadId = NtCurrentTeb()->ClientId.UniqueThread; 01515 LdrpShutdownInProgress = TRUE; 01516 RtlEnterCriticalSection(&LoaderLock); 01517 01518 try { 01519 01520 // 01521 // check to see if the heap is locked. If so, do not do ANY 01522 // dll processing since it is very likely that a dll will need 01523 // to do heap operations, but that the heap is not in good shape. 01524 // ExitProcess called in a very active app can leave threads terminated 01525 // in the middle of the heap code or in other very bad places. Checking the 01526 // heap lock is a good indication that the process was very active when it 01527 // called ExitProcess 01528 // 01529 01530 if ( RtlpHeapIsLocked( RtlProcessHeap() )) { 01531 ; 01532 } 01533 else { 01534 if ( Peb->BeingDebugged ) { 01535 RtlValidateProcessHeaps(); 01536 } 01537 01538 // 01539 // Go in reverse order initialization order and build 01540 // the unload list 01541 // 01542 01543 Next = Peb->Ldr->InInitializationOrderModuleList.Blink; 01544 while ( Next != &Peb->Ldr->InInitializationOrderModuleList) { 01545 LdrDataTableEntry 01546 = (PLDR_DATA_TABLE_ENTRY) 01547 (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks)); 01548 01549 Next = Next->Blink; 01550 01551 // 01552 // Walk through the entire list looking for 01553 // entries. For each entry, that has an init 01554 // routine, call it. 01555 // 01556 01557 if (Peb->ImageBaseAddress != LdrDataTableEntry->DllBase) { 01558 InitRoutine = (PDLL_INIT_ROUTINE)LdrDataTableEntry->EntryPoint; 01559 if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) { 01560 if (LdrDataTableEntry->Flags) { 01561 if ( LdrDataTableEntry->TlsIndex ) { 01562 LdrpCallTlsInitializers(LdrDataTableEntry->DllBase,DLL_PROCESS_DETACH); 01563 } 01564 01565 #if defined (WX86) 01566 if (!Wx86ProcessInit || 01567 LdrpRunWx86DllEntryPoint(InitRoutine, 01568 NULL, 01569 LdrDataTableEntry->DllBase, 01570 DLL_PROCESS_DETACH, 01571 (PVOID)1 01572 ) == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) 01573 #endif 01574 { 01575 LdrpCallInitRoutine(InitRoutine, 01576 LdrDataTableEntry->DllBase, 01577 DLL_PROCESS_DETACH, 01578 (PVOID)1); 01579 } 01580 01581 } 01582 } 01583 } 01584 } 01585 01586 // 01587 // If the image has tls than call its initializers 01588 // 01589 01590 if ( LdrpImageHasTls ) { 01591 LdrpCallTlsInitializers(NtCurrentPeb()->ImageBaseAddress,DLL_PROCESS_DETACH); 01592 } 01593 } 01594 01595 } finally { 01596 RtlLeaveCriticalSection(&LoaderLock); 01597 } 01598 01599 } 01600 01601 VOID 01602 LdrShutdownThread ( 01603 VOID 01604 ) 01605 01606 /*++ 01607 01608 Routine Description: 01609 01610 This function is called by a thread that is terminating cleanly. 01611 It's purpose is to call all of the processes DLLs to notify them 01612 that the thread is detaching. 01613 01614 Arguments: 01615 01616 None 01617 01618 Return Value: 01619 01620 None. 01621 01622 --*/ 01623 01624 { 01625 PPEB Peb; 01626 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 01627 PDLL_INIT_ROUTINE InitRoutine; 01628 PLIST_ENTRY Next; 01629 01630 Peb = NtCurrentPeb(); 01631 01632 RtlEnterCriticalSection(&LoaderLock); 01633 01634 try { 01635 01636 01637 // 01638 // Go in reverse order initialization order and build 01639 // the unload list 01640 // 01641 01642 Next = Peb->Ldr->InInitializationOrderModuleList.Blink; 01643 while ( Next != &Peb->Ldr->InInitializationOrderModuleList) { 01644 LdrDataTableEntry 01645 = (PLDR_DATA_TABLE_ENTRY) 01646 (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks)); 01647 01648 Next = Next->Blink; 01649 01650 // 01651 // Walk through the entire list looking for 01652 // entries. For each entry, that has an init 01653 // routine, call it. 01654 // 01655 01656 if (Peb->ImageBaseAddress != LdrDataTableEntry->DllBase) { 01657 if ( !(LdrDataTableEntry->Flags & LDRP_DONT_CALL_FOR_THREADS)) { 01658 InitRoutine = (PDLL_INIT_ROUTINE)LdrDataTableEntry->EntryPoint; 01659 if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) { 01660 if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) { 01661 if ( LdrDataTableEntry->TlsIndex ) { 01662 LdrpCallTlsInitializers(LdrDataTableEntry->DllBase,DLL_THREAD_DETACH); 01663 } 01664 01665 #if defined (WX86) 01666 if (!Wx86ProcessInit || 01667 LdrpRunWx86DllEntryPoint(InitRoutine, 01668 NULL, 01669 LdrDataTableEntry->DllBase, 01670 DLL_THREAD_DETACH, 01671 NULL 01672 ) == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) 01673 #endif 01674 { 01675 LdrpCallInitRoutine(InitRoutine, 01676 LdrDataTableEntry->DllBase, 01677 DLL_THREAD_DETACH, 01678 NULL); 01679 } 01680 } 01681 } 01682 } 01683 } 01684 } 01685 01686 // 01687 // If the image has tls than call its initializers 01688 // 01689 01690 if ( LdrpImageHasTls ) { 01691 LdrpCallTlsInitializers(NtCurrentPeb()->ImageBaseAddress,DLL_THREAD_DETACH); 01692 } 01693 LdrpFreeTls(); 01694 01695 } finally { 01696 01697 RtlLeaveCriticalSection(&LoaderLock); 01698 } 01699 } 01700 01701 VOID 01702 LdrpInitializeThread( 01703 IN PCONTEXT Context 01704 ) 01705 01706 /*++ 01707 01708 Routine Description: 01709 01710 This function is called by a thread that is terminating cleanly. 01711 It's purpose is to call all of the processes DLLs to notify them 01712 that the thread is detaching. 01713 01714 Arguments: 01715 01716 Context - Context that will be restored after loader initializes. 01717 01718 Return Value: 01719 01720 None. 01721 01722 --*/ 01723 01724 { 01725 PPEB Peb; 01726 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 01727 PDLL_INIT_ROUTINE InitRoutine; 01728 PLIST_ENTRY Next; 01729 01730 Peb = NtCurrentPeb(); 01731 01732 if ( LdrpShutdownInProgress ) { 01733 return; 01734 } 01735 01736 LdrpAllocateTls(); 01737 01738 Next = Peb->Ldr->InMemoryOrderModuleList.Flink; 01739 while (Next != &Peb->Ldr->InMemoryOrderModuleList) { 01740 LdrDataTableEntry 01741 = (PLDR_DATA_TABLE_ENTRY) 01742 (CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)); 01743 01744 // 01745 // Walk through the entire list looking for 01746 // entries. For each entry, that has an init 01747 // routine, call it. 01748 // 01749 if (Peb->ImageBaseAddress != LdrDataTableEntry->DllBase) { 01750 if ( !(LdrDataTableEntry->Flags & LDRP_DONT_CALL_FOR_THREADS)) { 01751 InitRoutine = (PDLL_INIT_ROUTINE)LdrDataTableEntry->EntryPoint; 01752 if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) { 01753 if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) { 01754 if ( LdrDataTableEntry->TlsIndex ) { 01755 if ( !LdrpShutdownInProgress ) { 01756 LdrpCallTlsInitializers(LdrDataTableEntry->DllBase,DLL_THREAD_ATTACH); 01757 } 01758 } 01759 01760 #if defined (WX86) 01761 if (!Wx86ProcessInit || 01762 LdrpRunWx86DllEntryPoint(InitRoutine, 01763 NULL, 01764 LdrDataTableEntry->DllBase, 01765 DLL_THREAD_ATTACH, 01766 NULL 01767 ) == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) 01768 #endif 01769 { 01770 if ( !LdrpShutdownInProgress ) { 01771 LdrpCallInitRoutine(InitRoutine, 01772 LdrDataTableEntry->DllBase, 01773 DLL_THREAD_ATTACH, 01774 NULL); 01775 } 01776 } 01777 } 01778 } 01779 } 01780 } 01781 Next = Next->Flink; 01782 } 01783 01784 // 01785 // If the image has tls than call its initializers 01786 // 01787 01788 if ( LdrpImageHasTls && !LdrpShutdownInProgress ) { 01789 LdrpCallTlsInitializers(NtCurrentPeb()->ImageBaseAddress,DLL_THREAD_ATTACH); 01790 } 01791 01792 } 01793 01794 01795 NTSTATUS 01796 LdrQueryImageFileExecutionOptions( 01797 IN PUNICODE_STRING ImagePathName, 01798 IN PWSTR OptionName, 01799 IN ULONG Type, 01800 OUT PVOID Buffer, 01801 IN ULONG BufferSize, 01802 OUT PULONG ResultSize OPTIONAL 01803 ) 01804 { 01805 BOOLEAN bNeedToFree=FALSE; 01806 NTSTATUS Status; 01807 UNICODE_STRING UnicodeString; 01808 PWSTR pw; 01809 OBJECT_ATTRIBUTES ObjectAttributes; 01810 HANDLE KeyHandle; 01811 UNICODE_STRING KeyPath; 01812 WCHAR KeyPathBuffer[ DOS_MAX_COMPONENT_LENGTH + 100 ]; 01813 ULONG KeyValueBuffer[ 256 ]; 01814 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; 01815 ULONG AllocLength; 01816 ULONG ResultLength; 01817 01818 KeyPath.Buffer = KeyPathBuffer; 01819 KeyPath.Length = 0; 01820 KeyPath.MaximumLength = sizeof( KeyPathBuffer ); 01821 01822 RtlAppendUnicodeToString( &KeyPath, 01823 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\" 01824 ); 01825 01826 UnicodeString = *ImagePathName; 01827 pw = (PWSTR)((PCHAR)UnicodeString.Buffer + UnicodeString.Length); 01828 UnicodeString.MaximumLength = UnicodeString.Length; 01829 while (UnicodeString.Length != 0) { 01830 if (pw[ -1 ] == OBJ_NAME_PATH_SEPARATOR) { 01831 break; 01832 } 01833 pw--; 01834 UnicodeString.Length -= sizeof( *pw ); 01835 } 01836 UnicodeString.Buffer = pw; 01837 UnicodeString.Length = UnicodeString.MaximumLength - UnicodeString.Length; 01838 01839 RtlAppendUnicodeStringToString( &KeyPath, &UnicodeString ); 01840 01841 InitializeObjectAttributes( &ObjectAttributes, 01842 &KeyPath, 01843 OBJ_CASE_INSENSITIVE, 01844 NULL, 01845 NULL 01846 ); 01847 01848 Status = NtOpenKey( &KeyHandle, 01849 GENERIC_READ, 01850 &ObjectAttributes 01851 ); 01852 01853 if (!NT_SUCCESS( Status )) { 01854 return Status; 01855 } 01856 01857 RtlInitUnicodeString( &UnicodeString, OptionName ); 01858 KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyValueBuffer; 01859 Status = NtQueryValueKey( KeyHandle, 01860 &UnicodeString, 01861 KeyValuePartialInformation, 01862 KeyValueInformation, 01863 sizeof( KeyValueBuffer ), 01864 &ResultLength 01865 ); 01866 if (Status == STATUS_BUFFER_OVERFLOW) { 01867 // 01868 // This function can be called before the process heap gets created 01869 // therefore we need to protect against this case. The majority of the 01870 // code will not hit this code path because they read just strings 01871 // containing hex numbers and for this the size of KeyValueBuffer is 01872 // more than sufficient. 01873 // 01874 01875 if (RtlProcessHeap()) { 01876 01877 AllocLength = sizeof( *KeyValueInformation ) + 01878 KeyValueInformation->DataLength; 01879 KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) 01880 RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TEMP_TAG ), AllocLength); 01881 01882 if (KeyValueInformation == NULL) { 01883 Status = STATUS_NO_MEMORY; 01884 } 01885 else { 01886 bNeedToFree = TRUE; 01887 Status = NtQueryValueKey( KeyHandle, 01888 &UnicodeString, 01889 KeyValuePartialInformation, 01890 KeyValueInformation, 01891 AllocLength, 01892 &ResultLength 01893 ); 01894 } 01895 } 01896 else { 01897 01898 Status = STATUS_NO_MEMORY; 01899 } 01900 } 01901 01902 if (NT_SUCCESS( Status )) { 01903 if (KeyValueInformation->Type == REG_BINARY) { 01904 if ((Buffer) && 01905 (KeyValueInformation->DataLength <= BufferSize)) { 01906 RtlMoveMemory( Buffer, &KeyValueInformation->Data, KeyValueInformation->DataLength); 01907 } 01908 else { 01909 Status = STATUS_BUFFER_OVERFLOW; 01910 } 01911 if (ARGUMENT_PRESENT( ResultSize )) { 01912 *ResultSize = KeyValueInformation->DataLength; 01913 } 01914 } 01915 else if (KeyValueInformation->Type == REG_DWORD) { 01916 01917 if (Type != REG_DWORD) { 01918 Status = STATUS_OBJECT_TYPE_MISMATCH; 01919 } 01920 else { 01921 if ((Buffer) 01922 && (BufferSize == sizeof(ULONG)) 01923 && (KeyValueInformation->DataLength == BufferSize)) { 01924 01925 RtlMoveMemory( Buffer, &KeyValueInformation->Data, KeyValueInformation->DataLength); 01926 } 01927 else { 01928 Status = STATUS_BUFFER_OVERFLOW; 01929 } 01930 01931 if (ARGUMENT_PRESENT( ResultSize )) { 01932 *ResultSize = KeyValueInformation->DataLength; 01933 } 01934 } 01935 } 01936 else if (KeyValueInformation->Type != REG_SZ) { 01937 Status = STATUS_OBJECT_TYPE_MISMATCH; 01938 } 01939 else { 01940 if (Type == REG_DWORD) { 01941 if (BufferSize != sizeof( ULONG )) { 01942 BufferSize = 0; 01943 Status = STATUS_INFO_LENGTH_MISMATCH; 01944 } 01945 else { 01946 UnicodeString.Buffer = (PWSTR)&KeyValueInformation->Data; 01947 UnicodeString.Length = (USHORT) 01948 (KeyValueInformation->DataLength - sizeof( UNICODE_NULL )); 01949 UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength; 01950 Status = RtlUnicodeStringToInteger( &UnicodeString, 0, (PULONG)Buffer ); 01951 } 01952 } 01953 else { 01954 if (KeyValueInformation->DataLength > BufferSize) { 01955 Status = STATUS_BUFFER_OVERFLOW; 01956 } 01957 else { 01958 BufferSize = KeyValueInformation->DataLength; 01959 } 01960 01961 RtlMoveMemory( Buffer, &KeyValueInformation->Data, BufferSize ); 01962 } 01963 01964 if (ARGUMENT_PRESENT( ResultSize )) { 01965 *ResultSize = BufferSize; 01966 } 01967 } 01968 } 01969 01970 if (bNeedToFree) 01971 RtlFreeHeap(RtlProcessHeap(), 0, KeyValueInformation); 01972 NtClose( KeyHandle ); 01973 return Status; 01974 } 01975 01976 01977 NTSTATUS 01978 LdrpInitializeTls( 01979 VOID 01980 ) 01981 { 01982 PLDR_DATA_TABLE_ENTRY Entry; 01983 PLIST_ENTRY Head,Next; 01984 PIMAGE_TLS_DIRECTORY TlsImage; 01985 PLDRP_TLS_ENTRY TlsEntry; 01986 ULONG TlsSize; 01987 BOOLEAN FirstTimeThru = TRUE; 01988 01989 InitializeListHead(&LdrpTlsList); 01990 01991 // 01992 // Walk through the loaded modules an look for TLS. If we find TLS, 01993 // lock in the module and add to the TLS chain. 01994 // 01995 01996 Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 01997 Next = Head->Flink; 01998 01999 while ( Next != Head ) { 02000 Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 02001 Next = Next->Flink; 02002 02003 TlsImage = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData( 02004 Entry->DllBase, 02005 TRUE, 02006 IMAGE_DIRECTORY_ENTRY_TLS, 02007 &TlsSize 02008 ); 02009 02010 // 02011 // mark whether or not the image file has TLS 02012 // 02013 02014 if ( FirstTimeThru ) { 02015 FirstTimeThru = FALSE; 02016 if ( TlsImage && !LdrpImageHasTls) { 02017 RtlpSerializeHeap( RtlProcessHeap() ); 02018 LdrpImageHasTls = TRUE; 02019 } 02020 } 02021 02022 if ( TlsImage ) { 02023 if (ShowSnaps) { 02024 DbgPrint( "LDR: Tls Found in %wZ at %lx\n", 02025 &Entry->BaseDllName, 02026 TlsImage 02027 ); 02028 } 02029 02030 TlsEntry = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( TLS_TAG ),sizeof(*TlsEntry)); 02031 if ( !TlsEntry ) { 02032 return STATUS_NO_MEMORY; 02033 } 02034 02035 // 02036 // Since this DLL has TLS, lock it in 02037 // 02038 02039 Entry->LoadCount = (USHORT)0xffff; 02040 02041 // 02042 // Mark this as having thread local storage 02043 // 02044 02045 Entry->TlsIndex = (USHORT)0xffff; 02046 02047 TlsEntry->Tls = *TlsImage; 02048 InsertTailList(&LdrpTlsList,&TlsEntry->Links); 02049 02050 // 02051 // Update the index for this dll's thread local storage 02052 // 02053 02054 02055 *(PLONG)TlsEntry->Tls.AddressOfIndex = LdrpNumberOfTlsEntries; 02056 TlsEntry->Tls.Characteristics = LdrpNumberOfTlsEntries++; 02057 } 02058 } 02059 02060 // 02061 // We now have walked through all static DLLs and know 02062 // all DLLs that reference thread local storage. Now we 02063 // just have to allocate the thread local storage for the current 02064 // thread and for all subsequent threads 02065 // 02066 02067 return LdrpAllocateTls(); 02068 } 02069 02070 NTSTATUS 02071 LdrpAllocateTls( 02072 VOID 02073 ) 02074 { 02075 PTEB Teb; 02076 PLIST_ENTRY Head, Next; 02077 PLDRP_TLS_ENTRY TlsEntry; 02078 PVOID *TlsVector; 02079 02080 Teb = NtCurrentTeb(); 02081 02082 // 02083 // Allocate the array of thread local storage pointers 02084 // 02085 02086 if ( LdrpNumberOfTlsEntries ) { 02087 TlsVector = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( TLS_TAG ),sizeof(PVOID)*LdrpNumberOfTlsEntries); 02088 if ( !TlsVector ) { 02089 return STATUS_NO_MEMORY; 02090 } 02091 02092 Teb->ThreadLocalStoragePointer = TlsVector; 02093 Head = &LdrpTlsList; 02094 Next = Head->Flink; 02095 02096 while ( Next != Head ) { 02097 TlsEntry = CONTAINING_RECORD(Next, LDRP_TLS_ENTRY, Links); 02098 Next = Next->Flink; 02099 TlsVector[TlsEntry->Tls.Characteristics] = RtlAllocateHeap( 02100 RtlProcessHeap(), 02101 MAKE_TAG( TLS_TAG ), 02102 TlsEntry->Tls.EndAddressOfRawData - TlsEntry->Tls.StartAddressOfRawData 02103 ); 02104 if (!TlsVector[TlsEntry->Tls.Characteristics] ) { 02105 return STATUS_NO_MEMORY; 02106 } 02107 02108 if (ShowSnaps) { 02109 DbgPrint("LDR: TlsVector %x Index %d = %x copied from %x to %x\n", 02110 TlsVector, 02111 TlsEntry->Tls.Characteristics, 02112 &TlsVector[TlsEntry->Tls.Characteristics], 02113 TlsEntry->Tls.StartAddressOfRawData, 02114 TlsVector[TlsEntry->Tls.Characteristics] 02115 ); 02116 } 02117 02118 RtlCopyMemory( 02119 TlsVector[TlsEntry->Tls.Characteristics], 02120 (PVOID)TlsEntry->Tls.StartAddressOfRawData, 02121 TlsEntry->Tls.EndAddressOfRawData - TlsEntry->Tls.StartAddressOfRawData 02122 ); 02123 02124 // 02125 // Do the TLS Callouts 02126 // 02127 02128 } 02129 } 02130 return STATUS_SUCCESS; 02131 } 02132 02133 VOID 02134 LdrpFreeTls( 02135 VOID 02136 ) 02137 { 02138 PTEB Teb; 02139 PLIST_ENTRY Head, Next; 02140 PLDRP_TLS_ENTRY TlsEntry; 02141 PVOID *TlsVector; 02142 02143 Teb = NtCurrentTeb(); 02144 02145 TlsVector = Teb->ThreadLocalStoragePointer; 02146 02147 if ( TlsVector ) { 02148 Head = &LdrpTlsList; 02149 Next = Head->Flink; 02150 02151 while ( Next != Head ) { 02152 TlsEntry = CONTAINING_RECORD(Next, LDRP_TLS_ENTRY, Links); 02153 Next = Next->Flink; 02154 02155 // 02156 // Do the TLS callouts 02157 // 02158 02159 if ( TlsVector[TlsEntry->Tls.Characteristics] ) { 02160 RtlFreeHeap( 02161 RtlProcessHeap(), 02162 0, 02163 TlsVector[TlsEntry->Tls.Characteristics] 02164 ); 02165 02166 } 02167 } 02168 02169 RtlFreeHeap( 02170 RtlProcessHeap(), 02171 0, 02172 TlsVector 02173 ); 02174 } 02175 } 02176 02177 VOID 02178 LdrpCallTlsInitializers( 02179 PVOID DllBase, 02180 ULONG Reason 02181 ) 02182 { 02183 PIMAGE_TLS_DIRECTORY TlsImage; 02184 ULONG TlsSize; 02185 PIMAGE_TLS_CALLBACK *CallBackArray; 02186 PIMAGE_TLS_CALLBACK InitRoutine; 02187 02188 TlsImage = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData( 02189 DllBase, 02190 TRUE, 02191 IMAGE_DIRECTORY_ENTRY_TLS, 02192 &TlsSize 02193 ); 02194 02195 02196 try { 02197 if ( TlsImage ) { 02198 CallBackArray = (PIMAGE_TLS_CALLBACK *)TlsImage->AddressOfCallBacks; 02199 if ( CallBackArray ) { 02200 if (ShowSnaps) { 02201 DbgPrint( "LDR: Tls Callbacks Found. Imagebase %lx Tls %lx CallBacks %lx\n", 02202 DllBase, 02203 TlsImage, 02204 CallBackArray 02205 ); 02206 } 02207 02208 while(*CallBackArray){ 02209 InitRoutine = *CallBackArray++; 02210 02211 if (ShowSnaps) { 02212 DbgPrint( "LDR: Calling Tls Callback Imagebase %lx Function %lx\n", 02213 DllBase, 02214 InitRoutine 02215 ); 02216 } 02217 02218 #if defined (WX86) 02219 if (!Wx86ProcessInit || 02220 LdrpRunWx86DllEntryPoint( 02221 (PDLL_INIT_ROUTINE)InitRoutine, 02222 NULL, 02223 DllBase, 02224 Reason, 02225 NULL 02226 ) == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) 02227 #endif 02228 { 02229 LdrpCallInitRoutine((PDLL_INIT_ROUTINE)InitRoutine, 02230 DllBase, 02231 Reason, 02232 0); 02233 } 02234 02235 } 02236 } 02237 } 02238 } 02239 except (EXCEPTION_EXECUTE_HANDLER) { 02240 ; 02241 } 02242 } 02243 02244 02245 02246 ULONG GetNextCommaValue( IN OUT WCHAR **p, IN OUT ULONG *len ) 02247 { 02248 ULONG Number = 0; 02249 02250 while (*len && (UNICODE_NULL != **p) && **p != L',') 02251 { 02252 // Let's ignore spaces 02253 if ( L' ' != **p ) 02254 { 02255 Number = (Number * 10) + ( (ULONG)**p - L'0' ); 02256 } 02257 02258 (*p)++; 02259 (*len)--; 02260 } 02261 02262 // 02263 // If we're at a comma, get past it for the next call 02264 // 02265 if ( L',' == **p ) 02266 { 02267 (*p)++; 02268 (*len)--; 02269 } 02270 02271 return Number; 02272 } 02273 02274 02275 02276 VOID 02277 LdrQueryApplicationCompatibilityGoo( 02278 IN PUNICODE_STRING UnicodeImageName 02279 ) 02280 02281 /*++ 02282 02283 Routine Description: 02284 02285 This function is called by LdrpInitialize after its initialized the 02286 process. It's purpose is to query any application specific flags, 02287 hacks, etc. If any app specific information is found, its hung off 02288 the PEB for other components to test against. 02289 02290 Besides setting hanging the AppCompatInfo struct off the PEB, the 02291 only other action that will occur in here is setting OS version 02292 numbers in the PEB if the appropriate Version lie app flag is set. 02293 02294 Arguments: 02295 02296 UnicodeImageName - Actual image name (including path) 02297 02298 Return Value: 02299 02300 None. 02301 02302 --*/ 02303 02304 { 02305 02306 PPEB Peb; 02307 PVOID ResourceInfo; 02308 ULONG TotalGooLength; 02309 ULONG AppCompatLength; 02310 ULONG ResultSize; 02311 ULONG ResourceSize; 02312 ULONG InputCompareLength; 02313 ULONG OutputCompareLength; 02314 LANGID LangId; 02315 NTSTATUS st; 02316 BOOLEAN bImageContainsVersionResourceInfo; 02317 ULONG_PTR IdPath[3]; 02318 APP_COMPAT_GOO LocalAppCompatGoo; 02319 PAPP_COMPAT_GOO AppCompatGoo; 02320 PAPP_COMPAT_INFO AppCompatInfo; 02321 PAPP_VARIABLE_INFO AppVariableInfo; 02322 PPRE_APP_COMPAT_INFO AppCompatEntry; 02323 PIMAGE_RESOURCE_DATA_ENTRY DataEntry; 02324 PEFFICIENTOSVERSIONINFOEXW OSVerInfo; 02325 UNICODE_STRING EnvName; 02326 UNICODE_STRING EnvValue; 02327 WCHAR *NewCSDString; 02328 WCHAR TempString[ 128 ]; // is the size of szCSDVersion in OSVERSIONINFOW 02329 BOOLEAN fNewCSDVersionBuffer = FALSE; 02330 02331 struct { 02332 USHORT TotalSize; 02333 USHORT DataSize; 02334 USHORT Type; 02335 WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode nul 02336 } *Resource; 02337 02338 02339 // 02340 // Check execution options to see if there's any Goo for this app. 02341 // We purposely feed a small struct to LdrQueryImageFileExecOptions, 02342 // so that it can come back with success/failure, and if success we see 02343 // how much we need to alloc. As the results coming back will be of 02344 // variable length. 02345 // 02346 Peb = NtCurrentPeb(); 02347 Peb->AppCompatInfo = NULL; 02348 RtlInitUnicodeString(&Peb->CSDVersion, NULL); 02349 02350 st = LdrQueryImageFileExecutionOptions( UnicodeImageName, 02351 L"ApplicationGoo", 02352 REG_BINARY, 02353 &LocalAppCompatGoo, 02354 sizeof(APP_COMPAT_GOO), 02355 &ResultSize 02356 ); 02357 02358 // 02359 // If there's an entry there, we're guaranteed to get overflow error. 02360 // 02361 if (st == STATUS_BUFFER_OVERFLOW) { 02362 02363 // 02364 // Something is there, alloc memory for the "Pre" Goo struct right now 02365 // 02366 AppCompatGoo = \ 02367 RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, ResultSize); 02368 02369 if (!AppCompatGoo) { 02370 return; 02371 } 02372 02373 // 02374 // Now that we've got the memory, hit it again 02375 // 02376 st = LdrQueryImageFileExecutionOptions( UnicodeImageName, 02377 L"ApplicationGoo", 02378 REG_BINARY, 02379 AppCompatGoo, 02380 ResultSize, 02381 &ResultSize 02382 ); 02383 02384 if (!NT_SUCCESS( st )) { 02385 RtlFreeHeap(Peb->ProcessHeap, 0, AppCompatGoo); 02386 return; 02387 } 02388 02389 // 02390 // Got a hit on this key, however we don't know fer sure that its 02391 // an exact match. There could be multiple App Compat entries 02392 // within this Goo. So we get the version resource information out 02393 // of the Image hdr (if avail) and later we compare it against all of 02394 // the entries found within the Goo hoping for a match. 02395 // 02396 // Need Language Id in order to query the resource info 02397 // 02398 bImageContainsVersionResourceInfo = FALSE; 02399 // NtQueryDefaultUILanguage(&LangId); 02400 IdPath[0] = 16; // RT_VERSION 02401 IdPath[1] = 1; // VS_VERSION_INFO 02402 IdPath[2] = 0; // LangId; 02403 02404 // 02405 // Search for version resource information 02406 // 02407 try { 02408 st = LdrpSearchResourceSection_U( 02409 Peb->ImageBaseAddress, 02410 IdPath, 02411 3, 02412 FALSE, 02413 FALSE, // TRUE, 02414 &DataEntry 02415 ); 02416 02417 } except(EXCEPTION_EXECUTE_HANDLER) { 02418 st = STATUS_UNSUCCESSFUL; 02419 } 02420 02421 if (NT_SUCCESS( st )) { 02422 02423 // 02424 // Give us a pointer to the resource information 02425 // 02426 try { 02427 st = LdrpAccessResourceData( 02428 Peb->ImageBaseAddress, 02429 DataEntry, 02430 &Resource, 02431 &ResourceSize 02432 ); 02433 02434 } except(EXCEPTION_EXECUTE_HANDLER) { 02435 st = STATUS_UNSUCCESSFUL; 02436 } 02437 02438 if (NT_SUCCESS( st )) { 02439 bImageContainsVersionResourceInfo = TRUE; 02440 } 02441 02442 } 02443 02444 // 02445 // Now that we either have (or have not) the version resource info, 02446 // bounce down each app compat entry looking for a match. If there 02447 // wasn't any version resource info in the image hdr, its going to be 02448 // an automatic match to an entry that also doesn't have anything for 02449 // its version resource info. Obviously there can be only one of these 02450 // "empty" entries within the Goo (as the first one will always be 02451 // matched first. 02452 // 02453 st = STATUS_SUCCESS; 02454 AppCompatEntry = AppCompatGoo->AppCompatEntry; 02455 TotalGooLength = \ 02456 AppCompatGoo->dwTotalGooSize - sizeof(AppCompatGoo->dwTotalGooSize); 02457 while (TotalGooLength) { 02458 02459 try { 02460 02461 // 02462 // Compare what we're told to by the resource info size. The 02463 // ResourceInfo (if avail) is directly behind the AppCompatEntry 02464 // 02465 InputCompareLength = AppCompatEntry->dwResourceInfoSize; 02466 ResourceInfo = AppCompatEntry + 1; 02467 if (bImageContainsVersionResourceInfo) { 02468 02469 if (InputCompareLength > Resource->TotalSize) { 02470 InputCompareLength = Resource->TotalSize; 02471 } 02472 02473 OutputCompareLength = \ 02474 (ULONG)RtlCompareMemory( 02475 ResourceInfo, 02476 Resource, 02477 InputCompareLength 02478 ); 02479 02480 } 02481 02482 // 02483 // In this case, we don't have any version resource info in 02484 // the image header, so set OutputCompareLength to zero. 02485 // If InputCompareLength was set to zero (above) due to the 02486 // AppCompatEntry also having no version resource info, then 02487 // the test will succeed (below) and we've found our match. 02488 // Otherwise, this is not the same app and it won't be a match. 02489 // 02490 else { 02491 OutputCompareLength = 0; 02492 } 02493 02494 } except(EXCEPTION_EXECUTE_HANDLER) { 02495 st = STATUS_UNSUCCESSFUL; 02496 } 02497 02498 if ((!NT_SUCCESS( st )) || 02499 (InputCompareLength != OutputCompareLength)) { 02500 02501 // 02502 // Wasn't a match for some reason or another, goto next entry 02503 // 02504 TotalGooLength -= AppCompatEntry->dwEntryTotalSize; 02505 (PUCHAR) AppCompatEntry += AppCompatEntry->dwEntryTotalSize; 02506 continue; 02507 } 02508 02509 // 02510 // We're a match!!! Now we have to create the final "Post" 02511 // app compat structure that will be used by everyone to follow. 02512 // This guy hangs off the Peb and it doesn't have the resource 02513 // info still lying around in there. 02514 // 02515 AppCompatLength = AppCompatEntry->dwEntryTotalSize; 02516 AppCompatLength -= AppCompatEntry->dwResourceInfoSize; 02517 Peb->AppCompatInfo = \ 02518 RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, AppCompatLength); 02519 02520 if (!Peb->AppCompatInfo) { 02521 break; 02522 } 02523 02524 AppCompatInfo = Peb->AppCompatInfo; 02525 AppCompatInfo->dwTotalSize = AppCompatLength; 02526 02527 // 02528 // Copy what was beyond the resource info to near the top starting at 02529 // the Application compat flags. 02530 // 02531 RtlMoveMemory( 02532 &AppCompatInfo->CompatibilityFlags, 02533 (PUCHAR) ResourceInfo + AppCompatEntry->dwResourceInfoSize, 02534 AppCompatInfo->dwTotalSize - FIELD_OFFSET(APP_COMPAT_INFO, CompatibilityFlags) 02535 ); 02536 02537 // 02538 // Now that we've created the "Post" app compat info struct to be 02539 // used by everyone, we need to check if version lying for this 02540 // app is requested. If so, we need to stuff the Peb right now. 02541 // 02542 if (AppCompatInfo->CompatibilityFlags.QuadPart & KACF_VERSIONLIE) { 02543 02544 // 02545 // Find the variable version lie struct somwhere within 02546 // 02547 if( STATUS_SUCCESS != LdrFindAppCompatVariableInfo(AVT_OSVERSIONINFO, &AppVariableInfo)) { 02548 break; 02549 } 02550 02551 // 02552 // The variable length information itself comes at the end 02553 // of the normal struct and could be of any aribitrary length 02554 // 02555 AppVariableInfo++; 02556 OSVerInfo = (PEFFICIENTOSVERSIONINFOEXW) AppVariableInfo; 02557 Peb->OSMajorVersion = OSVerInfo->dwMajorVersion; 02558 Peb->OSMinorVersion = OSVerInfo->dwMinorVersion; 02559 Peb->OSBuildNumber = (USHORT) OSVerInfo->dwBuildNumber; 02560 Peb->OSCSDVersion = (OSVerInfo->wServicePackMajor << 8) & 0xFF00; 02561 Peb->OSCSDVersion |= OSVerInfo->wServicePackMinor; 02562 Peb->OSPlatformId = OSVerInfo->dwPlatformId; 02563 02564 Peb->CSDVersion.Length = (USHORT)wcslen(&OSVerInfo->szCSDVersion[0])*sizeof(WCHAR); 02565 Peb->CSDVersion.MaximumLength = Peb->CSDVersion.Length + sizeof(WCHAR); 02566 Peb->CSDVersion.Buffer = \ 02567 RtlAllocateHeap( 02568 Peb->ProcessHeap, 02569 HEAP_ZERO_MEMORY, 02570 Peb->CSDVersion.MaximumLength 02571 ); 02572 02573 if (!Peb->CSDVersion.Buffer) { 02574 break; 02575 } 02576 wcscpy(Peb->CSDVersion.Buffer, &OSVerInfo->szCSDVersion[0]); 02577 fNewCSDVersionBuffer = TRUE; 02578 02579 } 02580 02581 break; 02582 02583 } 02584 02585 RtlFreeHeap(Peb->ProcessHeap, 0, AppCompatGoo); 02586 } 02587 02588 02589 // 02590 // Only look at the ENV stuff if haven't already gotten new version info from the registry 02591 // 02592 if ( FALSE == fNewCSDVersionBuffer ) 02593 { 02594 // 02595 // The format of this string is: 02596 // _COMPAT_VER_NNN = MajOSVer, MinOSVer, OSBldNum, MajCSD, MinCSD, PlatformID, CSDString 02597 // eg: _COMPAT_VER_NNN=4,0,1381,3,0,2,Service Pack 3 02598 // (for NT 4 SP3) 02599 02600 RtlInitUnicodeString(&EnvName, L"_COMPAT_VER_NNN"); 02601 02602 EnvValue.Buffer = TempString; 02603 EnvValue.Length = 0; 02604 EnvValue.MaximumLength = sizeof(TempString); 02605 02606 02607 st = RtlQueryEnvironmentVariable_U( 02608 NULL, 02609 &EnvName, 02610 &EnvValue 02611 ); 02612 02613 // 02614 // One of the possible error codes is BUFFER_TOO_SMALL - this indicates a 02615 // string that's wacko - they should not be larger than the size we define/expect 02616 // In this case, we'll ignore that string 02617 // 02618 if ( STATUS_SUCCESS == st ) 02619 { 02620 WCHAR *p = EnvValue.Buffer; 02621 WCHAR *NewSPString; 02622 ULONG len = EnvValue.Length / sizeof(WCHAR); // (Length is bytes, not chars) 02623 02624 // 02625 // Ok, someone wants different version info. 02626 // 02627 Peb->OSMajorVersion = GetNextCommaValue( &p, &len ); 02628 Peb->OSMinorVersion = GetNextCommaValue( &p, &len ); 02629 Peb->OSBuildNumber = (USHORT)GetNextCommaValue( &p, &len ); 02630 Peb->OSCSDVersion = (USHORT)(GetNextCommaValue( &p, &len )) << 8; 02631 Peb->OSCSDVersion |= (USHORT)GetNextCommaValue( &p, &len ); 02632 Peb->OSPlatformId = GetNextCommaValue( &p, &len ); 02633 02634 02635 // 02636 // Need to free the old buffer if there is one... 02637 // 02638 if ( fNewCSDVersionBuffer ) 02639 { 02640 RtlFreeHeap( Peb->ProcessHeap, 0, Peb->CSDVersion.Buffer ); 02641 Peb->CSDVersion.Buffer = NULL; 02642 } 02643 02644 if ( len ) 02645 { 02646 NewCSDString = \ 02647 RtlAllocateHeap( 02648 Peb->ProcessHeap, 02649 HEAP_ZERO_MEMORY, 02650 ( len + 1 ) * sizeof(WCHAR) 02651 ); 02652 02653 if ( NULL == NewCSDString ) 02654 { 02655 return; 02656 } 02657 02658 // 02659 // Now copy the string to memory that we'll keep 02660 // 02661 // We do a movemem here rather than a string copy because current comments in 02662 // RtlQueryEnvironmentVariable() indicate that in an edge case, we might not 02663 // have a trailing NULL - berniem 7/7/99 02664 // 02665 RtlMoveMemory( NewCSDString, p, len * sizeof(WCHAR) ); 02666 02667 } 02668 else 02669 { 02670 NewCSDString = NULL; 02671 } 02672 02673 RtlInitUnicodeString( &(Peb->CSDVersion), NewCSDString ); 02674 02675 } 02676 } 02677 02678 return; 02679 } 02680 02681 02682 NTSTATUS 02683 LdrFindAppCompatVariableInfo( 02684 IN ULONG dwTypeSeeking, 02685 OUT PAPP_VARIABLE_INFO *AppVariableInfo 02686 ) 02687 02688 /*++ 02689 02690 Routine Description: 02691 02692 This function is used to find a variable length struct by its type. 02693 The caller specifies what type its looking for and this function chews 02694 thru all the variable length structs to find it. If it does it returns 02695 the pointer and TRUE, else FALSE. 02696 02697 Arguments: 02698 02699 dwTypeSeeking - AVT that you are looking for 02700 02701 AppVariableInfo - pointer to pointer of variable info to be returned 02702 02703 Return Value: 02704 02705 TRUE or FALSE if entry is found 02706 02707 --*/ 02708 02709 { 02710 PPEB Peb; 02711 ULONG TotalSize; 02712 ULONG CurOffset; 02713 PAPP_VARIABLE_INFO pCurrentEntry; 02714 02715 Peb = NtCurrentPeb(); 02716 if (Peb->AppCompatInfo) { 02717 02718 // 02719 // Since we're not dealing with a fixed-size structure, TotalSize 02720 // will keep us from running off the end of the data list 02721 // 02722 TotalSize = ((PAPP_COMPAT_INFO) Peb->AppCompatInfo)->dwTotalSize; 02723 02724 // 02725 // The first variable structure (if there is one) will start 02726 // immediately after the fixed stuff 02727 // 02728 CurOffset = sizeof(APP_COMPAT_INFO); 02729 02730 while (CurOffset < TotalSize) { 02731 02732 pCurrentEntry = (PAPP_VARIABLE_INFO) ((PUCHAR)(Peb->AppCompatInfo) + CurOffset); 02733 02734 // 02735 // Have we found what we're looking for? 02736 // 02737 if (dwTypeSeeking == pCurrentEntry->dwVariableType) { 02738 *AppVariableInfo = pCurrentEntry; 02739 return (STATUS_SUCCESS); 02740 } 02741 02742 // 02743 // Let's go look at the next blob 02744 // 02745 CurOffset += (ULONG)(pCurrentEntry->dwVariableInfoSize); 02746 } 02747 02748 } 02749 02750 return (STATUS_NOT_FOUND); 02751 }

Generated on Sat May 15 19:40:37 2004 for test by doxygen 1.3.7