Source code of Windows XP (NT5)
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.

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