Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4927 lines
147 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ldrinit.c
  5. Abstract:
  6. This module implements loader initialization.
  7. Author:
  8. Mike O'Leary (mikeol) 26-Mar-1990
  9. Revision History:
  10. --*/
  11. #pragma warning(disable:4214) // bit field types other than int
  12. #pragma warning(disable:4201) // nameless struct/union
  13. #pragma warning(disable:4115) // named type definition in parentheses
  14. #pragma warning(disable:4127) // condition expression is constant
  15. #include <ntos.h>
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <heap.h>
  20. #include <heappage.h>
  21. #include <apcompat.h>
  22. #include "ldrp.h"
  23. #include <ctype.h>
  24. #include <windows.h>
  25. #if defined(_WIN64) || defined(BUILD_WOW6432)
  26. #include <wow64t.h>
  27. #endif
  28. #include <stktrace.h>
  29. #include "sxsp.h"
  30. BOOLEAN LdrpShutdownInProgress = FALSE;
  31. BOOLEAN LdrpImageHasTls = FALSE;
  32. BOOLEAN LdrpVerifyDlls = FALSE;
  33. BOOLEAN LdrpLdrDatabaseIsSetup = FALSE;
  34. BOOLEAN LdrpInLdrInit = FALSE;
  35. BOOLEAN LdrpShouldCreateStackTraceDb = FALSE;
  36. BOOLEAN ShowSnaps = FALSE;
  37. BOOLEAN ShowErrors = FALSE;
  38. EXTERN_C BOOLEAN g_SxsKeepActivationContextsAlive;
  39. EXTERN_C BOOLEAN g_SxsTrackReleaseStacks;
  40. EXTERN_C ULONG g_SxsMaxDeadActivationContexts;
  41. #if defined(_WIN64)
  42. PVOID Wow64Handle;
  43. ULONG UseWOW64;
  44. typedef VOID (*tWOW64LdrpInitialize)(IN PCONTEXT Context);
  45. tWOW64LdrpInitialize Wow64LdrpInitialize;
  46. PVOID Wow64PrepareForException;
  47. PVOID Wow64ApcRoutine;
  48. INVERTED_FUNCTION_TABLE LdrpInvertedFunctionTable = {
  49. 0, MAXIMUM_INVERTED_FUNCTION_TABLE_SIZE, FALSE};
  50. #endif
  51. #if defined(_WIN64) || defined(BUILD_WOW6432)
  52. ULONG NativePageSize;
  53. ULONG NativePageShift;
  54. #endif
  55. #define SLASH_SYSTEM32_SLASH L"\\system32\\"
  56. #define MSCOREE_DLL L"mscoree.dll"
  57. extern const WCHAR SlashSystem32SlashMscoreeDllWCharArray[] = SLASH_SYSTEM32_SLASH MSCOREE_DLL;
  58. extern const UNICODE_STRING SlashSystem32SlashMscoreeDllString =
  59. {
  60. sizeof(SlashSystem32SlashMscoreeDllWCharArray) - sizeof(SlashSystem32SlashMscoreeDllWCharArray[0]),
  61. sizeof(SlashSystem32SlashMscoreeDllWCharArray),
  62. (PWSTR)SlashSystem32SlashMscoreeDllWCharArray
  63. };
  64. extern const UNICODE_STRING SlashSystem32SlashString =
  65. {
  66. sizeof(SLASH_SYSTEM32_SLASH) - sizeof(SLASH_SYSTEM32_SLASH[0]),
  67. sizeof(SLASH_SYSTEM32_SLASH),
  68. (PWSTR)SlashSystem32SlashMscoreeDllWCharArray
  69. };
  70. extern const UNICODE_STRING MscoreeDllString =
  71. {
  72. sizeof(MSCOREE_DLL) - sizeof(MSCOREE_DLL[0]),
  73. sizeof(MSCOREE_DLL),
  74. (PWSTR)&SlashSystem32SlashMscoreeDllWCharArray[RTL_NUMBER_OF(SLASH_SYSTEM32_SLASH) - 1]
  75. };
  76. typedef NTSTATUS (*PCOR_VALIDATE_IMAGE)(PVOID *pImageBase, LPWSTR ImageName);
  77. typedef VOID (*PCOR_IMAGE_UNLOADING)(PVOID ImageBase);
  78. PVOID Cor20DllHandle;
  79. PCOR_VALIDATE_IMAGE CorValidateImage;
  80. PCOR_IMAGE_UNLOADING CorImageUnloading;
  81. PCOR_EXE_MAIN CorExeMain;
  82. DWORD CorImageCount;
  83. PVOID NtDllBase;
  84. extern const UNICODE_STRING NtDllName = RTL_CONSTANT_STRING(L"ntdll.dll");
  85. #define DLL_REDIRECTION_LOCAL_SUFFIX L".Local"
  86. extern ULONG RtlpDisableHeapLookaside; // defined in rtl\heap.c
  87. extern ULONG RtlpShutdownProcessFlags;
  88. extern void ShutDownEtwHandles();
  89. extern void CleanOnThreadExit();
  90. extern ULONG EtwpInitializeDll(void);
  91. extern void EtwpDeinitializeDll();
  92. #if defined (_X86_)
  93. void
  94. LdrpValidateImageForMp(
  95. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  96. );
  97. #endif
  98. PFNSE_INSTALLBEFOREINIT g_pfnSE_InstallBeforeInit;
  99. PFNSE_INSTALLAFTERINIT g_pfnSE_InstallAfterInit;
  100. PFNSE_DLLLOADED g_pfnSE_DllLoaded;
  101. PFNSE_DLLUNLOADED g_pfnSE_DllUnloaded;
  102. PFNSE_ISSHIMDLL g_pfnSE_IsShimDll;
  103. PFNSE_PROCESSDYING g_pfnSE_ProcessDying;
  104. PVOID g_pShimEngineModule;
  105. BOOLEAN g_LdrBreakOnLdrpInitializeProcessFailure;
  106. PEB_LDR_DATA PebLdr;
  107. PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
  108. #if DBG
  109. // Debug helpers to figure out where in LdrpInitializeProcess() things go south
  110. PCSTR g_LdrFunction;
  111. LONG g_LdrLine;
  112. #define LDRP_CHECKPOINT() { g_LdrFunction = __FUNCTION__; g_LdrLine = __LINE__; }
  113. #else
  114. #define LDRP_CHECKPOINT() /* nothing */
  115. #endif // DBG
  116. //
  117. // Defined in heappriv.h
  118. //
  119. VOID
  120. RtlDetectHeapLeaks (
  121. VOID
  122. );
  123. VOID
  124. LdrpInitializationFailure (
  125. IN NTSTATUS FailureCode
  126. );
  127. VOID
  128. LdrpRelocateStartContext (
  129. IN PCONTEXT Context,
  130. IN LONG_PTR Diff
  131. );
  132. NTSTATUS
  133. LdrpForkProcess (
  134. VOID
  135. );
  136. VOID
  137. LdrpInitializeThread (
  138. IN PCONTEXT Context
  139. );
  140. NTSTATUS
  141. LdrpOpenImageFileOptionsKey (
  142. IN PCUNICODE_STRING ImagePathName,
  143. IN BOOLEAN Wow64Path,
  144. OUT PHANDLE KeyHandle
  145. );
  146. VOID
  147. LdrpInitializeApplicationVerifierPackage (
  148. PCUNICODE_STRING UnicodeImageName,
  149. PPEB Peb,
  150. BOOLEAN EnabledSystemWide,
  151. BOOLEAN OptionsKeyPresent
  152. );
  153. BOOLEAN
  154. LdrpInitializeExecutionOptions (
  155. IN PCUNICODE_STRING UnicodeImageName,
  156. IN PPEB Peb
  157. );
  158. NTSTATUS
  159. LdrpQueryImageFileKeyOption (
  160. IN HANDLE KeyHandle,
  161. IN PCWSTR OptionName,
  162. IN ULONG Type,
  163. OUT PVOID Buffer,
  164. IN ULONG BufferSize,
  165. OUT PULONG ResultSize OPTIONAL
  166. );
  167. NTSTATUS
  168. LdrpTouchThreadStack (
  169. IN SIZE_T EnforcedStackCommit
  170. );
  171. NTSTATUS
  172. LdrpEnforceExecuteForCurrentThreadStack (
  173. VOID
  174. );
  175. NTSTATUS
  176. RtlpInitDeferredCriticalSection (
  177. VOID
  178. );
  179. VOID
  180. LdrQueryApplicationCompatibilityGoo (
  181. IN PCUNICODE_STRING UnicodeImageName,
  182. IN BOOLEAN ImageFileOptionsPresent
  183. );
  184. NTSTATUS
  185. LdrFindAppCompatVariableInfo (
  186. IN ULONG dwTypeSeeking,
  187. OUT PAPP_VARIABLE_INFO *AppVariableInfo
  188. );
  189. NTSTATUS
  190. LdrpSearchResourceSection_U (
  191. IN PVOID DllHandle,
  192. IN PULONG_PTR ResourceIdPath,
  193. IN ULONG ResourceIdPathLength,
  194. IN ULONG Flags,
  195. OUT PVOID *ResourceDirectoryOrData
  196. );
  197. NTSTATUS
  198. LdrpAccessResourceData (
  199. IN PVOID DllHandle,
  200. IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
  201. OUT PVOID *Address OPTIONAL,
  202. OUT PULONG Size OPTIONAL
  203. );
  204. VOID
  205. LdrpUnloadShimEngine (
  206. VOID
  207. );
  208. PVOID
  209. NtdllpAllocateStringRoutine (
  210. SIZE_T NumberOfBytes
  211. )
  212. {
  213. return RtlAllocateHeap (RtlProcessHeap(), 0, NumberOfBytes);
  214. }
  215. VOID
  216. NtdllpFreeStringRoutine (
  217. PVOID Buffer
  218. )
  219. {
  220. RtlFreeHeap (RtlProcessHeap(), 0, Buffer);
  221. }
  222. const PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine = NtdllpAllocateStringRoutine;
  223. const PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = NtdllpFreeStringRoutine;
  224. RTL_BITMAP FlsBitMap;
  225. RTL_BITMAP TlsBitMap;
  226. RTL_BITMAP TlsExpansionBitMap;
  227. RTL_CRITICAL_SECTION_DEBUG LoaderLockDebug;
  228. RTL_CRITICAL_SECTION LdrpLoaderLock = {
  229. &LoaderLockDebug,
  230. -1
  231. };
  232. BOOLEAN LoaderLockInitialized;
  233. PVOID LdrpHeap;
  234. //
  235. // 0 means no thread has been tasked to initialize the process.
  236. // 1 means a thread has been tasked but has not yet finished.
  237. // 2 means a thread has been tasked and initialization is complete.
  238. //
  239. LONG LdrpProcessInitialized;
  240. #define LDRP_PROCESS_INITIALIZATION_COMPLETE() \
  241. LdrpProcessInitializationComplete();
  242. VOID LdrpProcessInitializationComplete (
  243. VOID
  244. )
  245. /*++
  246. Routine Description:
  247. This function is called to trigger that process initialization has completed.
  248. Wow64 loader calls this entry after its process initialization part.
  249. Arguments:
  250. None.
  251. Return Value:
  252. None. Raises an exception on failure.
  253. --*/
  254. {
  255. ASSERT (LdrpProcessInitialized == 1);
  256. InterlockedIncrement (&LdrpProcessInitialized);
  257. }
  258. VOID
  259. LdrpInitialize (
  260. IN PCONTEXT Context,
  261. IN PVOID SystemArgument1,
  262. IN PVOID SystemArgument2
  263. )
  264. /*++
  265. Routine Description:
  266. This function is called as a User-Mode APC routine as the first
  267. user-mode code executed by a new thread. It's function is to initialize
  268. loader context, perform module initialization callouts...
  269. Arguments:
  270. Context - Supplies an optional context buffer that will be restored
  271. after all DLL initialization has been completed. If this
  272. parameter is NULL then this is a dynamic snap of this module.
  273. Otherwise this is a static snap prior to the user process
  274. gaining control.
  275. SystemArgument1 - Supplies the base address of the System Dll.
  276. SystemArgument2 - not used.
  277. Return Value:
  278. None. Raises an exception on failure.
  279. --*/
  280. {
  281. NTSTATUS InitStatus;
  282. PPEB Peb;
  283. PTEB Teb;
  284. LONG ProcessInitialized;
  285. MEMORY_BASIC_INFORMATION MemInfo;
  286. LARGE_INTEGER DelayValue;
  287. UNREFERENCED_PARAMETER (SystemArgument2);
  288. LDRP_CHECKPOINT();
  289. Teb = NtCurrentTeb ();
  290. //
  291. // Initialize the DeallocationStack so that subsequent stack growth for
  292. // this thread can happen properly regardless of where the process is
  293. // with respect to initialization.
  294. //
  295. if (Teb->DeallocationStack == NULL) {
  296. LDRP_CHECKPOINT();
  297. InitStatus = NtQueryVirtualMemory (NtCurrentProcess(),
  298. Teb->NtTib.StackLimit,
  299. MemoryBasicInformation,
  300. (PVOID)&MemInfo,
  301. sizeof(MemInfo),
  302. NULL);
  303. if (!NT_SUCCESS (InitStatus)) {
  304. DbgPrintEx(
  305. DPFLTR_LDR_ID,
  306. LDR_ERROR_DPFLTR,
  307. "LDR: %s - Call to NtQueryVirtualMemory failed with ntstaus %x\n",
  308. __FUNCTION__,
  309. InitStatus);
  310. LdrpInitializationFailure (InitStatus);
  311. RtlRaiseStatus (InitStatus);
  312. return;
  313. }
  314. Teb->DeallocationStack = MemInfo.AllocationBase;
  315. #if defined(_IA64_)
  316. Teb->DeallocationBStore = (PVOID)((ULONG_PTR)MemInfo.AllocationBase + MemInfo.RegionSize);
  317. #endif
  318. }
  319. do {
  320. ProcessInitialized = InterlockedCompareExchange (&LdrpProcessInitialized,
  321. 1,
  322. 0);
  323. if (ProcessInitialized != 1) {
  324. ASSERT ((ProcessInitialized == 0) || (ProcessInitialized == 2));
  325. break;
  326. }
  327. //
  328. // This is not the thread responsible for initializing the process -
  329. // some other thread has already begun this work but no telling how
  330. // far they have gone. So delay rather than try to synchronize on
  331. // a notification event.
  332. //
  333. //
  334. // Drop into a 30ms delay loop.
  335. //
  336. DelayValue.QuadPart = Int32x32To64 (30, -10000);
  337. while (LdrpProcessInitialized == 1) {
  338. InitStatus = NtDelayExecution (FALSE, &DelayValue);
  339. if (!NT_SUCCESS(InitStatus)) {
  340. DbgPrintEx(
  341. DPFLTR_LDR_ID,
  342. LDR_ERROR_DPFLTR,
  343. "LDR: ***NONFATAL*** %s - call to NtDelayExecution waiting on loader lock failed; ntstatus = %x\n",
  344. __FUNCTION__,
  345. InitStatus);
  346. }
  347. }
  348. } while (TRUE);
  349. Peb = Teb->ProcessEnvironmentBlock;
  350. if (ProcessInitialized == 0) {
  351. //
  352. // We are executing this for the first thread in the process -
  353. // initialize processwide structures.
  354. //
  355. //
  356. // Initialize the LoaderLock field so kernel thread termination
  357. // can make an effort to release it if need be.
  358. //
  359. Peb->LoaderLock = (PVOID) &LdrpLoaderLock;
  360. //
  361. // We execute in the first thread of the process. We will do
  362. // some more process-wide initialization.
  363. //
  364. LdrpInLdrInit = TRUE;
  365. #if DBG
  366. //
  367. // Time the load.
  368. //
  369. if (LdrpDisplayLoadTime) {
  370. NtQueryPerformanceCounter (&BeginTime, NULL);
  371. }
  372. #endif
  373. LDRP_CHECKPOINT();
  374. //
  375. // First initialize minimal exception handling so we can at least
  376. // debug it as well as deliver a popup if this application fails
  377. // to launch during LdrpInitializeProcess. Note this is very limited
  378. // as handlers cannot allocate from the heap until it is initialized,
  379. // etc, but this is good enough for LdrpInitializeProcessWrapperFilter.
  380. //
  381. InitializeListHead (&RtlpCalloutEntryList);
  382. #if defined(_WIN64)
  383. InitializeListHead (&RtlpDynamicFunctionTable);
  384. #endif
  385. __try {
  386. InitStatus = LdrpInitializeProcess (Context, SystemArgument1);
  387. if (!NT_SUCCESS(InitStatus)) {
  388. DbgPrintEx(
  389. DPFLTR_LDR_ID,
  390. LDR_ERROR_DPFLTR,
  391. "LDR: %s - call to LdrpInitializeProcess() failed with ntstatus %x\n",
  392. __FUNCTION__, InitStatus);
  393. }
  394. else if (Peb->MinimumStackCommit) {
  395. //
  396. // Make sure main thread gets the requested precommitted
  397. // stack size if such a value was specified system-wide
  398. // or for this process.
  399. //
  400. // This is a good point to do this since we just initialized
  401. // the process (among other things support for exception
  402. // dispatching).
  403. //
  404. InitStatus = LdrpTouchThreadStack (Peb->MinimumStackCommit);
  405. }
  406. LDRP_CHECKPOINT();
  407. } __except (LdrpInitializeProcessWrapperFilter(GetExceptionInformation()) ) {
  408. InitStatus = GetExceptionCode ();
  409. }
  410. LdrpInLdrInit = FALSE;
  411. #if DBG
  412. if (LdrpDisplayLoadTime) {
  413. NtQueryPerformanceCounter(&EndTime, NULL);
  414. NtQueryPerformanceCounter(&ElapsedTime, &Interval);
  415. ElapsedTime.QuadPart = EndTime.QuadPart - BeginTime.QuadPart;
  416. DbgPrint("\nLoadTime %ld In units of %ld cycles/second \n",
  417. ElapsedTime.LowPart,
  418. Interval.LowPart);
  419. ElapsedTime.QuadPart = EndTime.QuadPart - InitbTime.QuadPart;
  420. DbgPrint("InitTime %ld\n", ElapsedTime.LowPart);
  421. DbgPrint("Compares %d Bypasses %d Normal Snaps %d\nSecOpens %d SecCreates %d Maps %d Relocates %d\n",
  422. LdrpCompareCount,
  423. LdrpSnapBypass,
  424. LdrpNormalSnap,
  425. LdrpSectionOpens,
  426. LdrpSectionCreates,
  427. LdrpSectionMaps,
  428. LdrpSectionRelocates);
  429. }
  430. #endif
  431. #if defined(_WIN64)
  432. //
  433. // Wow64 will signal process initialization, so no need to do it twice.
  434. //
  435. if ((!UseWOW64) ||
  436. (NT_SUCCESS (InitStatus)) ||
  437. (LdrpProcessInitialized == 1)) {
  438. #endif
  439. LDRP_PROCESS_INITIALIZATION_COMPLETE();
  440. #if defined(_WIN64)
  441. }
  442. #endif
  443. }
  444. else {
  445. if (Peb->InheritedAddressSpace) {
  446. InitStatus = LdrpForkProcess ();
  447. }
  448. else {
  449. #if defined(_WIN64)
  450. //
  451. // Load in WOW64 if the image is supposed to run simulated.
  452. //
  453. if (UseWOW64) {
  454. //
  455. // This never returns. It will destroy the process.
  456. //
  457. (*Wow64LdrpInitialize)(Context);
  458. //
  459. // NEVER REACHED
  460. //
  461. }
  462. #endif
  463. InitStatus = STATUS_SUCCESS;
  464. LdrpInitializeThread (Context);
  465. }
  466. }
  467. NtTestAlert ();
  468. if (!NT_SUCCESS(InitStatus)) {
  469. LdrpInitializationFailure (InitStatus);
  470. RtlRaiseStatus (InitStatus);
  471. }
  472. //
  473. // The current thread is completely initialized. We will make sure
  474. // now that its stack has the right execute options. We avoid doing
  475. // this for Wow64 processes.
  476. //
  477. #if defined(_WIN64)
  478. ASSERT (!UseWOW64);
  479. #endif
  480. if (Peb->ExecuteOptions & (MEM_EXECUTE_OPTION_STACK | MEM_EXECUTE_OPTION_DATA)) {
  481. LdrpEnforceExecuteForCurrentThreadStack ();
  482. }
  483. }
  484. NTSTATUS
  485. LdrpForkProcess (
  486. VOID
  487. )
  488. {
  489. PPEB Peb;
  490. NTSTATUS st;
  491. Peb = NtCurrentPeb ();
  492. ASSERT (LdrpLoaderLock.DebugInfo->CriticalSection == &LdrpLoaderLock);
  493. ASSERT (LoaderLockInitialized == TRUE);
  494. ASSERT (Peb->ProcessHeap != NULL);
  495. //
  496. // Initialize the critical section package.
  497. //
  498. // If you wanted to preserve the cloned critical sections, you'd have to
  499. // reinitialize all of them as the semaphore handles weren't
  500. // duplicated. Unfortunately the threads aren't duplicated on fork either
  501. // so trying to recreate the OwningThread for owned critical sections
  502. // is pretty much impossible. Just stay with the behavior NT has always
  503. // had, leaks and all) - NO critical sections are duplicated.
  504. //
  505. if (Peb->InheritedAddressSpace == FALSE) {
  506. return STATUS_SUCCESS;
  507. }
  508. st = RtlpInitDeferredCriticalSection ();
  509. if (!NT_SUCCESS (st)) {
  510. return st;
  511. }
  512. //
  513. // Manually add the loader lock to the critical section list.
  514. //
  515. InsertTailList (&RtlCriticalSectionList,
  516. &LdrpLoaderLock.DebugInfo->ProcessLocksList);
  517. st = RtlInitializeCriticalSection (&FastPebLock);
  518. if (!NT_SUCCESS(st)) {
  519. return st;
  520. }
  521. Peb->InheritedAddressSpace = FALSE;
  522. return st;
  523. }
  524. VOID
  525. LdrpInitializationFailure (
  526. IN NTSTATUS FailureCode
  527. )
  528. {
  529. ULONG_PTR ErrorParameter;
  530. ULONG ErrorResponse;
  531. #if DBG
  532. DbgPrint("LDR: Process initialization failure; NTSTATUS = %08lx\n"
  533. " Function: %s\n"
  534. " Line: %d\n", FailureCode, g_LdrFunction, g_LdrLine);
  535. #endif
  536. if (LdrpFatalHardErrorCount) {
  537. return;
  538. }
  539. //
  540. // It's error time...
  541. //
  542. ErrorParameter = (ULONG_PTR)FailureCode;
  543. NtRaiseHardError (STATUS_APP_INIT_FAILURE,
  544. 1,
  545. 0,
  546. &ErrorParameter,
  547. OptionOk,
  548. &ErrorResponse);
  549. }
  550. INT
  551. LdrpInitializeProcessWrapperFilter (
  552. const struct _EXCEPTION_POINTERS *ExceptionPointers
  553. )
  554. /*++
  555. Routine Description:
  556. Exception filter function used in __try block around invocation of
  557. LdrpInitializeProcess() so that if LdrpInitializeProcess() fails,
  558. we can set a breakpoint here and see why instead of just catching
  559. the exception and propogating the status.
  560. Arguments:
  561. ExceptionCode
  562. Code returned from GetExceptionCode() in the __except()
  563. ExceptionPointers
  564. Pointer to exception information returned by GetExceptionInformation() in the __except()
  565. Return Value:
  566. EXCEPTION_EXECUTE_HANDLER
  567. --*/
  568. {
  569. if (DBG || g_LdrBreakOnLdrpInitializeProcessFailure) {
  570. DbgPrint ("LDR: LdrpInitializeProcess() threw an exception: %lu (0x%08lx)\n"
  571. " Exception record: .exr %p\n"
  572. " Context record: .cxr %p\n",
  573. ExceptionPointers->ExceptionRecord->ExceptionCode,
  574. ExceptionPointers->ExceptionRecord->ExceptionCode,
  575. ExceptionPointers->ExceptionRecord,
  576. ExceptionPointers->ContextRecord);
  577. #if DBG
  578. DbgPrint (" Last checkpoint: %s line %d\n",
  579. g_LdrFunction, g_LdrLine);
  580. #endif
  581. if (g_LdrBreakOnLdrpInitializeProcessFailure) {
  582. DbgBreakPoint ();
  583. }
  584. }
  585. return EXCEPTION_EXECUTE_HANDLER;
  586. }
  587. typedef struct _LDRP_PROCEDURE_NAME_ADDRESS_PAIR {
  588. STRING Name;
  589. PVOID * Address;
  590. } LDRP_PROCEDURE_NAME_ADDRESS_PAIR, *PLDRP_PROCEDURE_NAME_ADDRESS_PAIR;
  591. typedef CONST LDRP_PROCEDURE_NAME_ADDRESS_PAIR * PCLDRP_PROCEDURE_NAME_ADDRESS_PAIR;
  592. const static LDRP_PROCEDURE_NAME_ADDRESS_PAIR LdrpShimEngineProcedures[] =
  593. {
  594. { RTL_CONSTANT_STRING("SE_InstallBeforeInit"), (PVOID*)&g_pfnSE_InstallBeforeInit },
  595. { RTL_CONSTANT_STRING("SE_InstallAfterInit"), (PVOID*)&g_pfnSE_InstallAfterInit },
  596. { RTL_CONSTANT_STRING("SE_DllLoaded"), (PVOID*)&g_pfnSE_DllLoaded },
  597. { RTL_CONSTANT_STRING("SE_DllUnloaded"), (PVOID*)&g_pfnSE_DllUnloaded },
  598. { RTL_CONSTANT_STRING("SE_IsShimDll"), (PVOID*)&g_pfnSE_IsShimDll },
  599. { RTL_CONSTANT_STRING("SE_ProcessDying"), (PVOID*)&g_pfnSE_ProcessDying }
  600. };
  601. VOID
  602. LdrpGetShimEngineInterface (
  603. VOID
  604. )
  605. {
  606. NTSTATUS Status = STATUS_SUCCESS;
  607. //
  608. // Get the interface to the shim engine.
  609. //
  610. SIZE_T i;
  611. for ( i = 0 ; i != RTL_NUMBER_OF(LdrpShimEngineProcedures); ++i ) {
  612. PCLDRP_PROCEDURE_NAME_ADDRESS_PAIR Procedure = &LdrpShimEngineProcedures[i];
  613. Status = LdrpGetProcedureAddress(g_pShimEngineModule, &Procedure->Name,
  614. 0, Procedure->Address, FALSE);
  615. if (!NT_SUCCESS(Status)) {
  616. #if DBG
  617. DbgPrint("LdrpGetProcAddress failed to find %s in ShimEngine\n",
  618. Procedure->Name.Buffer);
  619. #endif
  620. break;
  621. }
  622. }
  623. if (!NT_SUCCESS(Status)) {
  624. LdrpUnloadShimEngine();
  625. }
  626. }
  627. BOOL
  628. LdrInitShimEngineDynamic (
  629. IN PVOID pShimEngineModule
  630. )
  631. {
  632. PVOID LockCookie = NULL;
  633. NTSTATUS Status;
  634. Status = LdrLockLoaderLock (0, NULL, &LockCookie);
  635. if (!NT_SUCCESS(Status)) {
  636. return FALSE;
  637. }
  638. if (g_pShimEngineModule == NULL) {
  639. //
  640. // Set the global shim engine ptr.
  641. //
  642. g_pShimEngineModule = pShimEngineModule;
  643. //
  644. // Get shimengine interface.
  645. //
  646. LdrpGetShimEngineInterface ();
  647. }
  648. Status = LdrUnlockLoaderLock (0, LockCookie);
  649. ASSERT(NT_SUCCESS(Status));
  650. return TRUE;
  651. }
  652. VOID
  653. LdrpLoadShimEngine (
  654. PWCHAR pwszShimEngine,
  655. PUNICODE_STRING pstrExeFullPath,
  656. PVOID pAppCompatExeData
  657. )
  658. {
  659. UNICODE_STRING strEngine;
  660. NTSTATUS status;
  661. RtlInitUnicodeString (&strEngine, pwszShimEngine);
  662. //
  663. // Load the specified shim engine.
  664. //
  665. status = LdrpLoadDll (0,
  666. UNICODE_NULL,
  667. NULL,
  668. &strEngine,
  669. &g_pShimEngineModule,
  670. FALSE);
  671. if (!NT_SUCCESS(status)) {
  672. #if DBG
  673. DbgPrint("LDR: Couldn't load the shim engine\n");
  674. #endif
  675. return;
  676. }
  677. LdrpGetShimEngineInterface ();
  678. //
  679. // Call the shim engine to give it a chance to initialize.
  680. //
  681. if (g_pfnSE_InstallBeforeInit != NULL) {
  682. (*g_pfnSE_InstallBeforeInit) (pstrExeFullPath, pAppCompatExeData);
  683. }
  684. }
  685. VOID
  686. LdrpUnloadShimEngine (
  687. VOID
  688. )
  689. {
  690. SIZE_T i;
  691. LdrUnloadDll (g_pShimEngineModule);
  692. for ( i = 0 ; i != RTL_NUMBER_OF(LdrpShimEngineProcedures); ++i ) {
  693. *(LdrpShimEngineProcedures[i].Address) = NULL;
  694. }
  695. g_pShimEngineModule = NULL;
  696. }
  697. NTSTATUS
  698. LdrpInitializeProcess (
  699. IN PCONTEXT Context OPTIONAL,
  700. IN PVOID SystemDllBase
  701. )
  702. /*++
  703. Routine Description:
  704. This function initializes the loader for the process. This includes:
  705. - Initializing the loader data table
  706. - Connecting to the loader subsystem
  707. - Initializing all statically linked DLLs
  708. Arguments:
  709. Context - Supplies an optional context buffer that will be restore
  710. after all DLL initialization has been completed. If this
  711. parameter is NULL then this is a dynamic snap of this module.
  712. Otherwise this is a static snap prior to the user process
  713. gaining control.
  714. SystemDllBase - Supplies the base address of the system dll.
  715. Return Value:
  716. NTSTATUS.
  717. --*/
  718. {
  719. PPEB_LDR_DATA Ldr;
  720. BOOLEAN ImageFileOptionsPresent;
  721. LOGICAL UseCOR;
  722. #if !defined(_WIN64)
  723. IMAGE_COR20_HEADER *Cor20Header;
  724. ULONG Cor20HeaderSize;
  725. #endif
  726. PWSTR pw;
  727. PTEB Teb;
  728. PPEB Peb;
  729. NTSTATUS st;
  730. PWCH p, pp;
  731. UNICODE_STRING CurDir;
  732. UNICODE_STRING FullImageName;
  733. UNICODE_STRING CommandLine;
  734. ULONG DebugProcessHeapOnly;
  735. HANDLE LinkHandle;
  736. static WCHAR SystemDllPathBuffer[DOS_MAX_PATH_LENGTH];
  737. UNICODE_STRING SystemDllPath;
  738. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  739. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  740. OBJECT_ATTRIBUTES Obja;
  741. LOGICAL StaticCurDir;
  742. ULONG i;
  743. PIMAGE_NT_HEADERS NtHeader;
  744. PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
  745. ULONG ProcessHeapFlags;
  746. RTL_HEAP_PARAMETERS HeapParameters;
  747. NLSTABLEINFO xInitTableInfo;
  748. LARGE_INTEGER LongTimeout;
  749. UNICODE_STRING SystemRoot;
  750. LONG_PTR Diff;
  751. ULONG_PTR OldBase;
  752. PVOID pAppCompatExeData;
  753. RTL_HEAP_PARAMETERS LdrpHeapParameters;
  754. PLDR_DATA_TABLE_ENTRY Entry;
  755. PLIST_ENTRY Head;
  756. PLIST_ENTRY Next;
  757. UNICODE_STRING UnicodeImageName;
  758. UNICODE_STRING ImagePathName; // for .local dll redirection, xwu
  759. PWCHAR ImagePathNameBuffer;
  760. BOOL DotLocalExists = FALSE;
  761. const static ANSI_STRING Kernel32ProcessInitPostImportFunctionName = RTL_CONSTANT_STRING("BaseProcessInitPostImport");
  762. const static UNICODE_STRING SlashKnownDllsString = RTL_CONSTANT_STRING(L"\\KnownDlls");
  763. const static UNICODE_STRING KnownDllPathString = RTL_CONSTANT_STRING(L"KnownDllPath");
  764. HANDLE ProcessHeap;
  765. LDRP_CHECKPOINT();
  766. //
  767. // Figure out process name.
  768. //
  769. Teb = NtCurrentTeb();
  770. Peb = Teb->ProcessEnvironmentBlock;
  771. ProcessParameters = Peb->ProcessParameters;
  772. pw = ProcessParameters->ImagePathName.Buffer;
  773. if (!(ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
  774. pw = (PWSTR)((PCHAR)pw + (ULONG_PTR)(ProcessParameters));
  775. }
  776. //
  777. // UnicodeImageName holds the base name + extension of the image.
  778. //
  779. UnicodeImageName.Buffer = pw;
  780. UnicodeImageName.Length = ProcessParameters->ImagePathName.Length;
  781. UnicodeImageName.MaximumLength = UnicodeImageName.Length + sizeof(WCHAR);
  782. StaticCurDir = TRUE;
  783. UseCOR = FALSE;
  784. ImagePathNameBuffer = NULL;
  785. DebugProcessHeapOnly = 0;
  786. NtHeader = RtlImageNtHeader (Peb->ImageBaseAddress);
  787. if (!NtHeader) {
  788. DbgPrintEx(
  789. DPFLTR_LDR_ID,
  790. LDR_ERROR_DPFLTR,
  791. "LDR: %s - failing because we were unable to map the image base address (%p) to the PIMAGE_NT_HEADERS\n",
  792. __FUNCTION__,
  793. Peb->ImageBaseAddress);
  794. return STATUS_INVALID_IMAGE_FORMAT;
  795. }
  796. //
  797. // Retrieve the native page size of the system
  798. //
  799. #if defined(_WIN64)
  800. NativePageSize = PAGE_SIZE;
  801. NativePageShift = PAGE_SHIFT;
  802. #elif defined(BUILD_WOW6432)
  803. NativePageSize = Wow64GetSystemNativePageSize ();
  804. NativePageShift = 0;
  805. i = NativePageSize;
  806. while ((i & 1) == 0) {
  807. i >>= 1;
  808. NativePageShift++;
  809. }
  810. #endif
  811. //
  812. // Parse `image file execution options' registry values if there
  813. // are any. ImageFileOptionsPresent supplies a hint about any existing
  814. // ImageFileExecutionOption key. If the key is missing, the
  815. // ApplicationCompatibilityGoo and DebugProcessHeapOnly entries won't
  816. // be checked again.
  817. //
  818. ImageFileOptionsPresent = LdrpInitializeExecutionOptions (&UnicodeImageName,
  819. Peb);
  820. pAppCompatExeData = NULL;
  821. #if defined(_WIN64)
  822. if ((NtHeader != NULL) &&
  823. (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
  824. ULONG_PTR Wow64Info;
  825. //
  826. // 64-bit loader, but the exe image is 32-bit. If
  827. // the Wow64Information is nonzero then use WOW64.
  828. // Othewise the image is a COM+ ILONLY image with
  829. // 32BITREQUIRED not set - the memory manager has
  830. // already checked the COR header and decided to
  831. // run the image in a full 64-bit process.
  832. //
  833. LDRP_CHECKPOINT();
  834. st = NtQueryInformationProcess (NtCurrentProcess(),
  835. ProcessWow64Information,
  836. &Wow64Info,
  837. sizeof(Wow64Info),
  838. NULL);
  839. if (!NT_SUCCESS (st)) {
  840. return st;
  841. }
  842. if (Wow64Info) {
  843. UseWOW64 = TRUE;
  844. }
  845. else {
  846. //
  847. // Set UseCOR to TRUE to indicate the image is a COM+ runtime image.
  848. //
  849. UseCOR = TRUE;
  850. }
  851. }
  852. #else
  853. Cor20Header = RtlImageDirectoryEntryToData (Peb->ImageBaseAddress,
  854. TRUE,
  855. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
  856. &Cor20HeaderSize);
  857. if (Cor20Header) {
  858. UseCOR = TRUE;
  859. }
  860. #endif
  861. LDRP_CHECKPOINT();
  862. ASSERT (Peb->Ldr == NULL);
  863. NtDllBase = SystemDllBase;
  864. if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE) {
  865. #if defined(_WIN64)
  866. if (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  867. #endif
  868. //
  869. // Native subsystems load slower, but validate their DLLs.
  870. // This is to help CSR detect bad images faster.
  871. //
  872. LdrpVerifyDlls = TRUE;
  873. }
  874. //
  875. // Capture app compat data and clear shim data field.
  876. //
  877. #if defined(_WIN64)
  878. //
  879. // If this is an x86 image, then let 32-bit ntdll read
  880. // and reset the appcompat pointer.
  881. //
  882. if (UseWOW64 == FALSE)
  883. #endif
  884. {
  885. pAppCompatExeData = Peb->pShimData;
  886. Peb->pShimData = NULL;
  887. }
  888. #if defined(BUILD_WOW6432)
  889. {
  890. //
  891. // The process is running in WOW64. Sort out the optional header
  892. // format and reformat the image if its page size is smaller than
  893. // the native page size.
  894. //
  895. PIMAGE_NT_HEADERS32 NtHeader32 = (PIMAGE_NT_HEADERS32)NtHeader;
  896. if (NtHeader32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 &&
  897. NtHeader32->OptionalHeader.SectionAlignment < NativePageSize) {
  898. SIZE_T ReturnLength;
  899. MEMORY_BASIC_INFORMATION MemoryInformation;
  900. st = NtQueryVirtualMemory (NtCurrentProcess(),
  901. NtHeader32,
  902. MemoryBasicInformation,
  903. &MemoryInformation,
  904. sizeof MemoryInformation,
  905. &ReturnLength);
  906. if (! NT_SUCCESS(st)) {
  907. DbgPrintEx(
  908. DPFLTR_LDR_ID,
  909. LDR_ERROR_DPFLTR,
  910. "LDR: %s - failing wow64 process initialization because:\n"
  911. " FileHeader.Machine (%u) != IMAGE_FILE_MACHINE_I386 (%u) or\n"
  912. " OptionalHeader.SectionAlignment (%u) >= NATIVE_PAGE_SIZE (%u) or\n"
  913. " NtQueryVirtualMemory on PE header failed (ntstatus %x)\n",
  914. __FUNCTION__,
  915. NtHeader32->FileHeader.Machine, IMAGE_FILE_MACHINE_I386,
  916. NtHeader32->OptionalHeader.SectionAlignment, NativePageSize,
  917. st);
  918. return st;
  919. }
  920. if ((MemoryInformation.Protect != PAGE_READONLY) &&
  921. (MemoryInformation.Protect != PAGE_EXECUTE_READ)) {
  922. st = LdrpWx86FormatVirtualImage (NULL,
  923. NtHeader32,
  924. Peb->ImageBaseAddress);
  925. if (!NT_SUCCESS(st)) {
  926. DbgPrintEx(
  927. DPFLTR_LDR_ID,
  928. LDR_ERROR_DPFLTR,
  929. "LDR: %s - failing wow64 process initialization because:\n"
  930. " FileHeader.Machine (%u) != IMAGE_FILE_MACHINE_I386 (%u) or\n"
  931. " OptionalHeader.SectionAlignment (%u) >= NATIVE_PAGE_SIZE (%u) or\n"
  932. " LdrpWxFormatVirtualImage failed (ntstatus %x)\n",
  933. __FUNCTION__,
  934. NtHeader32->FileHeader.Machine, IMAGE_FILE_MACHINE_I386,
  935. NtHeader32->OptionalHeader.SectionAlignment, NativePageSize,
  936. st);
  937. if (st == STATUS_SUCCESS) {
  938. st = STATUS_INVALID_IMAGE_FORMAT;
  939. }
  940. return st;
  941. }
  942. }
  943. }
  944. }
  945. #endif
  946. LDRP_CHECKPOINT();
  947. LdrpNumberOfProcessors = Peb->NumberOfProcessors;
  948. RtlpTimeout = Peb->CriticalSectionTimeout;
  949. LongTimeout.QuadPart = Int32x32To64 (3600, -10000000);
  950. ProcessParameters = RtlNormalizeProcessParams (Peb->ProcessParameters);
  951. if (ProcessParameters) {
  952. FullImageName = ProcessParameters->ImagePathName;
  953. CommandLine = ProcessParameters->CommandLine;
  954. } else {
  955. RtlInitEmptyUnicodeString (&FullImageName, NULL, 0);
  956. RtlInitEmptyUnicodeString (&CommandLine, NULL, 0);
  957. }
  958. LDRP_CHECKPOINT();
  959. RtlInitNlsTables (Peb->AnsiCodePageData,
  960. Peb->OemCodePageData,
  961. Peb->UnicodeCaseTableData,
  962. &xInitTableInfo);
  963. RtlResetRtlTranslations (&xInitTableInfo);
  964. i = 0;
  965. #if defined(_WIN64)
  966. if (UseWOW64 || UseCOR) {
  967. //
  968. // Ignore image config data when initializing the 64-bit loader.
  969. // The 32-bit loader in ntdll32 will look at the config data
  970. // and do the right thing.
  971. //
  972. ImageConfigData = NULL;
  973. } else
  974. #endif
  975. {
  976. ImageConfigData = RtlImageDirectoryEntryToData (Peb->ImageBaseAddress,
  977. TRUE,
  978. IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
  979. &i);
  980. }
  981. RtlZeroMemory (&HeapParameters, sizeof (HeapParameters));
  982. ProcessHeapFlags = HEAP_GROWABLE | HEAP_CLASS_0;
  983. HeapParameters.Length = sizeof (HeapParameters);
  984. if (ImageConfigData) {
  985. if (i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear)) {
  986. Peb->NtGlobalFlag &= ~ImageConfigData->GlobalFlagsClear;
  987. }
  988. if (i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet)) {
  989. Peb->NtGlobalFlag |= ImageConfigData->GlobalFlagsSet;
  990. }
  991. if ((i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout)) &&
  992. (ImageConfigData->CriticalSectionDefaultTimeout)) {
  993. //
  994. // Convert from milliseconds to NT time scale (100ns)
  995. //
  996. RtlpTimeout.QuadPart = Int32x32To64( (LONG)ImageConfigData->CriticalSectionDefaultTimeout,
  997. -10000);
  998. }
  999. if ((i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags)) &&
  1000. (ImageConfigData->ProcessHeapFlags)) {
  1001. ProcessHeapFlags = ImageConfigData->ProcessHeapFlags;
  1002. }
  1003. if ((i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold)) &&
  1004. (ImageConfigData->DeCommitFreeBlockThreshold)) {
  1005. HeapParameters.DeCommitFreeBlockThreshold = ImageConfigData->DeCommitFreeBlockThreshold;
  1006. }
  1007. if ((i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold)) &&
  1008. (ImageConfigData->DeCommitTotalFreeThreshold)) {
  1009. HeapParameters.DeCommitTotalFreeThreshold = ImageConfigData->DeCommitTotalFreeThreshold;
  1010. }
  1011. if ((i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize)) &&
  1012. (ImageConfigData->MaximumAllocationSize)) {
  1013. HeapParameters.MaximumAllocationSize = ImageConfigData->MaximumAllocationSize;
  1014. }
  1015. if ((i >= RTL_SIZEOF_THROUGH_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold)) &&
  1016. (ImageConfigData->VirtualMemoryThreshold)) {
  1017. HeapParameters.VirtualMemoryThreshold = ImageConfigData->VirtualMemoryThreshold;
  1018. }
  1019. }
  1020. LDRP_CHECKPOINT();
  1021. //
  1022. // This field is non-zero if the image file that was used to create this
  1023. // process contained a non-zero value in its image header. If so, then
  1024. // set the affinity mask for the process using this value. It could also
  1025. // be non-zero if the parent process created us suspended and poked our
  1026. // PEB with a non-zero value before resuming.
  1027. //
  1028. if (Peb->ImageProcessAffinityMask) {
  1029. st = NtSetInformationProcess (NtCurrentProcess(),
  1030. ProcessAffinityMask,
  1031. &Peb->ImageProcessAffinityMask,
  1032. sizeof (Peb->ImageProcessAffinityMask));
  1033. if (NT_SUCCESS (st)) {
  1034. KdPrint (("LDR: Using ProcessAffinityMask of 0x%Ix from image.\n",
  1035. Peb->ImageProcessAffinityMask));
  1036. }
  1037. else {
  1038. KdPrint (("LDR: Failed to set ProcessAffinityMask of 0x%Ix from image (Status == %08x).\n",
  1039. Peb->ImageProcessAffinityMask, st));
  1040. }
  1041. }
  1042. ShowSnaps = (BOOLEAN)((FLG_SHOW_LDR_SNAPS & Peb->NtGlobalFlag) != 0);
  1043. if (ShowSnaps) {
  1044. DbgPrint ("LDR: PID: 0x%x started - '%wZ'\n",
  1045. Teb->ClientId.UniqueProcess,
  1046. &CommandLine);
  1047. }
  1048. //
  1049. // Initialize the critical section package.
  1050. //
  1051. LDRP_CHECKPOINT();
  1052. if (RtlpTimeout.QuadPart < LongTimeout.QuadPart) {
  1053. RtlpTimoutDisable = TRUE;
  1054. }
  1055. st = RtlpInitDeferredCriticalSection ();
  1056. if (!NT_SUCCESS (st)) {
  1057. return st;
  1058. }
  1059. Peb->FlsBitmap = &FlsBitMap;
  1060. Peb->TlsBitmap = &TlsBitMap;
  1061. Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
  1062. RtlInitializeBitMap (&FlsBitMap,
  1063. &Peb->FlsBitmapBits[0],
  1064. RTL_BITS_OF (Peb->FlsBitmapBits));
  1065. RtlSetBit (&FlsBitMap, 0);
  1066. InitializeListHead (&Peb->FlsListHead);
  1067. RtlInitializeBitMap (&TlsBitMap,
  1068. &Peb->TlsBitmapBits[0],
  1069. RTL_BITS_OF (Peb->TlsBitmapBits));
  1070. RtlSetBit (&TlsBitMap, 0);
  1071. RtlInitializeBitMap (&TlsExpansionBitMap,
  1072. &Peb->TlsExpansionBitmapBits[0],
  1073. RTL_BITS_OF (Peb->TlsExpansionBitmapBits));
  1074. RtlSetBit (&TlsExpansionBitMap, 0);
  1075. #if defined(_WIN64)
  1076. //
  1077. // Allocate the predefined Wow64 TLS slots.
  1078. //
  1079. if (UseWOW64) {
  1080. RtlSetBits (Peb->TlsBitmap, 0, WOW64_TLS_MAX_NUMBER);
  1081. }
  1082. #endif
  1083. //
  1084. // Mark the loader lock as initialized.
  1085. //
  1086. for (i = 0; i < LDRP_HASH_TABLE_SIZE; i += 1) {
  1087. InitializeListHead (&LdrpHashTable[i]);
  1088. }
  1089. InsertTailList (&RtlCriticalSectionList,
  1090. &LdrpLoaderLock.DebugInfo->ProcessLocksList);
  1091. LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
  1092. LoaderLockInitialized = TRUE;
  1093. LDRP_CHECKPOINT();
  1094. //
  1095. // Initialize the stack trace data base if requested
  1096. //
  1097. if ((Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
  1098. || LdrpShouldCreateStackTraceDb) {
  1099. PVOID BaseAddress = NULL;
  1100. SIZE_T ReserveSize = 8 * RTL_MEG;
  1101. st = LdrQueryImageFileExecutionOptions (&UnicodeImageName,
  1102. L"StackTraceDatabaseSizeInMb",
  1103. REG_DWORD,
  1104. &ReserveSize,
  1105. sizeof (ReserveSize),
  1106. NULL);
  1107. //
  1108. // Sanity check the value read from registry.
  1109. //
  1110. if (! NT_SUCCESS(st)) {
  1111. ReserveSize = 8 * RTL_MEG;
  1112. }
  1113. else {
  1114. if (ReserveSize < 8) {
  1115. ReserveSize = 8 * RTL_MEG;
  1116. }
  1117. else if (ReserveSize > 128) {
  1118. ReserveSize = 128 * RTL_MEG;
  1119. }
  1120. else {
  1121. ReserveSize *= RTL_MEG;
  1122. }
  1123. DbgPrint ("LDR: Stack trace database size is %u Mb \n",
  1124. ReserveSize / RTL_MEG);
  1125. }
  1126. st = NtAllocateVirtualMemory (NtCurrentProcess(),
  1127. (PVOID *)&BaseAddress,
  1128. 0,
  1129. &ReserveSize,
  1130. MEM_RESERVE,
  1131. PAGE_READWRITE);
  1132. if (NT_SUCCESS(st)) {
  1133. st = RtlInitializeStackTraceDataBase (BaseAddress,
  1134. 0,
  1135. ReserveSize);
  1136. if (!NT_SUCCESS (st)) {
  1137. NtFreeVirtualMemory (NtCurrentProcess(),
  1138. (PVOID *)&BaseAddress,
  1139. &ReserveSize,
  1140. MEM_RELEASE);
  1141. }
  1142. else {
  1143. //
  1144. // If the stack trace db is not created due to page heap
  1145. // enabling then we can set the NT heap debugging flags.
  1146. // If we create it due to page heap then we should not
  1147. // enable these flags because page heap and NT debug heap
  1148. // do not coexist peacefully.
  1149. //
  1150. if (!LdrpShouldCreateStackTraceDb) {
  1151. Peb->NtGlobalFlag |= FLG_HEAP_VALIDATE_PARAMETERS;
  1152. }
  1153. }
  1154. }
  1155. }
  1156. //
  1157. // Initialize the loader data based in the PEB.
  1158. //
  1159. st = RtlInitializeCriticalSection (&FastPebLock);
  1160. if (!NT_SUCCESS(st)) {
  1161. return st;
  1162. }
  1163. st = RtlInitializeCriticalSection (&RtlpCalloutEntryLock);
  1164. if (!NT_SUCCESS(st)) {
  1165. return st;
  1166. }
  1167. LDRP_CHECKPOINT();
  1168. //
  1169. // Initialize the Etw stuff.
  1170. //
  1171. st = EtwpInitializeDll ();
  1172. if (!NT_SUCCESS(st)) {
  1173. return st;
  1174. }
  1175. InitializeListHead (&LdrpDllNotificationList);
  1176. Peb->FastPebLock = &FastPebLock;
  1177. LDRP_CHECKPOINT();
  1178. RtlInitializeHeapManager ();
  1179. LDRP_CHECKPOINT();
  1180. #if defined(_WIN64)
  1181. if ((UseWOW64) ||
  1182. (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
  1183. //
  1184. // Create a heap using all defaults. The 32-bit process heap
  1185. // will be created later by ntdll32 using the parameters from the exe.
  1186. //
  1187. ProcessHeap = RtlCreateHeap (ProcessHeapFlags,
  1188. NULL,
  1189. 0,
  1190. 0,
  1191. NULL,
  1192. &HeapParameters);
  1193. } else
  1194. #endif
  1195. {
  1196. if (NtHeader->OptionalHeader.MajorSubsystemVersion <= 3 &&
  1197. NtHeader->OptionalHeader.MinorSubsystemVersion < 51
  1198. ) {
  1199. ProcessHeapFlags |= HEAP_CREATE_ALIGN_16;
  1200. }
  1201. ProcessHeap = RtlCreateHeap (ProcessHeapFlags,
  1202. NULL,
  1203. NtHeader->OptionalHeader.SizeOfHeapReserve,
  1204. NtHeader->OptionalHeader.SizeOfHeapCommit,
  1205. NULL, // Lock to use for serialization
  1206. &HeapParameters);
  1207. }
  1208. if (ProcessHeap == NULL) {
  1209. DbgPrintEx(
  1210. DPFLTR_LDR_ID,
  1211. LDR_ERROR_DPFLTR,
  1212. "LDR: %s - unable to create process heap\n",
  1213. __FUNCTION__);
  1214. return STATUS_NO_MEMORY;
  1215. }
  1216. Peb->ProcessHeap = ProcessHeap;
  1217. //
  1218. // Create the loader private heap.
  1219. //
  1220. RtlZeroMemory (&LdrpHeapParameters, sizeof(LdrpHeapParameters));
  1221. LdrpHeapParameters.Length = sizeof (LdrpHeapParameters);
  1222. LdrpHeap = RtlCreateHeap (
  1223. HEAP_GROWABLE | HEAP_CLASS_1,
  1224. NULL,
  1225. 64 * 1024, // 0 is ok here, 64k is a chosen tuned number
  1226. 24 * 1024, // 0 is ok here, 24k is a chosen tuned number
  1227. NULL,
  1228. &LdrpHeapParameters);
  1229. if (LdrpHeap == NULL) {
  1230. DbgPrintEx(
  1231. DPFLTR_LDR_ID,
  1232. LDR_ERROR_DPFLTR,
  1233. "LDR: %s failing process initialization due to inability to create loader private heap.\n",
  1234. __FUNCTION__);
  1235. return STATUS_NO_MEMORY;
  1236. }
  1237. LDRP_CHECKPOINT();
  1238. NtdllBaseTag = RtlCreateTagHeap (ProcessHeap,
  1239. 0,
  1240. L"NTDLL!",
  1241. L"!Process\0" // Heap Name
  1242. L"CSRSS Client\0"
  1243. L"LDR Database\0"
  1244. L"Current Directory\0"
  1245. L"TLS Storage\0"
  1246. L"DBGSS Client\0"
  1247. L"SE Temporary\0"
  1248. L"Temporary\0"
  1249. L"LocalAtom\0");
  1250. RtlInitializeAtomPackage (MAKE_TAG(ATOM_TAG));
  1251. LDRP_CHECKPOINT();
  1252. //
  1253. // Allow only the process heap to have page allocations turned on.
  1254. //
  1255. if (ImageFileOptionsPresent) {
  1256. st = LdrQueryImageFileExecutionOptions (&UnicodeImageName,
  1257. L"DebugProcessHeapOnly",
  1258. REG_DWORD,
  1259. &DebugProcessHeapOnly,
  1260. sizeof (DebugProcessHeapOnly),
  1261. NULL);
  1262. if (NT_SUCCESS (st)) {
  1263. if (RtlpDebugPageHeap && (DebugProcessHeapOnly != 0)) {
  1264. //
  1265. // The process heap was created while `pageheap' was on
  1266. // so now we just disable `pageheap' boolean and everything
  1267. // will be quiet. Note that actually we get two heaps
  1268. // `pageheap-ed' because there is also the loader heap
  1269. // that gets created. This is ok. We need to verify that too.
  1270. //
  1271. RtlpDebugPageHeap = FALSE;
  1272. //
  1273. // If `DebugProcessHeapOnly' is on we need to disable per dll
  1274. // page heap because the new thunks replacing allocation
  1275. // functions call directly page heap APIs which do not check
  1276. // if page heap is on or not. They just assume it is on since
  1277. // they are called from NT heap manager properly. We cannot
  1278. // just put a check in all page heap APIs because there is
  1279. // no meaningful value to return in case the page heap is not
  1280. // on.
  1281. //
  1282. RtlpDphGlobalFlags &= ~PAGE_HEAP_USE_DLL_NAMES;
  1283. }
  1284. }
  1285. }
  1286. LDRP_CHECKPOINT();
  1287. SystemDllPath.Buffer = SystemDllPathBuffer;
  1288. SystemDllPath.Length = 0;
  1289. SystemDllPath.MaximumLength = sizeof (SystemDllPathBuffer);
  1290. RtlInitUnicodeString (&SystemRoot, USER_SHARED_DATA->NtSystemRoot);
  1291. RtlAppendUnicodeStringToString (&SystemDllPath, &SystemRoot);
  1292. RtlAppendUnicodeStringToString (&SystemDllPath, &SlashSystem32SlashString);
  1293. InitializeObjectAttributes (&Obja,
  1294. (PUNICODE_STRING)&SlashKnownDllsString,
  1295. OBJ_CASE_INSENSITIVE,
  1296. NULL,
  1297. NULL);
  1298. st = NtOpenDirectoryObject (&LdrpKnownDllObjectDirectory,
  1299. DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
  1300. &Obja);
  1301. if (!NT_SUCCESS(st)) {
  1302. LdrpKnownDllObjectDirectory = NULL;
  1303. //
  1304. // KnownDlls directory doesn't exist - assume it's system32.
  1305. //
  1306. RtlInitUnicodeString (&LdrpKnownDllPath, SystemDllPath.Buffer);
  1307. LdrpKnownDllPath.Length -= sizeof(WCHAR); // remove trailing '\'
  1308. } else {
  1309. //
  1310. // Open up the known dll pathname link and query its value.
  1311. //
  1312. InitializeObjectAttributes (&Obja,
  1313. (PUNICODE_STRING)&KnownDllPathString,
  1314. OBJ_CASE_INSENSITIVE,
  1315. LdrpKnownDllObjectDirectory,
  1316. NULL);
  1317. st = NtOpenSymbolicLinkObject (&LinkHandle, SYMBOLIC_LINK_QUERY, &Obja);
  1318. if (NT_SUCCESS (st)) {
  1319. LdrpKnownDllPath.Length = 0;
  1320. LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
  1321. LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
  1322. st = NtQuerySymbolicLinkObject (LinkHandle,
  1323. &LdrpKnownDllPath,
  1324. NULL);
  1325. NtClose(LinkHandle);
  1326. if (!NT_SUCCESS(st)) {
  1327. DbgPrintEx(
  1328. DPFLTR_LDR_ID,
  1329. LDR_ERROR_DPFLTR,
  1330. "LDR: %s - failed call to NtQuerySymbolicLinkObject with status %x\n",
  1331. __FUNCTION__,
  1332. st);
  1333. return st;
  1334. }
  1335. } else {
  1336. DbgPrintEx(
  1337. DPFLTR_LDR_ID,
  1338. LDR_ERROR_DPFLTR,
  1339. "LDR: %s - failed call to NtOpenSymbolicLinkObject with status %x\n",
  1340. __FUNCTION__,
  1341. st);
  1342. return st;
  1343. }
  1344. }
  1345. LDRP_CHECKPOINT();
  1346. if (ProcessParameters) {
  1347. //
  1348. // If the process was created with process parameters,
  1349. // then extract:
  1350. //
  1351. // - Library Search Path
  1352. //
  1353. // - Starting Current Directory
  1354. //
  1355. if (ProcessParameters->DllPath.Length) {
  1356. LdrpDefaultPath = ProcessParameters->DllPath;
  1357. }
  1358. else {
  1359. LdrpInitializationFailure(STATUS_INVALID_PARAMETER);
  1360. }
  1361. CurDir = ProcessParameters->CurrentDirectory.DosPath;
  1362. #define DRIVE_ROOT_DIRECTORY_LENGTH 3 /* (sizeof("X:\\") - 1) */
  1363. if (CurDir.Buffer == NULL || CurDir.Length == 0 || CurDir.Buffer[ 0 ] == UNICODE_NULL) {
  1364. CurDir.Buffer = RtlAllocateHeap (ProcessHeap,
  1365. 0,
  1366. (DRIVE_ROOT_DIRECTORY_LENGTH + 1) * sizeof(WCHAR));
  1367. if (CurDir.Buffer == NULL) {
  1368. DbgPrintEx(
  1369. DPFLTR_LDR_ID,
  1370. LDR_ERROR_DPFLTR,
  1371. "LDR: %s - unable to allocate current working directory buffer\n",
  1372. __FUNCTION__);
  1373. return STATUS_NO_MEMORY;
  1374. }
  1375. StaticCurDir = FALSE;
  1376. RtlCopyMemory (CurDir.Buffer,
  1377. USER_SHARED_DATA->NtSystemRoot,
  1378. DRIVE_ROOT_DIRECTORY_LENGTH * sizeof(WCHAR));
  1379. CurDir.Buffer[DRIVE_ROOT_DIRECTORY_LENGTH] = UNICODE_NULL;
  1380. CurDir.Length = DRIVE_ROOT_DIRECTORY_LENGTH * sizeof(WCHAR);
  1381. CurDir.MaximumLength = CurDir.Length + sizeof(WCHAR);
  1382. }
  1383. }
  1384. else {
  1385. CurDir = SystemRoot;
  1386. }
  1387. //
  1388. // Make sure the module data base is initialized before we take any
  1389. // exceptions.
  1390. //
  1391. LDRP_CHECKPOINT();
  1392. Ldr = &PebLdr;
  1393. Peb->Ldr = Ldr;
  1394. Ldr->Length = sizeof(PEB_LDR_DATA);
  1395. Ldr->Initialized = TRUE;
  1396. ASSERT (Ldr->SsHandle == NULL);
  1397. ASSERT (Ldr->EntryInProgress == NULL);
  1398. ASSERT (Ldr->InLoadOrderModuleList.Flink == NULL);
  1399. ASSERT (Ldr->InLoadOrderModuleList.Blink == NULL);
  1400. ASSERT (Ldr->InMemoryOrderModuleList.Flink == NULL);
  1401. ASSERT (Ldr->InMemoryOrderModuleList.Blink == NULL);
  1402. ASSERT (Ldr->InInitializationOrderModuleList.Flink == NULL);
  1403. ASSERT (Ldr->InInitializationOrderModuleList.Blink == NULL);
  1404. InitializeListHead (&Ldr->InLoadOrderModuleList);
  1405. InitializeListHead (&Ldr->InMemoryOrderModuleList);
  1406. InitializeListHead (&Ldr->InInitializationOrderModuleList);
  1407. //
  1408. // Allocate the first data table entry for the image. Since we
  1409. // have already mapped this one, we need to do the allocation by hand.
  1410. // Its characteristics identify it as not a Dll, but it is linked
  1411. // into the table so that pc correlation searching doesn't have to
  1412. // be special cased.
  1413. //
  1414. LdrpImageEntry = LdrpAllocateDataTableEntry (Peb->ImageBaseAddress);
  1415. LdrDataTableEntry = LdrpImageEntry;
  1416. if (LdrDataTableEntry == NULL) {
  1417. DbgPrintEx(
  1418. DPFLTR_LDR_ID,
  1419. LDR_ERROR_DPFLTR,
  1420. "LDR: %s - failing process initialization due to inability allocate \"%wZ\"'s LDR_DATA_TABLE_ENTRY\n",
  1421. __FUNCTION__,
  1422. &FullImageName);
  1423. if (!StaticCurDir) {
  1424. RtlFreeUnicodeString (&CurDir);
  1425. }
  1426. return STATUS_NO_MEMORY;
  1427. }
  1428. LdrDataTableEntry->LoadCount = (USHORT)0xffff;
  1429. LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase);
  1430. LdrDataTableEntry->FullDllName = FullImageName;
  1431. LdrDataTableEntry->Flags = (UseCOR) ? LDRP_COR_IMAGE : 0;
  1432. LdrDataTableEntry->EntryPointActivationContext = NULL;
  1433. //
  1434. // p = strrchr(FullImageName, '\\');
  1435. // but not necessarily null terminated
  1436. //
  1437. pp = UNICODE_NULL;
  1438. p = FullImageName.Buffer;
  1439. while (*p) {
  1440. if (*p++ == (WCHAR)'\\') {
  1441. pp = p;
  1442. }
  1443. }
  1444. if (pp != UNICODE_NULL) {
  1445. LdrDataTableEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)p - (ULONG_PTR)pp);
  1446. LdrDataTableEntry->BaseDllName.MaximumLength = LdrDataTableEntry->BaseDllName.Length + sizeof(WCHAR);
  1447. LdrDataTableEntry->BaseDllName.Buffer =
  1448. (PWSTR)
  1449. (((ULONG_PTR) LdrDataTableEntry->FullDllName.Buffer) +
  1450. (LdrDataTableEntry->FullDllName.Length - LdrDataTableEntry->BaseDllName.Length));
  1451. } else {
  1452. LdrDataTableEntry->BaseDllName = LdrDataTableEntry->FullDllName;
  1453. }
  1454. LdrDataTableEntry->Flags |= LDRP_ENTRY_PROCESSED;
  1455. LdrpInsertMemoryTableEntry (LdrDataTableEntry);
  1456. //
  1457. // The process references the system DLL, so insert this next into the
  1458. // loader table. Since we have already mapped this one, we need to do
  1459. // the allocation by hand. Since every application will be statically
  1460. // linked to the system Dll, keep the LoadCount initialized to 0.
  1461. //
  1462. LdrDataTableEntry = LdrpAllocateDataTableEntry (SystemDllBase);
  1463. if (LdrDataTableEntry == NULL) {
  1464. DbgPrintEx(
  1465. DPFLTR_LDR_ID,
  1466. LDR_ERROR_DPFLTR,
  1467. "LDR: %s - failing process initialization due to inability to allocate NTDLL's LDR_DATA_TABLE_ENTRY\n",
  1468. __FUNCTION__);
  1469. if (!StaticCurDir) {
  1470. RtlFreeUnicodeString (&CurDir);
  1471. }
  1472. return STATUS_NO_MEMORY;
  1473. }
  1474. LdrDataTableEntry->Flags = (USHORT)LDRP_IMAGE_DLL;
  1475. LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase);
  1476. LdrDataTableEntry->LoadCount = (USHORT)0xffff;
  1477. LdrDataTableEntry->EntryPointActivationContext = NULL;
  1478. LdrDataTableEntry->FullDllName = SystemDllPath;
  1479. RtlAppendUnicodeStringToString(&LdrDataTableEntry->FullDllName, &NtDllName);
  1480. LdrDataTableEntry->BaseDllName = NtDllName;
  1481. LdrpInsertMemoryTableEntry (LdrDataTableEntry);
  1482. #if defined(_WIN64)
  1483. RtlInitializeHistoryTable ();
  1484. #endif
  1485. LdrpNtDllDataTableEntry = LdrDataTableEntry;
  1486. if (ShowSnaps) {
  1487. DbgPrint( "LDR: NEW PROCESS\n" );
  1488. DbgPrint( " Image Path: %wZ (%wZ)\n",
  1489. &LdrpImageEntry->FullDllName,
  1490. &LdrpImageEntry->BaseDllName
  1491. );
  1492. DbgPrint( " Current Directory: %wZ\n", &CurDir );
  1493. DbgPrint( " Search Path: %wZ\n", &LdrpDefaultPath );
  1494. }
  1495. //
  1496. // Add init routine to list
  1497. //
  1498. InsertHeadList (&Ldr->InInitializationOrderModuleList,
  1499. &LdrDataTableEntry->InInitializationOrderLinks);
  1500. //
  1501. // Inherit the current directory
  1502. //
  1503. LDRP_CHECKPOINT();
  1504. st = RtlSetCurrentDirectory_U (&CurDir);
  1505. if (!NT_SUCCESS(st)) {
  1506. DbgPrintEx(
  1507. DPFLTR_LDR_ID,
  1508. LDR_ERROR_DPFLTR,
  1509. "LDR: %s - unable to set current directory to \"%wZ\"; status = %x\n",
  1510. __FUNCTION__,
  1511. &CurDir,
  1512. st);
  1513. if (!StaticCurDir) {
  1514. RtlFreeUnicodeString (&CurDir);
  1515. }
  1516. CurDir = SystemRoot;
  1517. st = RtlSetCurrentDirectory_U (&CurDir);
  1518. if (!NT_SUCCESS(st)) {
  1519. DbgPrintEx(
  1520. DPFLTR_LDR_ID,
  1521. LDR_ERROR_DPFLTR,
  1522. "LDR: %s - unable to set current directory to NtSystemRoot; status = %x\n",
  1523. __FUNCTION__,
  1524. st);
  1525. }
  1526. }
  1527. else {
  1528. if (!StaticCurDir) {
  1529. RtlFreeUnicodeString (&CurDir);
  1530. }
  1531. }
  1532. if (ProcessParameters->Flags & RTL_USER_PROC_APP_MANIFEST_PRESENT) {
  1533. // Application manifests prevent .local detection.
  1534. //
  1535. // Note that we don't clear the flag so that someone like app compat
  1536. // can forcibly set it to reenable .local + app manifest behavior.
  1537. } else {
  1538. //
  1539. // Fusion 1.0 fixup : check the existence of .local, and set
  1540. // a flag in PPeb->ProcessParameters.Flags
  1541. //
  1542. // Setup the global for this process that decides whether we want DLL
  1543. // redirection on or not. LoadLibrary() and GetModuleHandle() look at this
  1544. // boolean.
  1545. //
  1546. if (ProcessParameters->ImagePathName.Length > (MAXUSHORT -
  1547. sizeof(DLL_REDIRECTION_LOCAL_SUFFIX))) {
  1548. return STATUS_NAME_TOO_LONG;
  1549. }
  1550. ImagePathName.Length = ProcessParameters->ImagePathName.Length;
  1551. ImagePathName.MaximumLength = ProcessParameters->ImagePathName.Length + sizeof(DLL_REDIRECTION_LOCAL_SUFFIX);
  1552. ImagePathNameBuffer = (PWCHAR) RtlAllocateHeap (ProcessHeap, MAKE_TAG( TEMP_TAG ), ImagePathName.MaximumLength);
  1553. if (ImagePathNameBuffer == NULL) {
  1554. DbgPrintEx(
  1555. DPFLTR_LDR_ID,
  1556. LDR_ERROR_DPFLTR,
  1557. "LDR: %s - unable to allocate heap for the image's .local path\n",
  1558. __FUNCTION__);
  1559. return STATUS_NO_MEMORY;
  1560. }
  1561. RtlCopyMemory (ImagePathNameBuffer,
  1562. pw,
  1563. ProcessParameters->ImagePathName.Length);
  1564. ImagePathName.Buffer = ImagePathNameBuffer;
  1565. //
  1566. // Now append the suffix:
  1567. //
  1568. st = RtlAppendUnicodeToString(&ImagePathName, DLL_REDIRECTION_LOCAL_SUFFIX);
  1569. if (!NT_SUCCESS(st)) {
  1570. #if DBG
  1571. DbgPrint("RtlAppendUnicodeToString fails with status %lx\n", st);
  1572. #endif
  1573. RtlFreeHeap(ProcessHeap, 0, ImagePathNameBuffer);
  1574. return st;
  1575. }
  1576. //
  1577. // RtlDoesFileExists_U() wants a null-terminated string.
  1578. //
  1579. ImagePathNameBuffer[ImagePathName.Length / sizeof(WCHAR)] = UNICODE_NULL;
  1580. DotLocalExists = RtlDoesFileExists_U(ImagePathNameBuffer);
  1581. if (DotLocalExists) { // set the flag in Peb->ProcessParameters->flags
  1582. ProcessParameters->Flags |= RTL_USER_PROC_DLL_REDIRECTION_LOCAL;
  1583. }
  1584. RtlFreeHeap (ProcessHeap, 0, ImagePathNameBuffer); //cleanup
  1585. }
  1586. //
  1587. // Second round of application verifier initialization. We need to split
  1588. // this into two phases because some verifier things must happen very early
  1589. // and other things rely on other things being already initialized
  1590. // (exception dispatching, system heap, etc).
  1591. //
  1592. if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER) {
  1593. AVrfInitializeVerifier (FALSE, NULL, 1);
  1594. }
  1595. #if defined(_WIN64)
  1596. //
  1597. // Load in WOW64 if the image is supposed to run simulated
  1598. //
  1599. if (UseWOW64) {
  1600. static UNICODE_STRING Wow64DllName = RTL_CONSTANT_STRING(L"wow64.dll");
  1601. CONST static ANSI_STRING Wow64LdrpInitializeProcName = RTL_CONSTANT_STRING("Wow64LdrpInitialize");
  1602. CONST static ANSI_STRING Wow64PrepareForExceptionProcName = RTL_CONSTANT_STRING("Wow64PrepareForException");
  1603. CONST static ANSI_STRING Wow64ApcRoutineProcName = RTL_CONSTANT_STRING("Wow64ApcRoutine");
  1604. st = LdrLoadDll(NULL, NULL, &Wow64DllName, &Wow64Handle);
  1605. if (!NT_SUCCESS(st)) {
  1606. if (ShowSnaps) {
  1607. DbgPrint("LDR: wow64.dll not found. Status=%x\n", st);
  1608. }
  1609. return st;
  1610. }
  1611. //
  1612. // Get the entrypoints. They are roughly cloned from ntos\ps\psinit.c
  1613. // PspInitSystemDll().
  1614. //
  1615. st = LdrGetProcedureAddress (Wow64Handle,
  1616. &Wow64LdrpInitializeProcName,
  1617. 0,
  1618. (PVOID *)&Wow64LdrpInitialize);
  1619. if (!NT_SUCCESS(st)) {
  1620. if (ShowSnaps) {
  1621. DbgPrint("LDR: Wow64LdrpInitialize not found. Status=%x\n", st);
  1622. }
  1623. return st;
  1624. }
  1625. st = LdrGetProcedureAddress (Wow64Handle,
  1626. &Wow64PrepareForExceptionProcName,
  1627. 0,
  1628. (PVOID *)&Wow64PrepareForException);
  1629. if (!NT_SUCCESS(st)) {
  1630. if (ShowSnaps) {
  1631. DbgPrint("LDR: Wow64PrepareForException not found. Status=%x\n", st);
  1632. }
  1633. return st;
  1634. }
  1635. st = LdrGetProcedureAddress (Wow64Handle,
  1636. &Wow64ApcRoutineProcName,
  1637. 0,
  1638. (PVOID *)&Wow64ApcRoutine);
  1639. if (!NT_SUCCESS(st)) {
  1640. if (ShowSnaps) {
  1641. DbgPrint("LDR: Wow64ApcRoutine not found. Status=%x\n", st);
  1642. }
  1643. return st;
  1644. }
  1645. //
  1646. // Now that all DLLs are loaded, if the process is being debugged,
  1647. // signal the debugger with an exception
  1648. //
  1649. if (Peb->BeingDebugged) {
  1650. DbgBreakPoint ();
  1651. }
  1652. //
  1653. // Mark the process as initialized so subsequent threads that
  1654. // get created know not to wait.
  1655. //
  1656. LdrpInLdrInit = FALSE;
  1657. //
  1658. // Call wow64 to load and run 32-bit ntdll.dll.
  1659. //
  1660. (*Wow64LdrpInitialize)(Context);
  1661. //
  1662. // This never returns. It will destroy the process.
  1663. //
  1664. }
  1665. #endif
  1666. LDRP_CHECKPOINT();
  1667. //
  1668. // Check if image is COM+.
  1669. //
  1670. if (UseCOR) {
  1671. //
  1672. // The image is COM+ so notify the runtime that the image was loaded
  1673. // and allow it to verify the image for correctness.
  1674. //
  1675. PVOID OriginalViewBase;
  1676. OriginalViewBase = Peb->ImageBaseAddress;
  1677. st = LdrpCorValidateImage (&Peb->ImageBaseAddress,
  1678. LdrpImageEntry->FullDllName.Buffer);
  1679. if (!NT_SUCCESS(st)) {
  1680. return st;
  1681. }
  1682. if (OriginalViewBase != Peb->ImageBaseAddress) {
  1683. //
  1684. // Mscoree has substituted a new image at a new base in place
  1685. // of the original image. Unmap the original image and use
  1686. // the new image from now on.
  1687. //
  1688. NtUnmapViewOfSection (NtCurrentProcess(), OriginalViewBase);
  1689. NtHeader = RtlImageNtHeader (Peb->ImageBaseAddress);
  1690. if (!NtHeader) {
  1691. LdrpCorUnloadImage (Peb->ImageBaseAddress);
  1692. return STATUS_INVALID_IMAGE_FORMAT;
  1693. }
  1694. //
  1695. // Update the exe's LDR_DATA_TABLE_ENTRY.
  1696. //
  1697. LdrpImageEntry->DllBase = Peb->ImageBaseAddress;
  1698. LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint (LdrpImageEntry->DllBase);
  1699. }
  1700. //
  1701. // Edit the initial instruction pointer to point into mscoree.dll.
  1702. //
  1703. LdrpCorReplaceStartContext (Context);
  1704. }
  1705. LDRP_CHECKPOINT();
  1706. //
  1707. // If this is a windows subsystem app, load kernel32 so that it
  1708. // can handle processing activation contexts found in DLLs and the .exe.
  1709. //
  1710. if ((NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
  1711. (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)) {
  1712. PVOID Kernel32Handle;
  1713. const static UNICODE_STRING Kernel32DllName = RTL_CONSTANT_STRING(L"kernel32.dll");
  1714. st = LdrLoadDll (NULL, // DllPath
  1715. NULL, // DllCharacteristics
  1716. &Kernel32DllName, // DllName
  1717. &Kernel32Handle // DllHandle
  1718. );
  1719. if (!NT_SUCCESS(st)) {
  1720. if (ShowSnaps) {
  1721. DbgPrint("LDR: Unable to load kernel32.dll. Status=%x\n", st);
  1722. }
  1723. return st;
  1724. }
  1725. st = LdrGetProcedureAddress (Kernel32Handle,
  1726. &Kernel32ProcessInitPostImportFunctionName,
  1727. 0,
  1728. (PVOID *) &Kernel32ProcessInitPostImportFunction);
  1729. if (!NT_SUCCESS(st)) {
  1730. if (ShowSnaps) {
  1731. DbgPrint(
  1732. "LDR: Failed to find post-import process init function in kernel32; ntstatus 0x%08lx\n", st);
  1733. }
  1734. Kernel32ProcessInitPostImportFunction = NULL;
  1735. if (st != STATUS_PROCEDURE_NOT_FOUND) {
  1736. return st;
  1737. }
  1738. }
  1739. }
  1740. LDRP_CHECKPOINT();
  1741. st = LdrpWalkImportDescriptor (LdrpDefaultPath.Buffer, LdrpImageEntry);
  1742. if (!NT_SUCCESS(st)) {
  1743. DbgPrintEx(
  1744. DPFLTR_LDR_ID,
  1745. LDR_ERROR_DPFLTR,
  1746. "LDR: %s - call to LdrpWalkImportDescriptor failed with status %x\n",
  1747. __FUNCTION__,
  1748. st);
  1749. //
  1750. // This failure is fatal and we must not run the process.
  1751. //
  1752. return st;
  1753. }
  1754. LDRP_CHECKPOINT();
  1755. if ((PVOID)NtHeader->OptionalHeader.ImageBase != Peb->ImageBaseAddress) {
  1756. //
  1757. // The executable is not at its original address. It must be
  1758. // relocated now.
  1759. //
  1760. PVOID ViewBase;
  1761. ViewBase = Peb->ImageBaseAddress;
  1762. st = LdrpSetProtection (ViewBase, FALSE);
  1763. if (!NT_SUCCESS(st)) {
  1764. DbgPrintEx(
  1765. DPFLTR_LDR_ID,
  1766. LDR_ERROR_DPFLTR,
  1767. "LDR: %s - call to LdrpSetProtection(%p, FALSE) failed with status %x\n",
  1768. __FUNCTION__,
  1769. ViewBase,
  1770. st);
  1771. return st;
  1772. }
  1773. st = LdrRelocateImage (ViewBase,
  1774. "LDR",
  1775. STATUS_SUCCESS,
  1776. STATUS_CONFLICTING_ADDRESSES,
  1777. STATUS_INVALID_IMAGE_FORMAT);
  1778. if (!NT_SUCCESS(st)) {
  1779. DbgPrintEx(
  1780. DPFLTR_LDR_ID,
  1781. LDR_ERROR_DPFLTR,
  1782. "LDR: %s - call to LdrRelocateImage failed with status %x\n",
  1783. __FUNCTION__,
  1784. st);
  1785. return st;
  1786. }
  1787. //
  1788. // Update the initial thread context record as per the relocation.
  1789. //
  1790. if ((Context != NULL) && (UseCOR == FALSE)) {
  1791. OldBase = NtHeader->OptionalHeader.ImageBase;
  1792. Diff = (PCHAR)ViewBase - (PCHAR)OldBase;
  1793. LdrpRelocateStartContext (Context, Diff);
  1794. }
  1795. st = LdrpSetProtection (ViewBase, TRUE);
  1796. if (!NT_SUCCESS (st)) {
  1797. DbgPrintEx(
  1798. DPFLTR_LDR_ID,
  1799. LDR_ERROR_DPFLTR,
  1800. "LDR: %s - call to LdrpSetProtection(%p, TRUE) failed with status %x\n",
  1801. __FUNCTION__,
  1802. ViewBase,
  1803. st);
  1804. return st;
  1805. }
  1806. }
  1807. LDRP_CHECKPOINT();
  1808. LdrpReferenceLoadedDll (LdrpImageEntry);
  1809. //
  1810. // Lock the loaded DLLs to prevent dlls that back link to the exe from
  1811. // causing problems when they are unloaded.
  1812. //
  1813. Head = &Ldr->InLoadOrderModuleList;
  1814. Next = Head->Flink;
  1815. while (Next != Head) {
  1816. Entry = CONTAINING_RECORD (Next,
  1817. LDR_DATA_TABLE_ENTRY,
  1818. InLoadOrderLinks);
  1819. Entry->LoadCount = 0xffff;
  1820. Next = Next->Flink;
  1821. }
  1822. //
  1823. // All static DLLs are now pinned in place. No init routines
  1824. // have been run yet.
  1825. //
  1826. LdrpLdrDatabaseIsSetup = TRUE;
  1827. LDRP_CHECKPOINT();
  1828. st = LdrpInitializeTls ();
  1829. if (!NT_SUCCESS(st)) {
  1830. DbgPrintEx (DPFLTR_LDR_ID,
  1831. LDR_ERROR_DPFLTR,
  1832. "LDR: %s - failed to initialize TLS slots; status %x\n",
  1833. __FUNCTION__,
  1834. st);
  1835. return st;
  1836. }
  1837. #if defined(_X86_)
  1838. //
  1839. // Register initial dll ranges with the stack tracing module.
  1840. // This is used for getting reliable stack traces on X86.
  1841. //
  1842. Head = &Ldr->InMemoryOrderModuleList;
  1843. Next = Head->Flink;
  1844. while (Next != Head) {
  1845. Entry = CONTAINING_RECORD (Next,
  1846. LDR_DATA_TABLE_ENTRY,
  1847. InMemoryOrderLinks);
  1848. RtlpStkMarkDllRange (Entry);
  1849. Next = Next->Flink;
  1850. }
  1851. #endif
  1852. //
  1853. // Now that all DLLs are loaded, if the process is being debugged,
  1854. // signal the debugger with an exception.
  1855. //
  1856. if (Peb->BeingDebugged) {
  1857. DbgBreakPoint ();
  1858. ShowSnaps = (BOOLEAN)((FLG_SHOW_LDR_SNAPS & Peb->NtGlobalFlag) != 0);
  1859. }
  1860. LDRP_CHECKPOINT();
  1861. #if defined (_X86_)
  1862. if (LdrpNumberOfProcessors > 1) {
  1863. LdrpValidateImageForMp (LdrDataTableEntry);
  1864. }
  1865. #endif
  1866. #if DBG
  1867. if (LdrpDisplayLoadTime) {
  1868. NtQueryPerformanceCounter (&InitbTime, NULL);
  1869. }
  1870. #endif
  1871. //
  1872. // Check for shimmed apps if necessary
  1873. //
  1874. if (pAppCompatExeData != NULL) {
  1875. Peb->AppCompatInfo = NULL;
  1876. //
  1877. // The name of the engine is the first thing in the appcompat structure.
  1878. //
  1879. LdrpLoadShimEngine ((WCHAR*)pAppCompatExeData,
  1880. &UnicodeImageName,
  1881. pAppCompatExeData);
  1882. }
  1883. else {
  1884. //
  1885. // Get all application goo here (hacks, flags, etc.)
  1886. //
  1887. LdrQueryApplicationCompatibilityGoo (&UnicodeImageName,
  1888. ImageFileOptionsPresent);
  1889. }
  1890. LDRP_CHECKPOINT();
  1891. st = LdrpRunInitializeRoutines (Context);
  1892. if (!NT_SUCCESS(st)) {
  1893. DbgPrintEx(
  1894. DPFLTR_LDR_ID,
  1895. LDR_ERROR_DPFLTR,
  1896. "LDR: %s - Failed running initialization routines; status %x\n",
  1897. __FUNCTION__,
  1898. st);
  1899. return st;
  1900. }
  1901. //
  1902. // Shim engine callback.
  1903. //
  1904. if (g_pfnSE_InstallAfterInit != NULL) {
  1905. if (!(*g_pfnSE_InstallAfterInit) (&UnicodeImageName, pAppCompatExeData)) {
  1906. LdrpUnloadShimEngine ();
  1907. }
  1908. }
  1909. if (Peb->PostProcessInitRoutine != NULL) {
  1910. (Peb->PostProcessInitRoutine) ();
  1911. }
  1912. LDRP_CHECKPOINT();
  1913. return STATUS_SUCCESS;
  1914. }
  1915. VOID
  1916. LdrShutdownProcess (
  1917. VOID
  1918. )
  1919. /*++
  1920. Routine Description:
  1921. This function is called by a process that is terminating cleanly.
  1922. It's purpose is to call all of the processes DLLs to notify them
  1923. that the process is detaching.
  1924. Arguments:
  1925. None
  1926. Return Value:
  1927. None.
  1928. --*/
  1929. {
  1930. PTEB Teb;
  1931. PPEB Peb;
  1932. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  1933. PDLL_INIT_ROUTINE InitRoutine;
  1934. PLIST_ENTRY Next;
  1935. UNICODE_STRING CommandLine;
  1936. //
  1937. // Only unload once - ie: guard against Dll termination routines that
  1938. // might call exit process in fatal situations.
  1939. //
  1940. if (LdrpShutdownInProgress) {
  1941. return;
  1942. }
  1943. //
  1944. // Notify the shim engine that the process is exiting.
  1945. //
  1946. if (g_pfnSE_ProcessDying) {
  1947. (*g_pfnSE_ProcessDying) ();
  1948. }
  1949. Teb = NtCurrentTeb();
  1950. Peb = Teb->ProcessEnvironmentBlock;
  1951. if (ShowSnaps) {
  1952. CommandLine = Peb->ProcessParameters->CommandLine;
  1953. if (!(Peb->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
  1954. CommandLine.Buffer = (PWSTR)((PCHAR)CommandLine.Buffer + (ULONG_PTR)(Peb->ProcessParameters));
  1955. }
  1956. DbgPrint ("LDR: PID: 0x%x finished - '%wZ'\n",
  1957. Teb->ClientId.UniqueProcess,
  1958. &CommandLine);
  1959. }
  1960. LdrpShutdownThreadId = Teb->ClientId.UniqueThread;
  1961. LdrpShutdownInProgress = TRUE;
  1962. RtlEnterCriticalSection (&LdrpLoaderLock);
  1963. try {
  1964. //
  1965. // NTRAID#NTBUG9-399703-2001/05/21-SilviuC
  1966. // check for process heap lock does not
  1967. // offer enough protection. The if below is not enough to prevent
  1968. // deadlocks in dll init code due to waiting for critical sections
  1969. // orphaned by terminating all threads (except this one).
  1970. //
  1971. // A better way to implement this would be to iterate all
  1972. // critical sections and figure out if any of them is abandoned
  1973. // with an owner thread different than this one. If yes then we
  1974. // probably should not call dll init routines. The code
  1975. // right now is deadlock-prone.
  1976. //
  1977. // Check to see if the heap is locked. If so, do not do ANY
  1978. // dll processing since it is very likely that a dll will need
  1979. // to do heap operations, but that the heap is not in good shape.
  1980. // ExitProcess called in a very active app can leave threads
  1981. // terminated in the middle of the heap code or in other very
  1982. // bad places. Checking the heap lock is a good indication that
  1983. // the process was very active when it called ExitProcess.
  1984. //
  1985. if (RtlpHeapIsLocked (Peb->ProcessHeap) == FALSE) {
  1986. //
  1987. // If tracing was ever turned on then cleanup the things here.
  1988. //
  1989. if (USER_SHARED_DATA->TraceLogging) {
  1990. ShutDownEtwHandles ();
  1991. }
  1992. //
  1993. // NOTICE-2001/05/21-SilviuC
  1994. // IMPORTANT NOTE. We cannot do heap validation here no matter
  1995. // how much we would like to because we have just unconditionally
  1996. // terminated all the other threads and this could have left
  1997. // heaps in some weird state. For instance a heap might have
  1998. // been destroyed but we did not manage to get it out of the
  1999. // process heap list and we will still try to validate it.
  2000. // In the future all this type of code should be implemented
  2001. // in appverifier.
  2002. //
  2003. //
  2004. // Go in reverse order initialization order and build
  2005. // the unload list.
  2006. //
  2007. Next = PebLdr.InInitializationOrderModuleList.Blink;
  2008. while (Next != &PebLdr.InInitializationOrderModuleList) {
  2009. LdrDataTableEntry
  2010. = (PLDR_DATA_TABLE_ENTRY)
  2011. (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks));
  2012. Next = Next->Blink;
  2013. //
  2014. // Walk through the entire list looking for
  2015. // entries. For each entry that has an init
  2016. // routine, call it.
  2017. //
  2018. if (Peb->ImageBaseAddress != LdrDataTableEntry->DllBase) {
  2019. InitRoutine = (PDLL_INIT_ROUTINE)(ULONG_PTR)LdrDataTableEntry->EntryPoint;
  2020. if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) {
  2021. LDRP_ACTIVATE_ACTIVATION_CONTEXT(LdrDataTableEntry);
  2022. if ( LdrDataTableEntry->TlsIndex) {
  2023. LdrpCallTlsInitializers(LdrDataTableEntry->DllBase,DLL_PROCESS_DETACH);
  2024. }
  2025. LdrpCallInitRoutine(InitRoutine,
  2026. LdrDataTableEntry->DllBase,
  2027. DLL_PROCESS_DETACH,
  2028. (PVOID)1);
  2029. LDRP_DEACTIVATE_ACTIVATION_CONTEXT();
  2030. }
  2031. }
  2032. }
  2033. //
  2034. // If the image has tls than call its initializers
  2035. //
  2036. if (LdrpImageHasTls) {
  2037. LDRP_ACTIVATE_ACTIVATION_CONTEXT(LdrpImageEntry);
  2038. LdrpCallTlsInitializers(Peb->ImageBaseAddress,DLL_PROCESS_DETACH);
  2039. LDRP_DEACTIVATE_ACTIVATION_CONTEXT();
  2040. }
  2041. }
  2042. //
  2043. // This is a good moment to call automated heap leak detection since
  2044. // we just called all DllMain's with PROCESS_DETACH and therefore we
  2045. // offered all cleanup opportunities we can offer.
  2046. //
  2047. RtlDetectHeapLeaks ();
  2048. //
  2049. // Now Deinitialize the Etw stuff. This needs to happen
  2050. // AFTER DLL_PROCESS_DETACH because the critsect cannot
  2051. // be deleted for DLLs who de-register during detach.
  2052. //
  2053. EtwpDeinitializeDll ();
  2054. } finally {
  2055. RtlLeaveCriticalSection (&LdrpLoaderLock);
  2056. }
  2057. }
  2058. VOID
  2059. LdrShutdownThread (
  2060. VOID
  2061. )
  2062. /*++
  2063. Routine Description:
  2064. This function is called by a thread that is terminating cleanly.
  2065. It's purpose is to call all of the processes DLLs to notify them
  2066. that the thread is detaching.
  2067. Arguments:
  2068. None.
  2069. Return Value:
  2070. None.
  2071. --*/
  2072. {
  2073. PPEB Peb;
  2074. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  2075. PDLL_INIT_ROUTINE InitRoutine;
  2076. PLIST_ENTRY Next;
  2077. ULONG Flags;
  2078. Peb = NtCurrentPeb ();
  2079. //
  2080. // If the heap tracing was ever turned on then do the cleaning
  2081. // stuff here.
  2082. //
  2083. if (USER_SHARED_DATA->TraceLogging){
  2084. CleanOnThreadExit ();
  2085. }
  2086. RtlEnterCriticalSection (&LdrpLoaderLock);
  2087. __try {
  2088. //
  2089. // Walk in the reverse direction of initialization order to build
  2090. // the unload list.
  2091. //
  2092. Next = PebLdr.InInitializationOrderModuleList.Blink;
  2093. while (Next != &PebLdr.InInitializationOrderModuleList) {
  2094. LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)
  2095. (CONTAINING_RECORD (Next,
  2096. LDR_DATA_TABLE_ENTRY,
  2097. InInitializationOrderLinks));
  2098. Next = Next->Blink;
  2099. Flags = LdrDataTableEntry->Flags;
  2100. //
  2101. // Walk through the entire list looking for
  2102. // entries. For each entry, that has an init
  2103. // routine, call it.
  2104. //
  2105. if ((Peb->ImageBaseAddress != LdrDataTableEntry->DllBase) &&
  2106. (!(Flags & LDRP_DONT_CALL_FOR_THREADS)) &&
  2107. (LdrDataTableEntry->EntryPoint != NULL) &&
  2108. (Flags & LDRP_PROCESS_ATTACH_CALLED) &&
  2109. (Flags & LDRP_IMAGE_DLL)) {
  2110. InitRoutine = (PDLL_INIT_ROUTINE)(ULONG_PTR)LdrDataTableEntry->EntryPoint;
  2111. LDRP_ACTIVATE_ACTIVATION_CONTEXT(LdrDataTableEntry);
  2112. if (LdrDataTableEntry->TlsIndex) {
  2113. LdrpCallTlsInitializers (LdrDataTableEntry->DllBase,
  2114. DLL_THREAD_DETACH);
  2115. }
  2116. LdrpCallInitRoutine (InitRoutine,
  2117. LdrDataTableEntry->DllBase,
  2118. DLL_THREAD_DETACH,
  2119. NULL);
  2120. LDRP_DEACTIVATE_ACTIVATION_CONTEXT();
  2121. }
  2122. }
  2123. //
  2124. // If the image has TLS than call its initializers.
  2125. //
  2126. if (LdrpImageHasTls) {
  2127. LDRP_ACTIVATE_ACTIVATION_CONTEXT(LdrpImageEntry);
  2128. LdrpCallTlsInitializers (Peb->ImageBaseAddress, DLL_THREAD_DETACH);
  2129. LDRP_DEACTIVATE_ACTIVATION_CONTEXT();
  2130. }
  2131. LdrpFreeTls ();
  2132. } __finally {
  2133. RtlLeaveCriticalSection (&LdrpLoaderLock);
  2134. }
  2135. }
  2136. VOID
  2137. LdrpInitializeThread (
  2138. IN PCONTEXT Context
  2139. )
  2140. /*++
  2141. Routine Description:
  2142. This function is called by each thread as it starts.
  2143. Its purpose is to call all of the process' DLLs to notify them
  2144. that the thread is starting up.
  2145. Arguments:
  2146. Context - Context that will be restored after loader initializes.
  2147. Return Value:
  2148. None.
  2149. --*/
  2150. {
  2151. PPEB Peb;
  2152. PLIST_ENTRY Next;
  2153. PDLL_INIT_ROUTINE InitRoutine;
  2154. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  2155. UNREFERENCED_PARAMETER (Context);
  2156. Peb = NtCurrentPeb ();
  2157. if (LdrpShutdownInProgress) {
  2158. return;
  2159. }
  2160. RtlEnterCriticalSection (&LdrpLoaderLock);
  2161. __try {
  2162. LdrpAllocateTls ();
  2163. Next = PebLdr.InMemoryOrderModuleList.Flink;
  2164. while (Next != &PebLdr.InMemoryOrderModuleList) {
  2165. LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)
  2166. (CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
  2167. //
  2168. // Walk through the entire list looking for
  2169. // entries. For each entry, that has an init
  2170. // routine, call it.
  2171. //
  2172. if ((Peb->ImageBaseAddress != LdrDataTableEntry->DllBase) &&
  2173. (!(LdrDataTableEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))) {
  2174. InitRoutine = (PDLL_INIT_ROUTINE)(ULONG_PTR)LdrDataTableEntry->EntryPoint;
  2175. if ((InitRoutine) &&
  2176. (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
  2177. (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL)) {
  2178. LDRP_ACTIVATE_ACTIVATION_CONTEXT (LdrDataTableEntry);
  2179. if (LdrDataTableEntry->TlsIndex) {
  2180. if (!LdrpShutdownInProgress) {
  2181. LdrpCallTlsInitializers (LdrDataTableEntry->DllBase,
  2182. DLL_THREAD_ATTACH);
  2183. }
  2184. }
  2185. if (!LdrpShutdownInProgress) {
  2186. LdrpCallInitRoutine (InitRoutine,
  2187. LdrDataTableEntry->DllBase,
  2188. DLL_THREAD_ATTACH,
  2189. NULL);
  2190. }
  2191. LDRP_DEACTIVATE_ACTIVATION_CONTEXT ();
  2192. }
  2193. }
  2194. Next = Next->Flink;
  2195. }
  2196. //
  2197. // If the image has TLS than call its initializers.
  2198. //
  2199. if (LdrpImageHasTls && !LdrpShutdownInProgress) {
  2200. LDRP_ACTIVATE_ACTIVATION_CONTEXT (LdrpImageEntry);
  2201. LdrpCallTlsInitializers (Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
  2202. LDRP_DEACTIVATE_ACTIVATION_CONTEXT ();
  2203. }
  2204. } __finally {
  2205. RtlLeaveCriticalSection (&LdrpLoaderLock);
  2206. }
  2207. }
  2208. NTSTATUS
  2209. LdrpOpenImageFileOptionsKey (
  2210. IN PCUNICODE_STRING ImagePathName,
  2211. IN BOOLEAN Wow64Path,
  2212. OUT PHANDLE KeyHandle
  2213. )
  2214. {
  2215. ULONG UnicodeStringLength, l;
  2216. PWSTR pw;
  2217. OBJECT_ATTRIBUTES ObjectAttributes;
  2218. UNICODE_STRING KeyPath;
  2219. WCHAR KeyPathBuffer[ DOS_MAX_COMPONENT_LENGTH + 100 ];
  2220. PWCHAR p;
  2221. PWCHAR BasePath;
  2222. p = KeyPathBuffer;
  2223. #define STRTMP L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"
  2224. #define STRTMP_WOW64 L"\\Registry\\Machine\\Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"
  2225. if (Wow64Path == TRUE) {
  2226. BasePath = STRTMP_WOW64;
  2227. l = sizeof (STRTMP_WOW64) - sizeof (WCHAR);
  2228. } else {
  2229. BasePath = STRTMP;
  2230. l = sizeof (STRTMP) - sizeof (WCHAR);
  2231. }
  2232. if (l > sizeof (KeyPathBuffer)) {
  2233. return STATUS_BUFFER_TOO_SMALL;
  2234. }
  2235. RtlCopyMemory (p, BasePath, l);
  2236. p += (l / sizeof (WCHAR));
  2237. UnicodeStringLength = ImagePathName->Length;
  2238. pw = (PWSTR)((PCHAR)ImagePathName->Buffer + UnicodeStringLength);
  2239. while (UnicodeStringLength != 0) {
  2240. if (pw[ -1 ] == OBJ_NAME_PATH_SEPARATOR) {
  2241. break;
  2242. }
  2243. pw--;
  2244. UnicodeStringLength -= sizeof( *pw );
  2245. }
  2246. UnicodeStringLength = ImagePathName->Length - UnicodeStringLength;
  2247. l = l + UnicodeStringLength;
  2248. if (l > sizeof (KeyPathBuffer)) {
  2249. return STATUS_BUFFER_TOO_SMALL;
  2250. }
  2251. RtlCopyMemory (p, pw, UnicodeStringLength);
  2252. KeyPath.Buffer = KeyPathBuffer;
  2253. KeyPath.Length = (USHORT) l;
  2254. InitializeObjectAttributes (&ObjectAttributes,
  2255. &KeyPath,
  2256. OBJ_CASE_INSENSITIVE,
  2257. NULL,
  2258. NULL);
  2259. return NtOpenKey (KeyHandle, GENERIC_READ, &ObjectAttributes);
  2260. }
  2261. NTSTATUS
  2262. LdrpQueryImageFileKeyOption (
  2263. IN HANDLE KeyHandle,
  2264. IN PCWSTR OptionName,
  2265. IN ULONG Type,
  2266. OUT PVOID Buffer,
  2267. IN ULONG BufferSize,
  2268. OUT PULONG ResultSize OPTIONAL
  2269. )
  2270. {
  2271. NTSTATUS Status;
  2272. UNICODE_STRING UnicodeString;
  2273. ULONG KeyValueBuffer [256];
  2274. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  2275. ULONG AllocLength;
  2276. ULONG ResultLength;
  2277. HANDLE ProcessHeap = 0;
  2278. Status = RtlInitUnicodeStringEx (&UnicodeString, OptionName);
  2279. if (!NT_SUCCESS( Status )) {
  2280. return Status;
  2281. }
  2282. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) &KeyValueBuffer[0];
  2283. Status = NtQueryValueKey (KeyHandle,
  2284. &UnicodeString,
  2285. KeyValuePartialInformation,
  2286. KeyValueInformation,
  2287. sizeof (KeyValueBuffer),
  2288. &ResultLength);
  2289. if (Status == STATUS_BUFFER_OVERFLOW) {
  2290. //
  2291. // This function can be called before the process heap gets created
  2292. // therefore we need to protect against this case. The majority of the
  2293. // code will not hit this code path because they read just strings
  2294. // containing hex numbers and for this the size of KeyValueBuffer is
  2295. // more than sufficient.
  2296. //
  2297. ProcessHeap = RtlProcessHeap ();
  2298. if (!ProcessHeap) {
  2299. return STATUS_NO_MEMORY;
  2300. }
  2301. AllocLength = sizeof (*KeyValueInformation) +
  2302. KeyValueInformation->DataLength;
  2303. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap (ProcessHeap,
  2304. MAKE_TAG (TEMP_TAG),
  2305. AllocLength);
  2306. if (KeyValueInformation == NULL) {
  2307. return STATUS_NO_MEMORY;
  2308. }
  2309. Status = NtQueryValueKey (KeyHandle,
  2310. &UnicodeString,
  2311. KeyValuePartialInformation,
  2312. KeyValueInformation,
  2313. AllocLength,
  2314. &ResultLength);
  2315. }
  2316. if (NT_SUCCESS( Status )) {
  2317. if (KeyValueInformation->Type == REG_BINARY) {
  2318. if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize)) {
  2319. RtlCopyMemory (Buffer,
  2320. &KeyValueInformation->Data,
  2321. KeyValueInformation->DataLength);
  2322. }
  2323. else {
  2324. Status = STATUS_BUFFER_OVERFLOW;
  2325. }
  2326. if (ARGUMENT_PRESENT( ResultSize )) {
  2327. *ResultSize = KeyValueInformation->DataLength;
  2328. }
  2329. }
  2330. else if (KeyValueInformation->Type == REG_DWORD) {
  2331. if (Type != REG_DWORD) {
  2332. Status = STATUS_OBJECT_TYPE_MISMATCH;
  2333. }
  2334. else {
  2335. if ((Buffer)
  2336. && (BufferSize == sizeof(ULONG))
  2337. && (KeyValueInformation->DataLength == BufferSize)) {
  2338. RtlCopyMemory (Buffer,
  2339. &KeyValueInformation->Data,
  2340. KeyValueInformation->DataLength);
  2341. }
  2342. else {
  2343. Status = STATUS_BUFFER_OVERFLOW;
  2344. }
  2345. if (ARGUMENT_PRESENT( ResultSize )) {
  2346. *ResultSize = KeyValueInformation->DataLength;
  2347. }
  2348. }
  2349. }
  2350. else if (KeyValueInformation->Type != REG_SZ) {
  2351. Status = STATUS_OBJECT_TYPE_MISMATCH;
  2352. }
  2353. else {
  2354. if (Type == REG_DWORD) {
  2355. if (BufferSize != sizeof( ULONG )) {
  2356. BufferSize = 0;
  2357. Status = STATUS_INFO_LENGTH_MISMATCH;
  2358. }
  2359. else {
  2360. UnicodeString.Buffer = (PWSTR)&KeyValueInformation->Data;
  2361. UnicodeString.Length = (USHORT)
  2362. (KeyValueInformation->DataLength - sizeof( UNICODE_NULL ));
  2363. UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
  2364. Status = RtlUnicodeStringToInteger( &UnicodeString, 0, (PULONG)Buffer );
  2365. }
  2366. }
  2367. else {
  2368. if (KeyValueInformation->DataLength > BufferSize) {
  2369. Status = STATUS_BUFFER_OVERFLOW;
  2370. }
  2371. else {
  2372. BufferSize = KeyValueInformation->DataLength;
  2373. }
  2374. RtlCopyMemory (Buffer, &KeyValueInformation->Data, BufferSize);
  2375. }
  2376. if (ARGUMENT_PRESENT( ResultSize )) {
  2377. *ResultSize = BufferSize;
  2378. }
  2379. }
  2380. }
  2381. if (KeyValueInformation != (PKEY_VALUE_PARTIAL_INFORMATION) &KeyValueBuffer[0]) {
  2382. RtlFreeHeap (ProcessHeap, 0, KeyValueInformation);
  2383. }
  2384. return Status;
  2385. }
  2386. NTSTATUS
  2387. LdrQueryImageFileExecutionOptionsEx(
  2388. IN PCUNICODE_STRING ImagePathName,
  2389. IN PCWSTR OptionName,
  2390. IN ULONG Type,
  2391. OUT PVOID Buffer,
  2392. IN ULONG BufferSize,
  2393. OUT PULONG ResultSize OPTIONAL,
  2394. IN BOOLEAN Wow64Path
  2395. )
  2396. {
  2397. NTSTATUS Status;
  2398. HANDLE KeyHandle;
  2399. Status = LdrpOpenImageFileOptionsKey (ImagePathName, Wow64Path, &KeyHandle);
  2400. if (NT_SUCCESS (Status)) {
  2401. Status = LdrpQueryImageFileKeyOption (KeyHandle,
  2402. OptionName,
  2403. Type,
  2404. Buffer,
  2405. BufferSize,
  2406. ResultSize);
  2407. NtClose (KeyHandle);
  2408. }
  2409. return Status;
  2410. }
  2411. NTSTATUS
  2412. LdrQueryImageFileExecutionOptions(
  2413. IN PCUNICODE_STRING ImagePathName,
  2414. IN PCWSTR OptionName,
  2415. IN ULONG Type,
  2416. OUT PVOID Buffer,
  2417. IN ULONG BufferSize,
  2418. OUT PULONG ResultSize OPTIONAL
  2419. )
  2420. {
  2421. return LdrQueryImageFileExecutionOptionsEx (
  2422. ImagePathName,
  2423. OptionName,
  2424. Type,
  2425. Buffer,
  2426. BufferSize,
  2427. ResultSize,
  2428. FALSE
  2429. );
  2430. }
  2431. NTSTATUS
  2432. LdrpInitializeTls (
  2433. VOID
  2434. )
  2435. {
  2436. PLDR_DATA_TABLE_ENTRY Entry;
  2437. PLIST_ENTRY Head,Next;
  2438. PIMAGE_TLS_DIRECTORY TlsImage;
  2439. PLDRP_TLS_ENTRY TlsEntry;
  2440. ULONG TlsSize;
  2441. LOGICAL FirstTimeThru;
  2442. HANDLE ProcessHeap;
  2443. ProcessHeap = RtlProcessHeap();
  2444. FirstTimeThru = TRUE;
  2445. InitializeListHead (&LdrpTlsList);
  2446. //
  2447. // Walk through the loaded modules and look for TLS. If we find TLS,
  2448. // lock in the module and add to the TLS chain.
  2449. //
  2450. Head = &PebLdr.InLoadOrderModuleList;
  2451. Next = Head->Flink;
  2452. while (Next != Head) {
  2453. Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  2454. Next = Next->Flink;
  2455. TlsImage = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData(
  2456. Entry->DllBase,
  2457. TRUE,
  2458. IMAGE_DIRECTORY_ENTRY_TLS,
  2459. &TlsSize);
  2460. //
  2461. // Mark whether or not the image file has TLS.
  2462. //
  2463. if (FirstTimeThru) {
  2464. FirstTimeThru = FALSE;
  2465. if (TlsImage && !LdrpImageHasTls) {
  2466. RtlpSerializeHeap (ProcessHeap);
  2467. LdrpImageHasTls = TRUE;
  2468. }
  2469. }
  2470. if (TlsImage) {
  2471. if (ShowSnaps) {
  2472. DbgPrint( "LDR: Tls Found in %wZ at %p\n",
  2473. &Entry->BaseDllName,
  2474. TlsImage);
  2475. }
  2476. TlsEntry = (PLDRP_TLS_ENTRY)RtlAllocateHeap(ProcessHeap,MAKE_TAG( TLS_TAG ),sizeof(*TlsEntry));
  2477. if ( !TlsEntry ) {
  2478. return STATUS_NO_MEMORY;
  2479. }
  2480. //
  2481. // Since this DLL has TLS, lock it in
  2482. //
  2483. Entry->LoadCount = (USHORT)0xffff;
  2484. //
  2485. // Mark this as having thread local storage
  2486. //
  2487. Entry->TlsIndex = (USHORT)0xffff;
  2488. TlsEntry->Tls = *TlsImage;
  2489. InsertTailList(&LdrpTlsList,&TlsEntry->Links);
  2490. //
  2491. // Update the index for this dll's thread local storage
  2492. //
  2493. *(PLONG)TlsEntry->Tls.AddressOfIndex = LdrpNumberOfTlsEntries;
  2494. TlsEntry->Tls.Characteristics = LdrpNumberOfTlsEntries++;
  2495. }
  2496. }
  2497. //
  2498. // We now have walked through all static DLLs and know
  2499. // all DLLs that reference thread local storage. Now we
  2500. // just have to allocate the thread local storage for the current
  2501. // thread and for all subsequent threads.
  2502. //
  2503. return LdrpAllocateTls ();
  2504. }
  2505. NTSTATUS
  2506. LdrpAllocateTls (
  2507. VOID
  2508. )
  2509. {
  2510. PTEB Teb;
  2511. PLIST_ENTRY Head, Next;
  2512. PLDRP_TLS_ENTRY TlsEntry;
  2513. PVOID *TlsVector;
  2514. HANDLE ProcessHeap;
  2515. //
  2516. // Allocate the array of thread local storage pointers
  2517. //
  2518. if (LdrpNumberOfTlsEntries) {
  2519. Teb = NtCurrentTeb();
  2520. ProcessHeap = Teb->ProcessEnvironmentBlock->ProcessHeap;
  2521. TlsVector = (PVOID *)RtlAllocateHeap(ProcessHeap,MAKE_TAG( TLS_TAG ),sizeof(PVOID)*LdrpNumberOfTlsEntries);
  2522. if (!TlsVector) {
  2523. return STATUS_NO_MEMORY;
  2524. }
  2525. //
  2526. // NOTICE-2002/03/14-ELi
  2527. // Zero out the new array of pointers, LdrpFreeTls frees the pointers
  2528. // if the pointers are non-NULL
  2529. //
  2530. RtlZeroMemory( TlsVector, sizeof(PVOID)*LdrpNumberOfTlsEntries );
  2531. Teb->ThreadLocalStoragePointer = TlsVector;
  2532. Head = &LdrpTlsList;
  2533. Next = Head->Flink;
  2534. while (Next != Head) {
  2535. TlsEntry = CONTAINING_RECORD(Next, LDRP_TLS_ENTRY, Links);
  2536. Next = Next->Flink;
  2537. TlsVector[TlsEntry->Tls.Characteristics] = RtlAllocateHeap(
  2538. ProcessHeap,
  2539. MAKE_TAG( TLS_TAG ),
  2540. TlsEntry->Tls.EndAddressOfRawData - TlsEntry->Tls.StartAddressOfRawData
  2541. );
  2542. if (!TlsVector[TlsEntry->Tls.Characteristics] ) {
  2543. return STATUS_NO_MEMORY;
  2544. }
  2545. if (ShowSnaps) {
  2546. DbgPrint("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
  2547. TlsVector,
  2548. TlsEntry->Tls.Characteristics,
  2549. &TlsVector[TlsEntry->Tls.Characteristics],
  2550. TlsEntry->Tls.StartAddressOfRawData,
  2551. TlsVector[TlsEntry->Tls.Characteristics]);
  2552. }
  2553. //
  2554. // Do the TLS Callouts
  2555. //
  2556. RtlCopyMemory (
  2557. TlsVector[TlsEntry->Tls.Characteristics],
  2558. (PVOID)TlsEntry->Tls.StartAddressOfRawData,
  2559. TlsEntry->Tls.EndAddressOfRawData - TlsEntry->Tls.StartAddressOfRawData
  2560. );
  2561. }
  2562. }
  2563. return STATUS_SUCCESS;
  2564. }
  2565. VOID
  2566. LdrpFreeTls (
  2567. VOID
  2568. )
  2569. {
  2570. PTEB Teb;
  2571. PLIST_ENTRY Head, Next;
  2572. PLDRP_TLS_ENTRY TlsEntry;
  2573. PVOID *TlsVector;
  2574. HANDLE ProcessHeap;
  2575. Teb = NtCurrentTeb();
  2576. TlsVector = Teb->ThreadLocalStoragePointer;
  2577. if (TlsVector) {
  2578. ProcessHeap = Teb->ProcessEnvironmentBlock->ProcessHeap;
  2579. Head = &LdrpTlsList;
  2580. Next = Head->Flink;
  2581. while (Next != Head) {
  2582. TlsEntry = CONTAINING_RECORD(Next, LDRP_TLS_ENTRY, Links);
  2583. Next = Next->Flink;
  2584. //
  2585. // Do the TLS callouts
  2586. //
  2587. if (TlsVector[TlsEntry->Tls.Characteristics]) {
  2588. RtlFreeHeap (ProcessHeap,
  2589. 0,
  2590. TlsVector[TlsEntry->Tls.Characteristics]);
  2591. }
  2592. }
  2593. RtlFreeHeap (ProcessHeap, 0, TlsVector);
  2594. }
  2595. }
  2596. VOID
  2597. LdrpCallTlsInitializers (
  2598. IN PVOID DllBase,
  2599. IN ULONG Reason
  2600. )
  2601. {
  2602. PIMAGE_TLS_DIRECTORY TlsImage;
  2603. ULONG TlsSize;
  2604. PIMAGE_TLS_CALLBACK *CallBackArray;
  2605. PIMAGE_TLS_CALLBACK InitRoutine;
  2606. TlsImage = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData(
  2607. DllBase,
  2608. TRUE,
  2609. IMAGE_DIRECTORY_ENTRY_TLS,
  2610. &TlsSize
  2611. );
  2612. if (TlsImage) {
  2613. try {
  2614. CallBackArray = (PIMAGE_TLS_CALLBACK *)TlsImage->AddressOfCallBacks;
  2615. if ( CallBackArray ) {
  2616. if (ShowSnaps) {
  2617. DbgPrint( "LDR: Tls Callbacks Found. Imagebase %p Tls %p CallBacks %p\n",
  2618. DllBase,
  2619. TlsImage,
  2620. CallBackArray
  2621. );
  2622. }
  2623. while (*CallBackArray) {
  2624. InitRoutine = *CallBackArray++;
  2625. if (ShowSnaps) {
  2626. DbgPrint( "LDR: Calling Tls Callback Imagebase %p Function %p\n",
  2627. DllBase,
  2628. InitRoutine
  2629. );
  2630. }
  2631. LdrpCallInitRoutine((PDLL_INIT_ROUTINE)InitRoutine,
  2632. DllBase,
  2633. Reason,
  2634. 0);
  2635. }
  2636. }
  2637. }
  2638. except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2639. DbgPrintEx(
  2640. DPFLTR_LDR_ID,
  2641. LDR_ERROR_DPFLTR,
  2642. "LDR: %s - caught exception %08lx calling TLS callbacks\n",
  2643. __FUNCTION__,
  2644. GetExceptionCode());
  2645. }
  2646. }
  2647. }
  2648. ULONG
  2649. GetNextCommaValue (
  2650. IN OUT WCHAR **p,
  2651. IN OUT ULONG *len
  2652. )
  2653. {
  2654. ULONG Number;
  2655. Number = 0;
  2656. while (*len && (UNICODE_NULL != **p) && **p != L',') {
  2657. //
  2658. // Ignore spaces.
  2659. //
  2660. if ( L' ' != **p ) {
  2661. Number = (Number * 10) + ( (ULONG)**p - L'0' );
  2662. }
  2663. (*p)++;
  2664. (*len)--;
  2665. }
  2666. //
  2667. // If we're at a comma, get past it for the next call
  2668. //
  2669. if ((*len) && (L',' == **p)) {
  2670. (*p)++;
  2671. (*len)--;
  2672. }
  2673. return Number;
  2674. }
  2675. VOID
  2676. LdrQueryApplicationCompatibilityGoo (
  2677. IN PCUNICODE_STRING UnicodeImageName,
  2678. IN BOOLEAN ImageFileOptionsPresent
  2679. )
  2680. /*++
  2681. Routine Description:
  2682. This function is called by LdrpInitialize after its initialized the
  2683. process. It's purpose is to query any application specific flags,
  2684. hacks, etc. If any app specific information is found, its hung off
  2685. the PEB for other components to test against.
  2686. Besides setting hanging the AppCompatInfo struct off the PEB, the
  2687. only other action that will occur in here is setting OS version
  2688. numbers in the PEB if the appropriate Version lie app flag is set.
  2689. Arguments:
  2690. UnicodeImageName - Actual image name (including path)
  2691. Return Value:
  2692. None.
  2693. --*/
  2694. {
  2695. PPEB Peb;
  2696. PVOID ResourceInfo;
  2697. ULONG TotalGooLength;
  2698. ULONG AppCompatLength;
  2699. ULONG ResultSize;
  2700. ULONG ResourceSize;
  2701. ULONG InputCompareLength;
  2702. ULONG OutputCompareLength;
  2703. NTSTATUS st;
  2704. LOGICAL ImageContainsVersionResourceInfo;
  2705. ULONG_PTR IdPath[3];
  2706. APP_COMPAT_GOO LocalAppCompatGoo;
  2707. PAPP_COMPAT_GOO AppCompatGoo;
  2708. PAPP_COMPAT_INFO AppCompatInfo;
  2709. PAPP_VARIABLE_INFO AppVariableInfo;
  2710. PPRE_APP_COMPAT_INFO AppCompatEntry;
  2711. PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
  2712. PEFFICIENTOSVERSIONINFOEXW OSVerInfo;
  2713. UNICODE_STRING EnvValue;
  2714. WCHAR *NewCSDString;
  2715. WCHAR TempString[ 128 ]; // is the size of szCSDVersion in OSVERSIONINFOW
  2716. LOGICAL fNewCSDVersionBuffer;
  2717. HANDLE ProcessHeap;
  2718. struct {
  2719. USHORT TotalSize;
  2720. USHORT DataSize;
  2721. USHORT Type;
  2722. WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode nul
  2723. } *Resource;
  2724. //
  2725. // Check execution options to see if there's any Goo for this app.
  2726. // We purposely feed a small struct to LdrQueryImageFileExecOptions,
  2727. // so that it can come back with success/failure, and if success we see
  2728. // how much we need to alloc. As the results coming back will be of
  2729. // variable length.
  2730. //
  2731. fNewCSDVersionBuffer = FALSE;
  2732. Peb = NtCurrentPeb();
  2733. Peb->AppCompatInfo = NULL;
  2734. Peb->AppCompatFlags.QuadPart = 0;
  2735. ProcessHeap = Peb->ProcessHeap;
  2736. if (ImageFileOptionsPresent) {
  2737. st = LdrQueryImageFileExecutionOptions (UnicodeImageName,
  2738. L"ApplicationGoo",
  2739. REG_BINARY,
  2740. &LocalAppCompatGoo,
  2741. sizeof(APP_COMPAT_GOO),
  2742. &ResultSize);
  2743. //
  2744. // If there's an entry there, we're guaranteed to get overflow error.
  2745. //
  2746. if (st == STATUS_BUFFER_OVERFLOW) {
  2747. //
  2748. // Something is there, alloc memory for the "Pre" Goo struct
  2749. // right now.
  2750. //
  2751. AppCompatGoo =
  2752. RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, ResultSize);
  2753. if (!AppCompatGoo) {
  2754. return;
  2755. }
  2756. //
  2757. // Now that we've got the memory, hit it again
  2758. //
  2759. st = LdrQueryImageFileExecutionOptions (UnicodeImageName,
  2760. L"ApplicationGoo",
  2761. REG_BINARY,
  2762. AppCompatGoo,
  2763. ResultSize,
  2764. &ResultSize);
  2765. if (!NT_SUCCESS (st)) {
  2766. RtlFreeHeap (ProcessHeap, 0, AppCompatGoo);
  2767. return;
  2768. }
  2769. //
  2770. // Got a hit on this key, however we don't know fer sure that its
  2771. // an exact match. There could be multiple App Compat entries
  2772. // within this Goo. So we get the version resource information out
  2773. // of the Image hdr (if avail) and later we compare it against
  2774. // all of the entries found within the Goo hoping for a match.
  2775. //
  2776. // Need Language Id in order to query the resource info.
  2777. //
  2778. ImageContainsVersionResourceInfo = FALSE;
  2779. IdPath[0] = 16; // RT_VERSION
  2780. IdPath[1] = 1; // VS_VERSION_INFO
  2781. IdPath[2] = 0; // LangId;
  2782. //
  2783. // Search for version resource information
  2784. //
  2785. DataEntry = NULL;
  2786. Resource = NULL;
  2787. try {
  2788. st = LdrpSearchResourceSection_U (Peb->ImageBaseAddress,
  2789. IdPath,
  2790. 3,
  2791. 0,
  2792. &DataEntry);
  2793. } except(LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2794. st = STATUS_UNSUCCESSFUL;
  2795. }
  2796. if (NT_SUCCESS( st )) {
  2797. //
  2798. // Give us a pointer to the resource information
  2799. //
  2800. try {
  2801. st = LdrpAccessResourceData(
  2802. Peb->ImageBaseAddress,
  2803. DataEntry,
  2804. &Resource,
  2805. &ResourceSize
  2806. );
  2807. } except(LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2808. st = STATUS_UNSUCCESSFUL;
  2809. }
  2810. if (NT_SUCCESS( st )) {
  2811. ImageContainsVersionResourceInfo = TRUE;
  2812. }
  2813. }
  2814. //
  2815. // Now that we either have (or have not) the version resource info,
  2816. // bounce down each app compat entry looking for a match. If there
  2817. // wasn't any version resource info in the image hdr, it's going to
  2818. // be an automatic match to an entry that also doesn't have
  2819. // anything for its version resource info. Obviously there can
  2820. // be only one of these "empty" entries within the Goo (as the
  2821. // first one will always be matched first).
  2822. //
  2823. st = STATUS_SUCCESS;
  2824. AppCompatEntry = AppCompatGoo->AppCompatEntry;
  2825. //
  2826. // NTRAID#NTBUG9-550610-2002/02/21-DavidFie
  2827. // Trusting registry data too much
  2828. //
  2829. TotalGooLength =
  2830. AppCompatGoo->dwTotalGooSize - sizeof(AppCompatGoo->dwTotalGooSize);
  2831. while (TotalGooLength) {
  2832. ResourceInfo = NULL;
  2833. InputCompareLength = 0;
  2834. OutputCompareLength = 0;
  2835. try {
  2836. //
  2837. // Compare what we're told to by the resource info size.
  2838. // The ResourceInfo (if avail) is directly behind the
  2839. // AppCompatEntry.
  2840. //
  2841. InputCompareLength = AppCompatEntry->dwResourceInfoSize;
  2842. ResourceInfo = AppCompatEntry + 1;
  2843. if (ImageContainsVersionResourceInfo) {
  2844. if (InputCompareLength > Resource->TotalSize) {
  2845. InputCompareLength = Resource->TotalSize;
  2846. }
  2847. OutputCompareLength = (ULONG) RtlCompareMemory(
  2848. ResourceInfo,
  2849. Resource,
  2850. InputCompareLength);
  2851. }
  2852. else {
  2853. //
  2854. // In this case, we don't have any version resource
  2855. // info in the image header, so set OutputCompareLength
  2856. // to zero. If InputCompareLength was set to zero
  2857. // above due to the AppCompatEntry also having no
  2858. // version resource info, then the test will succeed
  2859. // (below) and we've found our match. Otherwise,
  2860. // this is not the same app and it won't be a match.
  2861. //
  2862. ASSERT (OutputCompareLength == 0);
  2863. }
  2864. } except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2865. st = STATUS_UNSUCCESSFUL;
  2866. }
  2867. if ((!NT_SUCCESS( st )) ||
  2868. (InputCompareLength != OutputCompareLength)) {
  2869. //
  2870. // Wasn't a match, go to the next entry.
  2871. //
  2872. //
  2873. // NTRAID#NTBUG9-550610-2002/02/21-DavidFie
  2874. // Trusting registry data too much
  2875. //
  2876. TotalGooLength -= AppCompatEntry->dwEntryTotalSize;
  2877. AppCompatEntry = (PPRE_APP_COMPAT_INFO) (
  2878. (PUCHAR)AppCompatEntry + AppCompatEntry->dwEntryTotalSize);
  2879. continue;
  2880. }
  2881. //
  2882. // We're a match - now we have to create the final "Post"
  2883. // app compat structure that will be used by everyone to follow.
  2884. // This guy hangs off the Peb and it doesn't have the resource
  2885. // info still lying around in there.
  2886. //
  2887. AppCompatLength = AppCompatEntry->dwEntryTotalSize;
  2888. AppCompatLength -= AppCompatEntry->dwResourceInfoSize;
  2889. Peb->AppCompatInfo =
  2890. RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, AppCompatLength);
  2891. if (!Peb->AppCompatInfo) {
  2892. break;
  2893. }
  2894. AppCompatInfo = Peb->AppCompatInfo;
  2895. AppCompatInfo->dwTotalSize = AppCompatLength;
  2896. //
  2897. // Copy what was beyond the resource info to near the top
  2898. // starting at the Application compat flags.
  2899. //
  2900. RtlCopyMemory(
  2901. &AppCompatInfo->CompatibilityFlags,
  2902. (PUCHAR) ResourceInfo + AppCompatEntry->dwResourceInfoSize,
  2903. AppCompatInfo->dwTotalSize - FIELD_OFFSET(APP_COMPAT_INFO, CompatibilityFlags)
  2904. );
  2905. //
  2906. // Copy the flags into the PEB. Temporary until we remove
  2907. // the compat goo altogether.
  2908. //
  2909. Peb->AppCompatFlags.QuadPart = AppCompatInfo->CompatibilityFlags.QuadPart;
  2910. //
  2911. // Now that we've created the "Post" app compat info struct
  2912. // to be used by everyone, we need to check if version
  2913. // lying for this app is requested. If so, we need to
  2914. // stuff the Peb right now.
  2915. //
  2916. if (AppCompatInfo->CompatibilityFlags.QuadPart & KACF_VERSIONLIE) {
  2917. //
  2918. // Find the variable version lie struct somewhere within.
  2919. //
  2920. if (LdrFindAppCompatVariableInfo (AVT_OSVERSIONINFO, &AppVariableInfo) != STATUS_SUCCESS) {
  2921. break;
  2922. }
  2923. //
  2924. // The variable length information itself comes at the end
  2925. // of the normal struct and could be of any arbitrary
  2926. // length.
  2927. //
  2928. AppVariableInfo += 1;
  2929. OSVerInfo = (PEFFICIENTOSVERSIONINFOEXW) AppVariableInfo;
  2930. Peb->OSMajorVersion = OSVerInfo->dwMajorVersion;
  2931. Peb->OSMinorVersion = OSVerInfo->dwMinorVersion;
  2932. Peb->OSBuildNumber = (USHORT) OSVerInfo->dwBuildNumber;
  2933. Peb->OSCSDVersion = (OSVerInfo->wServicePackMajor << 8) & 0xFF00;
  2934. Peb->OSCSDVersion |= OSVerInfo->wServicePackMinor;
  2935. Peb->OSPlatformId = OSVerInfo->dwPlatformId;
  2936. //
  2937. // NTRAID#NTBUG9-550610-2002/02/21-DavidFie
  2938. // Trusting registry data too much
  2939. //
  2940. Peb->CSDVersion.Length = (USHORT)wcslen(&OSVerInfo->szCSDVersion[0])*sizeof(WCHAR);
  2941. Peb->CSDVersion.MaximumLength = Peb->CSDVersion.Length + sizeof(WCHAR);
  2942. Peb->CSDVersion.Buffer = (PWSTR)RtlAllocateHeap (
  2943. ProcessHeap,
  2944. 0,
  2945. Peb->CSDVersion.MaximumLength);
  2946. if (!Peb->CSDVersion.Buffer) {
  2947. break;
  2948. }
  2949. RtlCopyMemory(Peb->CSDVersion.Buffer, &OSVerInfo->szCSDVersion[0], Peb->CSDVersion.Length);
  2950. RTL_STRING_NUL_TERMINATE(&Peb->CSDVersion);
  2951. fNewCSDVersionBuffer = TRUE;
  2952. }
  2953. break;
  2954. }
  2955. RtlFreeHeap (ProcessHeap, 0, AppCompatGoo);
  2956. }
  2957. }
  2958. //
  2959. // Only look at the ENV stuff if haven't already gotten new
  2960. // version info from the registry
  2961. //
  2962. if (fNewCSDVersionBuffer == FALSE) {
  2963. const static UNICODE_STRING COMPAT_VER_NN_String = RTL_CONSTANT_STRING(L"_COMPAT_VER_NNN");
  2964. //
  2965. // The format of this string is:
  2966. // _COMPAT_VER_NNN = MajOSVer, MinOSVer, OSBldNum, MajCSD, MinCSD, PlatformID, CSDString
  2967. // eg: _COMPAT_VER_NNN=4,0,1381,3,0,2,Service Pack 3
  2968. // (for NT 4 SP3)
  2969. EnvValue.Buffer = TempString;
  2970. EnvValue.Length = 0;
  2971. EnvValue.MaximumLength = sizeof(TempString);
  2972. st = RtlQueryEnvironmentVariable_U (NULL, &COMPAT_VER_NN_String, &EnvValue);
  2973. //
  2974. // One of the possible error codes is BUFFER_TOO_SMALL - this
  2975. // indicates a string that's wacko - they should not be larger
  2976. // than the size we define/expect. In this case, we'll ignore
  2977. // that string.
  2978. //
  2979. if (st == STATUS_SUCCESS) {
  2980. PWCHAR p = EnvValue.Buffer;
  2981. ULONG len = EnvValue.Length / sizeof(WCHAR); // (Length is bytes, not chars)
  2982. //
  2983. // Ok, someone wants different version info.
  2984. //
  2985. Peb->OSMajorVersion = GetNextCommaValue( &p, &len );
  2986. Peb->OSMinorVersion = GetNextCommaValue( &p, &len );
  2987. Peb->OSBuildNumber = (USHORT)GetNextCommaValue( &p, &len );
  2988. Peb->OSCSDVersion = (USHORT)(GetNextCommaValue( &p, &len )) << 8;
  2989. Peb->OSCSDVersion |= (USHORT)GetNextCommaValue( &p, &len );
  2990. Peb->OSPlatformId = GetNextCommaValue( &p, &len );
  2991. //
  2992. // Need to free the old buffer if there is one...
  2993. //
  2994. if (fNewCSDVersionBuffer) {
  2995. RtlFreeHeap( ProcessHeap, 0, Peb->CSDVersion.Buffer );
  2996. Peb->CSDVersion.Buffer = NULL;
  2997. }
  2998. if (len) {
  2999. NewCSDString = (PWSTR)RtlAllocateHeap (ProcessHeap,
  3000. 0,
  3001. (len + 1) * sizeof(WCHAR));
  3002. if (NULL == NewCSDString) {
  3003. return;
  3004. }
  3005. //
  3006. // Now copy the string to memory that we'll keep.
  3007. //
  3008. //
  3009. // NOTICE-1999/07/07-berniem
  3010. // We do a copy here rather than a string copy
  3011. // because current comments in RtlQueryEnvironmentVariable()
  3012. // indicate that in an edge case, we might not
  3013. // have a trailing NULL
  3014. //
  3015. RtlCopyMemory (NewCSDString, p, len * sizeof(WCHAR));
  3016. NewCSDString[len] = 0;
  3017. }
  3018. else {
  3019. NewCSDString = NULL;
  3020. }
  3021. RtlInitUnicodeString (&Peb->CSDVersion, NewCSDString);
  3022. }
  3023. }
  3024. return;
  3025. }
  3026. NTSTATUS
  3027. LdrFindAppCompatVariableInfo (
  3028. IN ULONG dwTypeSeeking,
  3029. OUT PAPP_VARIABLE_INFO *AppVariableInfo
  3030. )
  3031. /*++
  3032. Routine Description:
  3033. This function is used to find a variable length struct by its type.
  3034. The caller specifies what type its looking for and this function chews
  3035. thru all the variable length structs to find it. If it does it returns
  3036. the pointer and TRUE, else FALSE.
  3037. Arguments:
  3038. dwTypeSeeking - AVT that you are looking for
  3039. AppVariableInfo - pointer to pointer of variable info to be returned
  3040. Return Value:
  3041. NTSTATUS.
  3042. --*/
  3043. {
  3044. PPEB Peb;
  3045. ULONG TotalSize;
  3046. ULONG CurOffset;
  3047. PAPP_VARIABLE_INFO pCurrentEntry;
  3048. Peb = NtCurrentPeb();
  3049. if (Peb->AppCompatInfo) {
  3050. //
  3051. // Since we're not dealing with a fixed-size structure, TotalSize
  3052. // will keep us from running off the end of the data list.
  3053. //
  3054. TotalSize = ((PAPP_COMPAT_INFO) Peb->AppCompatInfo)->dwTotalSize;
  3055. //
  3056. // The first variable structure (if there is one) will start
  3057. // immediately after the fixed stuff
  3058. //
  3059. CurOffset = sizeof(APP_COMPAT_INFO);
  3060. while (CurOffset < TotalSize) {
  3061. pCurrentEntry = (PAPP_VARIABLE_INFO) ((PUCHAR)(Peb->AppCompatInfo) + CurOffset);
  3062. //
  3063. // Have we found what we're looking for?
  3064. //
  3065. if (dwTypeSeeking == pCurrentEntry->dwVariableType) {
  3066. *AppVariableInfo = pCurrentEntry;
  3067. return STATUS_SUCCESS;
  3068. }
  3069. //
  3070. // Let's go look at the next blob
  3071. //
  3072. CurOffset += (ULONG)(pCurrentEntry->dwVariableInfoSize);
  3073. }
  3074. }
  3075. return STATUS_NOT_FOUND;
  3076. }
  3077. NTSTATUS
  3078. LdrpCorValidateImage (
  3079. IN OUT PVOID *pImageBase,
  3080. IN LPWSTR ImageName
  3081. )
  3082. {
  3083. NTSTATUS st;
  3084. UNICODE_STRING SystemRoot;
  3085. UNICODE_STRING MscoreePath;
  3086. WCHAR PathBuffer [ 128 ];
  3087. //
  3088. // Load %windir%\system32\mscoree.dll and hold onto it until all COM+ images are unloaded.
  3089. //
  3090. MscoreePath.Buffer = PathBuffer;
  3091. MscoreePath.Length = 0;
  3092. MscoreePath.MaximumLength = sizeof (PathBuffer);
  3093. RtlInitUnicodeString (&SystemRoot, USER_SHARED_DATA->NtSystemRoot);
  3094. st = RtlAppendUnicodeStringToString (&MscoreePath, &SystemRoot);
  3095. if (NT_SUCCESS (st)) {
  3096. st = RtlAppendUnicodeStringToString (&MscoreePath, &SlashSystem32SlashMscoreeDllString);
  3097. if (NT_SUCCESS (st)) {
  3098. st = LdrLoadDll (NULL, NULL, &MscoreePath, &Cor20DllHandle);
  3099. }
  3100. }
  3101. if (!NT_SUCCESS (st)) {
  3102. if (ShowSnaps) {
  3103. DbgPrint("LDR: failed to load mscoree.dll, status=%x\n", st);
  3104. }
  3105. return st;
  3106. }
  3107. if (CorImageCount == 0) {
  3108. SIZE_T i;
  3109. const static LDRP_PROCEDURE_NAME_ADDRESS_PAIR CorProcedures[] = {
  3110. { RTL_CONSTANT_STRING("_CorValidateImage"), (PVOID *)&CorValidateImage },
  3111. { RTL_CONSTANT_STRING("_CorImageUnloading"), (PVOID *)&CorImageUnloading },
  3112. { RTL_CONSTANT_STRING("_CorExeMain"), (PVOID *)&CorExeMain }
  3113. };
  3114. for ( i = 0 ; i != RTL_NUMBER_OF(CorProcedures) ; ++i ) {
  3115. st = LdrGetProcedureAddress (Cor20DllHandle,
  3116. &CorProcedures[i].Name,
  3117. 0,
  3118. CorProcedures[i].Address
  3119. );
  3120. if (!NT_SUCCESS (st)) {
  3121. LdrUnloadDll (Cor20DllHandle);
  3122. return st;
  3123. }
  3124. }
  3125. }
  3126. //
  3127. // Call mscoree to validate the image.
  3128. //
  3129. st = (*CorValidateImage) (pImageBase, ImageName);
  3130. if (NT_SUCCESS(st)) {
  3131. //
  3132. // Success - bump the count of valid COM+ images.
  3133. //
  3134. CorImageCount += 1;
  3135. } else if (CorImageCount == 0) {
  3136. //
  3137. // Failure, and no other COM+ images are loaded, so unload mscoree.
  3138. //
  3139. LdrUnloadDll (Cor20DllHandle);
  3140. }
  3141. return st;
  3142. }
  3143. VOID
  3144. LdrpCorUnloadImage (
  3145. IN PVOID ImageBase
  3146. )
  3147. {
  3148. //
  3149. // Notify mscoree that the image is about be unmapped.
  3150. //
  3151. (*CorImageUnloading) (ImageBase);
  3152. if (--CorImageCount) {
  3153. //
  3154. // The count of loaded COM+ images is zero, so unload mscoree.
  3155. //
  3156. LdrUnloadDll (Cor20DllHandle);
  3157. }
  3158. }
  3159. VOID
  3160. LdrpInitializeApplicationVerifierPackage (
  3161. PCUNICODE_STRING UnicodeImageName,
  3162. PPEB Peb,
  3163. BOOLEAN EnabledSystemWide,
  3164. BOOLEAN OptionsKeyPresent
  3165. )
  3166. {
  3167. ULONG SavedPageHeapFlags;
  3168. NTSTATUS Status;
  3169. extern ULONG AVrfpVerifierFlags;
  3170. //
  3171. // If we are in safe boot mode we ignore all verification
  3172. // options.
  3173. //
  3174. if (USER_SHARED_DATA->SafeBootMode) {
  3175. Peb->NtGlobalFlag &= ~FLG_APPLICATION_VERIFIER;
  3176. Peb->NtGlobalFlag &= ~FLG_HEAP_PAGE_ALLOCS;
  3177. return;
  3178. }
  3179. //
  3180. // Call into the verifier proper.
  3181. //
  3182. //
  3183. // FUTURE-2002/04/02-SilviuC
  3184. // in time (soon) all should migrate in there.
  3185. //
  3186. if ((Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)) {
  3187. //
  3188. // If application verifier is enabled force creation of stack trace
  3189. // database. It is something really nice to have around for debugging
  3190. // critical sections issues or heap issues.
  3191. //
  3192. LdrpShouldCreateStackTraceDb = TRUE;
  3193. AVrfInitializeVerifier (EnabledSystemWide,
  3194. UnicodeImageName,
  3195. 0);
  3196. }
  3197. //
  3198. // Note that if application verifier is on, this automatically enables
  3199. // page heap.
  3200. //
  3201. if ((Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)) {
  3202. //
  3203. // We will enable page heap (RtlpDebugPageHeap) only after
  3204. // all other initializations for page heap are finished.
  3205. //
  3206. // No matter if the user mode stack trace database flag is set
  3207. // or not we will create the database. Page heap is so often
  3208. // used with +ust flag (traces) that it makes sense to tie
  3209. // them together.
  3210. //
  3211. LdrpShouldCreateStackTraceDb = TRUE;
  3212. //
  3213. // If page heap is enabled we need to disable any flag that
  3214. // might force creation of debug heaps for normal NT heaps.
  3215. // This is due to a dependency between page heap and NT heap
  3216. // where the page heap within PageHeapCreate tries to create
  3217. // a normal NT heap to accomodate some of the allocations.
  3218. // If we do not disable these flags we will get an infinite
  3219. // recursion between RtlpDebugPageHeapCreate and RtlCreateHeap.
  3220. //
  3221. Peb->NtGlobalFlag &=
  3222. ~( FLG_HEAP_ENABLE_TAGGING |
  3223. FLG_HEAP_ENABLE_TAG_BY_DLL |
  3224. FLG_HEAP_ENABLE_TAIL_CHECK |
  3225. FLG_HEAP_ENABLE_FREE_CHECK |
  3226. FLG_HEAP_VALIDATE_PARAMETERS |
  3227. FLG_HEAP_VALIDATE_ALL |
  3228. FLG_USER_STACK_TRACE_DB );
  3229. //
  3230. // Read page heap per process global flags. If we fail
  3231. // to read a value, the default ones are kept.
  3232. //
  3233. SavedPageHeapFlags = RtlpDphGlobalFlags;
  3234. RtlpDphGlobalFlags = 0xFFFFFFFF;
  3235. if (OptionsKeyPresent) {
  3236. Status = LdrQueryImageFileExecutionOptions(
  3237. UnicodeImageName,
  3238. L"PageHeapFlags",
  3239. REG_DWORD,
  3240. &RtlpDphGlobalFlags,
  3241. sizeof(RtlpDphGlobalFlags),
  3242. NULL);
  3243. if (!NT_SUCCESS(Status)) {
  3244. RtlpDphGlobalFlags = 0xFFFFFFFF;
  3245. }
  3246. }
  3247. //
  3248. // If app_verifier flag is on and there are no special settings for
  3249. // page heap then we will use full page heap with stack trace collection.
  3250. //
  3251. if ((Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)) {
  3252. if (RtlpDphGlobalFlags == 0xFFFFFFFF) {
  3253. //
  3254. // We did not pick up new settings from registry.
  3255. //
  3256. RtlpDphGlobalFlags = SavedPageHeapFlags;
  3257. }
  3258. }
  3259. else {
  3260. //
  3261. // Restore page heap options if we did not pick up new
  3262. // settings from registry.
  3263. //
  3264. if (RtlpDphGlobalFlags == 0xFFFFFFFF) {
  3265. RtlpDphGlobalFlags = SavedPageHeapFlags;
  3266. }
  3267. }
  3268. //
  3269. // If page heap is enabled and we have an image options key
  3270. // read more page heap parameters.
  3271. //
  3272. if (OptionsKeyPresent) {
  3273. LdrQueryImageFileExecutionOptions(
  3274. UnicodeImageName,
  3275. L"PageHeapSizeRangeStart",
  3276. REG_DWORD,
  3277. &RtlpDphSizeRangeStart,
  3278. sizeof(RtlpDphSizeRangeStart),
  3279. NULL
  3280. );
  3281. LdrQueryImageFileExecutionOptions(
  3282. UnicodeImageName,
  3283. L"PageHeapSizeRangeEnd",
  3284. REG_DWORD,
  3285. &RtlpDphSizeRangeEnd,
  3286. sizeof(RtlpDphSizeRangeEnd),
  3287. NULL
  3288. );
  3289. LdrQueryImageFileExecutionOptions(
  3290. UnicodeImageName,
  3291. L"PageHeapRandomProbability",
  3292. REG_DWORD,
  3293. &RtlpDphRandomProbability,
  3294. sizeof(RtlpDphRandomProbability),
  3295. NULL
  3296. );
  3297. LdrQueryImageFileExecutionOptions(
  3298. UnicodeImageName,
  3299. L"PageHeapFaultProbability",
  3300. REG_DWORD,
  3301. &RtlpDphFaultProbability,
  3302. sizeof(RtlpDphFaultProbability),
  3303. NULL
  3304. );
  3305. LdrQueryImageFileExecutionOptions(
  3306. UnicodeImageName,
  3307. L"PageHeapFaultTimeOut",
  3308. REG_DWORD,
  3309. &RtlpDphFaultTimeOut,
  3310. sizeof(RtlpDphFaultTimeOut),
  3311. NULL
  3312. );
  3313. //
  3314. // The two values below should be read as PVOIDs so that
  3315. // this works on 64-bit architetures. However since this
  3316. // feature relies on good stack traces and since we can get
  3317. // reliable stack traces only on X86 architectures we will
  3318. // leave it as it is.
  3319. //
  3320. LdrQueryImageFileExecutionOptions(
  3321. UnicodeImageName,
  3322. L"PageHeapDllRangeStart",
  3323. REG_DWORD,
  3324. &RtlpDphDllRangeStart,
  3325. sizeof(RtlpDphDllRangeStart),
  3326. NULL
  3327. );
  3328. LdrQueryImageFileExecutionOptions(
  3329. UnicodeImageName,
  3330. L"PageHeapDllRangeEnd",
  3331. REG_DWORD,
  3332. &RtlpDphDllRangeEnd,
  3333. sizeof(RtlpDphDllRangeEnd),
  3334. NULL
  3335. );
  3336. LdrQueryImageFileExecutionOptions(
  3337. UnicodeImageName,
  3338. L"PageHeapTargetDlls",
  3339. REG_SZ,
  3340. &RtlpDphTargetDlls,
  3341. 512*sizeof(WCHAR),
  3342. NULL
  3343. );
  3344. }
  3345. //
  3346. // Per dll page heap option is not supported if fast fill heap is enabled.
  3347. //
  3348. if ((RtlpDphGlobalFlags & PAGE_HEAP_USE_DLL_NAMES) &&
  3349. (AVrfpVerifierFlags & RTL_VRF_FLG_FAST_FILL_HEAP)) {
  3350. DbgPrint ("AVRF: per dll page heap option disabled because fast fill heap is enabled. \n");
  3351. RtlpDphGlobalFlags &= ~PAGE_HEAP_USE_DLL_NAMES;
  3352. }
  3353. //
  3354. // Turn on BOOLEAN RtlpDebugPageHeap to indicate that
  3355. // new heaps should be created with debug page heap manager
  3356. // when possible.
  3357. //
  3358. RtlpDebugPageHeap = TRUE;
  3359. }
  3360. }
  3361. NTSTATUS
  3362. LdrpTouchThreadStack (
  3363. IN SIZE_T EnforcedStackCommit
  3364. )
  3365. /*++
  3366. Routine description:
  3367. This routine is called if precommitted stacks are enforced for the process.
  3368. It will determine how much stack needs to be touched (therefore committed)
  3369. and then it will touch it. For any kind of error (e.g. stack overflow for
  3370. out of memory conditions it will return STATUS_NO_MEMORY.
  3371. Parameters:
  3372. EnforcedStackCommit - Supplies the amount of committed stack that should
  3373. be enforced for the main thread. This value can be
  3374. decreased in reality if it goes over the virtual
  3375. region reserved for the stack. It is not worth
  3376. taking care of this special case because it will
  3377. require either switching the stack or support in
  3378. the target process for detecting the enforced
  3379. stack commit requirement. The image can always be
  3380. changed to have a bigger stack reserve.
  3381. Return value:
  3382. STATUS_SUCCESS if the stack was successfully touched and STATUS_NO_MEMORY
  3383. otherwise.
  3384. --*/
  3385. {
  3386. ULONG_PTR TouchAddress;
  3387. ULONG_PTR TouchLimit;
  3388. ULONG_PTR LowStackLimit;
  3389. ULONG_PTR HighStackLimit;
  3390. NTSTATUS Status;
  3391. MEMORY_BASIC_INFORMATION MemoryInformation;
  3392. SIZE_T ReturnLength;
  3393. PTEB Teb;
  3394. Teb = NtCurrentTeb();
  3395. Status = NtQueryVirtualMemory (NtCurrentProcess(),
  3396. Teb->NtTib.StackLimit,
  3397. MemoryBasicInformation,
  3398. &MemoryInformation,
  3399. sizeof MemoryInformation,
  3400. &ReturnLength);
  3401. if (! NT_SUCCESS(Status)) {
  3402. return Status;
  3403. }
  3404. LowStackLimit = (ULONG_PTR)(MemoryInformation.AllocationBase);
  3405. LowStackLimit += 3 * PAGE_SIZE;
  3406. HighStackLimit = (ULONG_PTR)(Teb->NtTib.StackBase);
  3407. TouchAddress = HighStackLimit - PAGE_SIZE;
  3408. if (TouchAddress > EnforcedStackCommit) {
  3409. if (TouchAddress - EnforcedStackCommit > LowStackLimit) {
  3410. TouchLimit = TouchAddress - EnforcedStackCommit;
  3411. }
  3412. else {
  3413. TouchLimit = LowStackLimit;
  3414. }
  3415. }
  3416. else {
  3417. TouchLimit = LowStackLimit;
  3418. }
  3419. try {
  3420. while (TouchAddress >= TouchLimit) {
  3421. *((volatile UCHAR * const) TouchAddress);
  3422. TouchAddress -= PAGE_SIZE;
  3423. }
  3424. }
  3425. except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  3426. //
  3427. // If we get a stack overflow we will report it as no memory.
  3428. //
  3429. return STATUS_NO_MEMORY;
  3430. }
  3431. return STATUS_SUCCESS;
  3432. }
  3433. BOOLEAN
  3434. LdrpInitializeExecutionOptions (
  3435. IN PCUNICODE_STRING UnicodeImageName,
  3436. IN PPEB Peb
  3437. )
  3438. /*++
  3439. Routine description:
  3440. This routine reads the `image file execution options' key for the
  3441. current process and interprets all the values under the key.
  3442. Parameters:
  3443. Return value:
  3444. True if there is a registry key for this process.
  3445. --*/
  3446. {
  3447. NTSTATUS st;
  3448. BOOLEAN ImageFileOptionsPresent;
  3449. HANDLE KeyHandle;
  3450. ImageFileOptionsPresent = FALSE;
  3451. //
  3452. // Open the "Image File Execution Options" key for this program.
  3453. //
  3454. st = LdrpOpenImageFileOptionsKey (UnicodeImageName, FALSE, &KeyHandle);
  3455. if (NT_SUCCESS(st)) {
  3456. //
  3457. // We have image file execution options for this process
  3458. //
  3459. ImageFileOptionsPresent = TRUE;
  3460. //
  3461. // Hack for NT4 SP4. So we don't overload another GlobalFlag
  3462. // bit that we have to be "compatible" with for NT5, look for
  3463. // another value named "DisableHeapLookaside".
  3464. //
  3465. LdrpQueryImageFileKeyOption (KeyHandle,
  3466. L"DisableHeapLookaside",
  3467. REG_DWORD,
  3468. &RtlpDisableHeapLookaside,
  3469. sizeof( RtlpDisableHeapLookaside ),
  3470. NULL);
  3471. //
  3472. // Verification options during process shutdown (heap leaks, etc.).
  3473. //
  3474. LdrpQueryImageFileKeyOption (KeyHandle,
  3475. L"ShutdownFlags",
  3476. REG_DWORD,
  3477. &RtlpShutdownProcessFlags,
  3478. sizeof( RtlpShutdownProcessFlags ),
  3479. NULL);
  3480. //
  3481. // Check if there is a minimal stack commit enforced
  3482. // for this image. This will affect all threads but the
  3483. // one executing this code (initial thread).
  3484. //
  3485. {
  3486. DWORD MinimumStackCommitInBytes = 0;
  3487. LdrpQueryImageFileKeyOption (KeyHandle,
  3488. L"MinimumStackCommitInBytes",
  3489. REG_DWORD,
  3490. &MinimumStackCommitInBytes,
  3491. sizeof( MinimumStackCommitInBytes ),
  3492. NULL);
  3493. if (Peb->MinimumStackCommit < (SIZE_T)MinimumStackCommitInBytes) {
  3494. Peb->MinimumStackCommit = (SIZE_T)MinimumStackCommitInBytes;
  3495. }
  3496. }
  3497. //
  3498. // Check if ExecuteOptions is specified for this image. If yes
  3499. // we will transfer the options into the PEB. Later we will
  3500. // make sure the stack region has exactly the protection
  3501. // requested.
  3502. // There is no need to initialize this field at this as Wow64
  3503. // already done that. We only update it if there is a value set in
  3504. // there.
  3505. //
  3506. {
  3507. ULONG ExecuteOptions = 0;
  3508. NTSTATUS NtStatus;
  3509. NtStatus = LdrpQueryImageFileKeyOption (KeyHandle,
  3510. L"ExecuteOptions",
  3511. REG_DWORD,
  3512. &(ExecuteOptions),
  3513. sizeof (ExecuteOptions),
  3514. NULL);
  3515. #if defined(BUILD_WOW6432)
  3516. if (NT_SUCCESS (NtStatus)) {
  3517. #endif
  3518. Peb->ExecuteOptions = ExecuteOptions & (MEM_EXECUTE_OPTION_STACK | MEM_EXECUTE_OPTION_DATA);
  3519. #if defined(BUILD_WOW6432)
  3520. }
  3521. #endif
  3522. }
  3523. //
  3524. // Pickup the global_flags value from registry
  3525. //
  3526. {
  3527. BOOLEAN EnabledSystemWide = FALSE;
  3528. ULONG ProcessFlags;
  3529. if ((Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)) {
  3530. EnabledSystemWide = TRUE;
  3531. }
  3532. st = LdrpQueryImageFileKeyOption (KeyHandle,
  3533. L"GlobalFlag",
  3534. REG_DWORD,
  3535. &ProcessFlags,
  3536. sizeof( Peb->NtGlobalFlag ),
  3537. NULL);
  3538. //
  3539. // If we read a global value whatever is in there will
  3540. // take precedence over the systemwide settings. Only if no
  3541. // value is read the systemwide setting will kick in.
  3542. //
  3543. if (NT_SUCCESS(st)) {
  3544. Peb->NtGlobalFlag = ProcessFlags;
  3545. }
  3546. //
  3547. // If pageheap or appverifier is enabled we need to initialize the
  3548. // verifier package.
  3549. //
  3550. if ((Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))) {
  3551. LdrpInitializeApplicationVerifierPackage (UnicodeImageName,
  3552. Peb,
  3553. EnabledSystemWide,
  3554. TRUE);
  3555. }
  3556. }
  3557. {
  3558. const static struct {
  3559. PCWSTR Name;
  3560. PBOOLEAN Variable;
  3561. } Options[] = {
  3562. { L"ShowRecursiveDllLoads", &LdrpShowRecursiveDllLoads },
  3563. { L"BreakOnRecursiveDllLoads", &LdrpBreakOnRecursiveDllLoads },
  3564. { L"ShowLoaderErrors", &ShowErrors },
  3565. { L"BreakOnInitializeProcessFailure", &g_LdrBreakOnLdrpInitializeProcessFailure },
  3566. { L"KeepActivationContextsAlive", &g_SxsKeepActivationContextsAlive },
  3567. { L"TrackActivationContextReleases", &g_SxsTrackReleaseStacks },
  3568. };
  3569. SIZE_T i;
  3570. ULONG Temp;
  3571. for (i = 0 ; i != RTL_NUMBER_OF(Options) ; ++i) {
  3572. Temp = 0;
  3573. LdrpQueryImageFileKeyOption (KeyHandle, Options[i].Name, REG_DWORD, &Temp, sizeof(Temp), NULL);
  3574. if (Temp != 0) {
  3575. *Options[i].Variable = TRUE;
  3576. }
  3577. else {
  3578. *Options[i].Variable = FALSE;
  3579. }
  3580. }
  3581. // This is an actual ULONG that we're reading, but we don't want to set it unless
  3582. // it's there - it starts out at the right magic value.
  3583. Temp = 0;
  3584. LdrpQueryImageFileKeyOption(
  3585. KeyHandle,
  3586. L"MaxDeadActivationContexts",
  3587. REG_DWORD,
  3588. &Temp,
  3589. sizeof(Temp),
  3590. NULL);
  3591. if (Temp != 0) {
  3592. g_SxsMaxDeadActivationContexts = Temp;
  3593. }
  3594. }
  3595. NtClose(KeyHandle);
  3596. }
  3597. else {
  3598. //
  3599. // We do not have image file execution options for this process.
  3600. //
  3601. // If pageheap or appverifier is enabled system-wide we will enable
  3602. // them with default settings and ignore the options used when
  3603. // running process under debugger. If these are not set and process
  3604. // runs under debugger we will enable a few extra things (e.g.
  3605. // debug heap).
  3606. //
  3607. if ((Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))) {
  3608. LdrpInitializeApplicationVerifierPackage (UnicodeImageName,
  3609. Peb,
  3610. TRUE,
  3611. FALSE);
  3612. }
  3613. else {
  3614. if (Peb->BeingDebugged) {
  3615. const static UNICODE_STRING DebugVarName = RTL_CONSTANT_STRING(L"_NO_DEBUG_HEAP");
  3616. UNICODE_STRING DebugVarValue;
  3617. WCHAR TempString[ 16 ];
  3618. LOGICAL UseDebugHeap = TRUE;
  3619. DebugVarValue.Buffer = TempString;
  3620. DebugVarValue.Length = 0;
  3621. DebugVarValue.MaximumLength = sizeof(TempString);
  3622. //
  3623. // The PebLockRoutine is not initialized at this point
  3624. // We need to pass the explicit environment block.
  3625. //
  3626. st = RtlQueryEnvironmentVariable_U (Peb->ProcessParameters->Environment,
  3627. &DebugVarName,
  3628. &DebugVarValue);
  3629. if (NT_SUCCESS(st)) {
  3630. ULONG ULongValue;
  3631. st = RtlUnicodeStringToInteger (&DebugVarValue, 0, &ULongValue);
  3632. if (NT_SUCCESS(st) && ULongValue) {
  3633. UseDebugHeap = FALSE;
  3634. }
  3635. }
  3636. if (UseDebugHeap) {
  3637. Peb->NtGlobalFlag |= FLG_HEAP_ENABLE_FREE_CHECK |
  3638. FLG_HEAP_ENABLE_TAIL_CHECK |
  3639. FLG_HEAP_VALIDATE_PARAMETERS;
  3640. }
  3641. }
  3642. }
  3643. }
  3644. return ImageFileOptionsPresent;
  3645. }
  3646. NTSTATUS
  3647. LdrpEnforceExecuteForCurrentThreadStack (
  3648. VOID
  3649. )
  3650. /*++
  3651. Routine description:
  3652. This routine is called if execute rights must be granted for the
  3653. current thread's stack. It will determine the committed area of the
  3654. stack and add execute flag. It will also examine the rights for the
  3655. guard page on top of the stack. The reserved portion of the stack does
  3656. not need to be changed because once MEM_EXECUTE_OPTION_STACK is enabled
  3657. in the PEB the memory manager will take care of OR-ing the execute flag
  3658. for every new commit.
  3659. The function is also called if we have DATA execution but we do not want
  3660. STACK execution. In this case by default (due to DATA) any committed
  3661. area gets execute right and we want to revert this for stack areas.
  3662. Note. Even if the process has data execution set the stack might not have
  3663. the correct settings because the stack sometimes is allocated in a different
  3664. process (this is the case for the first thread of a process and for remote
  3665. threads).
  3666. Parameters:
  3667. None.
  3668. Return value:
  3669. STATUS_SUCCESS if we successfully changed execute rights.
  3670. --*/
  3671. {
  3672. MEMORY_BASIC_INFORMATION MemoryInformation;
  3673. NTSTATUS Status;
  3674. SIZE_T Length;
  3675. ULONG_PTR Address;
  3676. SIZE_T Size;
  3677. ULONG StackProtect;
  3678. ULONG OldProtect;
  3679. ULONG ExecuteOptions;
  3680. PTEB Teb;
  3681. Teb = NtCurrentTeb();
  3682. ExecuteOptions = Teb->ProcessEnvironmentBlock->ExecuteOptions;
  3683. ExecuteOptions &= (MEM_EXECUTE_OPTION_STACK | MEM_EXECUTE_OPTION_DATA);
  3684. ASSERT (ExecuteOptions != 0);
  3685. if (ExecuteOptions & MEM_EXECUTE_OPTION_STACK) {
  3686. //
  3687. // Data = X and Stack = 1: we need to set EXECUTE bit on the stack
  3688. // Even if Data = 1 we cannot be sure the stack has the right
  3689. // protection because it could have been allocated in a different
  3690. // process.
  3691. //
  3692. StackProtect = PAGE_EXECUTE_READWRITE;
  3693. }
  3694. else {
  3695. //
  3696. // Data = 1 and Stack = 0: we need to reset EXECUTE bit on the stack.
  3697. // Again it might be that Data is one but the stack does not have
  3698. // execution rights if this was a cross-process allocation.
  3699. //
  3700. StackProtect = PAGE_READWRITE;
  3701. ASSERT ((ExecuteOptions & MEM_EXECUTE_OPTION_DATA) != 0);
  3702. }
  3703. //
  3704. // Set the protection for the committed portion of the stack. Note
  3705. // that we cannot query the region and conclude there is nothing to do
  3706. // if execute bit is set for the bottom page of the stack (the one near
  3707. // the guard page) because the stack at this stage can have two regions:
  3708. // an upper one created by a parent process (this will not have execute bit
  3709. // set) and a lower portion that was created due to stack extensions (this
  3710. // one will have execute bit set). Therefore we will move directly to setting
  3711. // the new desired protection.
  3712. //
  3713. Address = (ULONG_PTR)(Teb->NtTib.StackLimit);
  3714. Size = (ULONG_PTR)(Teb->NtTib.StackBase) - (ULONG_PTR)(Teb->NtTib.StackLimit);
  3715. Status = NtProtectVirtualMemory (NtCurrentProcess(),
  3716. (PVOID)&Address,
  3717. &Size,
  3718. StackProtect,
  3719. &OldProtect);
  3720. if (! NT_SUCCESS(Status)) {
  3721. return Status;
  3722. }
  3723. //
  3724. // Check protection for the guard page of the stack. If the
  3725. // protection is correct we will avoid a more expensive protect() call.
  3726. //
  3727. Address = Address - PAGE_SIZE;
  3728. Status = NtQueryVirtualMemory (NtCurrentProcess(),
  3729. (PVOID)Address,
  3730. MemoryBasicInformation,
  3731. &MemoryInformation,
  3732. sizeof MemoryInformation,
  3733. &Length);
  3734. if (! NT_SUCCESS(Status)) {
  3735. return Status;
  3736. }
  3737. ASSERT (MemoryInformation.AllocationBase == Teb->DeallocationStack);
  3738. ASSERT (MemoryInformation.BaseAddress == (PVOID)Address);
  3739. ASSERT ((MemoryInformation.Protect & PAGE_GUARD) != 0);
  3740. if (MemoryInformation.Protect != (StackProtect | PAGE_GUARD)) {
  3741. //
  3742. // Set the proper protection flags for the guard page of the stack.
  3743. //
  3744. Size = PAGE_SIZE;
  3745. ASSERT (MemoryInformation.RegionSize == Size);
  3746. Status = NtProtectVirtualMemory (NtCurrentProcess(),
  3747. (PVOID)&Address,
  3748. &Size,
  3749. StackProtect | PAGE_GUARD,
  3750. &OldProtect);
  3751. if (! NT_SUCCESS(Status)) {
  3752. return Status;
  3753. }
  3754. ASSERT (OldProtect == MemoryInformation.Protect);
  3755. }
  3756. return STATUS_SUCCESS;
  3757. }
  3758. #include <ntverp.h>
  3759. const ULONG NtMajorVersion = VER_PRODUCTMAJORVERSION;
  3760. const ULONG NtMinorVersion = VER_PRODUCTMINORVERSION;
  3761. #if DBG
  3762. ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xC0000000; // C for "checked"
  3763. #else
  3764. ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xF0000000; // F for "free"
  3765. #endif
  3766. VOID
  3767. RtlGetNtVersionNumbers(
  3768. PULONG pNtMajorVersion,
  3769. PULONG pNtMinorVersion,
  3770. PULONG pNtBuildNumber
  3771. )
  3772. /*++
  3773. Routine description:
  3774. This routine will return the real OS build number, major and minor version
  3775. as compiled. It's used by code that needs to get a real version number
  3776. that can't be easily spoofed.
  3777. Parameters:
  3778. pNtMajorVersion - Pointer to ULONG that will hold major version.
  3779. pNtMinorVersion - Pointer to ULONG that will hold minor version.
  3780. pNtBuildNumber - Pointer to ULONG that will hold the build number (with 'C' or 'F' in high nibble to indicate free/checked)
  3781. Return value:
  3782. None
  3783. --*/
  3784. {
  3785. if (pNtMajorVersion) {
  3786. *pNtMajorVersion = NtMajorVersion;
  3787. }
  3788. if (pNtMinorVersion) {
  3789. *pNtMinorVersion = NtMinorVersion;
  3790. }
  3791. if (pNtBuildNumber) {
  3792. *pNtBuildNumber = NtBuildNumber;
  3793. }
  3794. }