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

2755 lines
78 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. support.c
  5. Abstract:
  6. This module implements various conversion routines
  7. that transform Win32 parameters into NT parameters.
  8. Author:
  9. Mark Lucovsky (markl) 20-Sep-1990
  10. Revision History:
  11. --*/
  12. #include "basedll.h"
  13. #if defined(BUILD_WOW6432)
  14. #include "wow64reg.h"
  15. #include <wow64t.h>
  16. #endif
  17. PCLDR_DATA_TABLE_ENTRY BasepExeLdrEntry = NULL;
  18. // N.B. These are the registry values we check for SafeDllSearchMode,
  19. // and MUST match the entries in BasepDllSearchPaths
  20. typedef enum {
  21. BasepCurrentDirUninitialized = -1,
  22. BasepCurrentDirAtStart = 0,
  23. BasepCurrentDirAfterSystem32 = 1,
  24. MaxBasepCurrentDir
  25. } BASEP_CURDIR_PLACEMENT;
  26. #define BASEP_DEFAULT_DLL_CURDIR_PLACEMENT (BasepCurrentDirAfterSystem32)
  27. #define BASEP_VALID_CURDIR_PLACEMENT_P(c) (BasepCurrentDirUninitialized < (c) \
  28. && (c) < MaxBasepCurrentDir)
  29. LONG BasepDllCurrentDirPlacement = BasepCurrentDirUninitialized;
  30. typedef enum {
  31. BasepSearchPathEnd, // end of path
  32. BasepSearchPathDlldir, // use the dll dir; fallback to nothing
  33. BasepSearchPathAppdir, // use the exe dir; fallback to base exe dir
  34. BasepSearchPathDefaultDirs, // use the default system dirs
  35. BasepSearchPathEnvPath, // use %PATH%
  36. BasepSearchPathCurdir, // use "."
  37. MaxBasepSearchPath
  38. } BASEP_SEARCH_PATH_ELEMENT;
  39. // N.B. The ordering of these must match the definitions for
  40. // BASEP_CURDIR_PLACEMENT.
  41. static const BASEP_SEARCH_PATH_ELEMENT BasepDllSearchPaths[MaxBasepCurrentDir][7] =
  42. {
  43. {
  44. // BasepCurrentDirAtStart
  45. BasepSearchPathAppdir,
  46. BasepSearchPathCurdir,
  47. BasepSearchPathDefaultDirs,
  48. BasepSearchPathEnvPath,
  49. BasepSearchPathEnd
  50. },
  51. {
  52. // BasepCurrentDirAfterSystem32
  53. BasepSearchPathAppdir,
  54. BasepSearchPathDefaultDirs,
  55. BasepSearchPathCurdir,
  56. BasepSearchPathEnvPath,
  57. BasepSearchPathEnd
  58. }
  59. };
  60. POBJECT_ATTRIBUTES
  61. BaseFormatObjectAttributes(
  62. OUT POBJECT_ATTRIBUTES ObjectAttributes,
  63. IN PSECURITY_ATTRIBUTES SecurityAttributes,
  64. IN PUNICODE_STRING ObjectName
  65. )
  66. /*++
  67. Routine Description:
  68. This function transforms a Win32 security attributes structure into
  69. an NT object attributes structure. It returns the address of the
  70. resulting structure (or NULL if SecurityAttributes was not
  71. specified).
  72. Arguments:
  73. ObjectAttributes - Returns an initialized NT object attributes
  74. structure that contains a superset of the information provided
  75. by the security attributes structure.
  76. SecurityAttributes - Supplies the address of a security attributes
  77. structure that needs to be transformed into an NT object
  78. attributes structure.
  79. ObjectName - Supplies a name for the object relative to the
  80. BaseNamedObjectDirectory object directory.
  81. Return Value:
  82. NULL - A value of null should be used to mimic the behavior of the
  83. specified SecurityAttributes structure.
  84. NON-NULL - Returns the ObjectAttributes value. The structure is
  85. properly initialized by this function.
  86. --*/
  87. {
  88. HANDLE RootDirectory;
  89. ULONG Attributes;
  90. PVOID SecurityDescriptor;
  91. if ( ARGUMENT_PRESENT(SecurityAttributes) ||
  92. ARGUMENT_PRESENT(ObjectName) ) {
  93. if ( SecurityAttributes ) {
  94. Attributes = (SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0);
  95. SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
  96. }
  97. else {
  98. Attributes = 0;
  99. SecurityDescriptor = NULL;
  100. }
  101. if ( ARGUMENT_PRESENT(ObjectName) ) {
  102. Attributes |= OBJ_OPENIF;
  103. RootDirectory = BaseGetNamedObjectDirectory();
  104. }
  105. else {
  106. RootDirectory = NULL;
  107. }
  108. InitializeObjectAttributes(
  109. ObjectAttributes,
  110. ObjectName,
  111. Attributes,
  112. RootDirectory,
  113. SecurityDescriptor
  114. );
  115. return ObjectAttributes;
  116. }
  117. else {
  118. return NULL;
  119. }
  120. }
  121. PLARGE_INTEGER
  122. BaseFormatTimeOut(
  123. OUT PLARGE_INTEGER TimeOut,
  124. IN DWORD Milliseconds
  125. )
  126. /*++
  127. Routine Description:
  128. This function translates a Win32 style timeout to an NT relative
  129. timeout value.
  130. Arguments:
  131. TimeOut - Returns an initialized NT timeout value that is equivalent
  132. to the Milliseconds parameter.
  133. Milliseconds - Supplies the timeout value in milliseconds. A value
  134. of -1 indicates indefinite timeout.
  135. Return Value:
  136. NULL - A value of null should be used to mimic the behavior of the
  137. specified Milliseconds parameter.
  138. NON-NULL - Returns the TimeOut value. The structure is properly
  139. initialized by this function.
  140. --*/
  141. {
  142. if ( (LONG) Milliseconds == -1 ) {
  143. return( NULL );
  144. }
  145. TimeOut->QuadPart = UInt32x32To64( Milliseconds, 10000 );
  146. TimeOut->QuadPart *= -1;
  147. return TimeOut;
  148. }
  149. NTSTATUS
  150. BaseCreateStack(
  151. IN HANDLE Process,
  152. IN SIZE_T StackSize,
  153. IN SIZE_T MaximumStackSize,
  154. OUT PINITIAL_TEB InitialTeb
  155. )
  156. /*++
  157. Routine Description:
  158. This function creates a stack for the specified process.
  159. Arguments:
  160. Process - Supplies a handle to the process that the stack will
  161. be allocated within.
  162. StackSize - An optional parameter, that if specified, supplies
  163. the initial commit size for the stack.
  164. MaximumStackSize - Supplies the maximum size for the new threads stack.
  165. If this parameter is not specified, then the reserve size of the
  166. current images stack descriptor is used.
  167. InitialTeb - Returns a populated InitialTeb that contains
  168. the stack size and limits.
  169. Return Value:
  170. TRUE - A stack was successfully created.
  171. FALSE - The stack counld not be created.
  172. --*/
  173. {
  174. NTSTATUS Status;
  175. PCH Stack;
  176. BOOLEAN GuardPage;
  177. SIZE_T RegionSize;
  178. ULONG OldProtect;
  179. SIZE_T ImageStackSize, ImageStackCommit;
  180. PIMAGE_NT_HEADERS NtHeaders;
  181. PPEB Peb;
  182. ULONG PageSize;
  183. Peb = NtCurrentPeb();
  184. BaseStaticServerData = BASE_SHARED_SERVER_DATA;
  185. PageSize = BASE_SYSINFO.PageSize;
  186. //
  187. // If the stack size was not supplied, then use the sizes from the
  188. // image header.
  189. //
  190. NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
  191. if (!NtHeaders) {
  192. return STATUS_INVALID_IMAGE_FORMAT;
  193. }
  194. ImageStackSize = NtHeaders->OptionalHeader.SizeOfStackReserve;
  195. ImageStackCommit = NtHeaders->OptionalHeader.SizeOfStackCommit;
  196. if ( !MaximumStackSize ) {
  197. MaximumStackSize = ImageStackSize;
  198. }
  199. if (!StackSize) {
  200. StackSize = ImageStackCommit;
  201. }
  202. else {
  203. //
  204. // Now Compute how much additional stack space is to be
  205. // reserved. This is done by... If the StackSize is <=
  206. // Reserved size in the image, then reserve whatever the image
  207. // specifies. Otherwise, round up to 1Mb.
  208. //
  209. if ( StackSize >= MaximumStackSize ) {
  210. MaximumStackSize = ROUND_UP(StackSize, (1024*1024));
  211. }
  212. }
  213. //
  214. // Align the stack size to a page boundry and the reserved size
  215. // to an allocation granularity boundry.
  216. //
  217. StackSize = ROUND_UP( StackSize, PageSize );
  218. MaximumStackSize = ROUND_UP(
  219. MaximumStackSize,
  220. BASE_SYSINFO.AllocationGranularity
  221. );
  222. //
  223. // Enforce a minimal stack commit if there is a PEB setting
  224. // for this.
  225. //
  226. {
  227. SIZE_T MinimumStackCommit;
  228. MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit;
  229. if (MinimumStackCommit != 0 && StackSize < MinimumStackCommit) {
  230. StackSize = MinimumStackCommit;
  231. }
  232. //
  233. // Recheck and realign reserve size
  234. //
  235. if ( StackSize >= MaximumStackSize ) {
  236. MaximumStackSize = ROUND_UP (StackSize, (1024*1024));
  237. }
  238. StackSize = ROUND_UP (StackSize, PageSize);
  239. MaximumStackSize = ROUND_UP (MaximumStackSize, BASE_SYSINFO.AllocationGranularity);
  240. }
  241. #if !defined (_IA64_)
  242. //
  243. // Reserve address space for the stack
  244. //
  245. Stack = NULL;
  246. Status = NtAllocateVirtualMemory(
  247. Process,
  248. (PVOID *)&Stack,
  249. 0,
  250. &MaximumStackSize,
  251. MEM_RESERVE,
  252. PAGE_READWRITE
  253. );
  254. #else
  255. //
  256. // Take RseStack into consideration.
  257. // RSE stack has same size as memory stack, has same StackBase,
  258. // has a guard page at the end, and grows upwards towards higher
  259. // memory addresses
  260. //
  261. //
  262. // Reserve address space for the two stacks
  263. //
  264. {
  265. SIZE_T TotalStackSize = MaximumStackSize * 2;
  266. Stack = NULL;
  267. Status = NtAllocateVirtualMemory(
  268. Process,
  269. (PVOID *)&Stack,
  270. 0,
  271. &TotalStackSize,
  272. MEM_RESERVE,
  273. PAGE_READWRITE
  274. );
  275. }
  276. #endif // IA64
  277. if ( !NT_SUCCESS( Status ) ) {
  278. return Status;
  279. }
  280. InitialTeb->OldInitialTeb.OldStackBase = NULL;
  281. InitialTeb->OldInitialTeb.OldStackLimit = NULL;
  282. InitialTeb->StackAllocationBase = Stack;
  283. InitialTeb->StackBase = Stack + MaximumStackSize;
  284. #if defined (_IA64_)
  285. InitialTeb->OldInitialTeb.OldBStoreLimit = NULL;
  286. #endif //IA64
  287. Stack += MaximumStackSize - StackSize;
  288. if (MaximumStackSize > StackSize) {
  289. Stack -= PageSize;
  290. StackSize += PageSize;
  291. GuardPage = TRUE;
  292. }
  293. else {
  294. GuardPage = FALSE;
  295. }
  296. //
  297. // Commit the initially valid portion of the stack
  298. //
  299. #if !defined(_IA64_)
  300. Status = NtAllocateVirtualMemory(
  301. Process,
  302. (PVOID *)&Stack,
  303. 0,
  304. &StackSize,
  305. MEM_COMMIT,
  306. PAGE_READWRITE
  307. );
  308. #else
  309. {
  310. //
  311. // memory and rse stacks are expected to be contiguous
  312. // reserver virtual memory for both stack at once
  313. //
  314. SIZE_T NewCommittedStackSize = StackSize * 2;
  315. Status = NtAllocateVirtualMemory(
  316. Process,
  317. (PVOID *)&Stack,
  318. 0,
  319. &NewCommittedStackSize,
  320. MEM_COMMIT,
  321. PAGE_READWRITE
  322. );
  323. }
  324. #endif //IA64
  325. if ( !NT_SUCCESS( Status ) ) {
  326. //
  327. // If the commit fails, then delete the address space for the stack
  328. //
  329. RegionSize = 0;
  330. NtFreeVirtualMemory(
  331. Process,
  332. (PVOID *)&Stack,
  333. &RegionSize,
  334. MEM_RELEASE
  335. );
  336. return Status;
  337. }
  338. InitialTeb->StackLimit = Stack;
  339. #if defined(_IA64_)
  340. InitialTeb->BStoreLimit = Stack + 2 * StackSize;
  341. #endif
  342. //
  343. // if we have space, create a guard page.
  344. //
  345. if (GuardPage) {
  346. RegionSize = PageSize;
  347. Status = NtProtectVirtualMemory(
  348. Process,
  349. (PVOID *)&Stack,
  350. &RegionSize,
  351. PAGE_GUARD | PAGE_READWRITE,
  352. &OldProtect
  353. );
  354. if ( !NT_SUCCESS( Status ) ) {
  355. return Status;
  356. }
  357. InitialTeb->StackLimit = (PVOID)((PUCHAR)InitialTeb->StackLimit + RegionSize);
  358. #if defined(_IA64_)
  359. //
  360. // additional code to Create RSE stack guard page
  361. //
  362. Stack = ((PCH)InitialTeb->StackBase) + StackSize - PageSize;
  363. RegionSize = PageSize;
  364. Status = NtProtectVirtualMemory(
  365. Process,
  366. (PVOID *)&Stack,
  367. &RegionSize,
  368. PAGE_GUARD | PAGE_READWRITE,
  369. &OldProtect
  370. );
  371. if ( !NT_SUCCESS( Status ) ) {
  372. return Status;
  373. }
  374. InitialTeb->BStoreLimit = (PVOID)Stack;
  375. #endif // IA64
  376. }
  377. return STATUS_SUCCESS;
  378. }
  379. VOID
  380. BaseThreadStart(
  381. IN LPTHREAD_START_ROUTINE lpStartAddress,
  382. IN LPVOID lpParameter
  383. )
  384. /*++
  385. Routine Description:
  386. This function is called to start a Win32 thread. Its purpose
  387. is to call the thread, and if the thread returns, to terminate
  388. the thread and delete its stack.
  389. Arguments:
  390. lpStartAddress - Supplies the starting address of the new thread. The
  391. address is logically a procedure that never returns and that
  392. accepts a single 32-bit pointer argument.
  393. lpParameter - Supplies a single parameter value passed to the thread.
  394. Return Value:
  395. None.
  396. --*/
  397. {
  398. try {
  399. //
  400. // test for fiber start or new thread
  401. //
  402. //
  403. // WARNING WARNING DO NOT CHANGE INIT OF NtTib.Version. There is
  404. // external code depending on this initialization !
  405. //
  406. if ( NtCurrentTeb()->NtTib.Version == OS2_VERSION ) {
  407. if ( !BaseRunningInServerProcess ) {
  408. CsrNewThread();
  409. }
  410. }
  411. ExitThread((lpStartAddress)(lpParameter));
  412. }
  413. except(UnhandledExceptionFilter( GetExceptionInformation() )) {
  414. if ( !BaseRunningInServerProcess ) {
  415. ExitProcess(GetExceptionCode());
  416. }
  417. else {
  418. ExitThread(GetExceptionCode());
  419. }
  420. }
  421. }
  422. VOID
  423. BaseProcessStart(
  424. PPROCESS_START_ROUTINE lpStartAddress
  425. )
  426. /*++
  427. Routine Description:
  428. This function is called to start a Win32 process. Its purpose is to
  429. call the initial thread of the process, and if the thread returns,
  430. to terminate the thread and delete its stack.
  431. Arguments:
  432. lpStartAddress - Supplies the starting address of the new thread. The
  433. address is logically a procedure that never returns.
  434. Return Value:
  435. None.
  436. --*/
  437. {
  438. try {
  439. #if defined(BUILD_WOW6432)
  440. void Report32bitAppLaunching ( );
  441. Report32bitAppLaunching ();
  442. #endif
  443. NtSetInformationThread( NtCurrentThread(),
  444. ThreadQuerySetWin32StartAddress,
  445. &lpStartAddress,
  446. sizeof( lpStartAddress )
  447. );
  448. ExitThread((lpStartAddress)());
  449. }
  450. except(UnhandledExceptionFilter( GetExceptionInformation() )) {
  451. if ( !BaseRunningInServerProcess ) {
  452. ExitProcess(GetExceptionCode());
  453. }
  454. else {
  455. ExitThread(GetExceptionCode());
  456. }
  457. }
  458. }
  459. VOID
  460. BaseFreeStackAndTerminate(
  461. IN PVOID OldStack,
  462. IN DWORD ExitCode
  463. )
  464. /*++
  465. Routine Description:
  466. This API is called during thread termination to delete a thread's
  467. stack and then terminate.
  468. Arguments:
  469. OldStack - Supplies the address of the stack to free.
  470. ExitCode - Supplies the termination status that the thread
  471. is to exit with.
  472. Return Value:
  473. None.
  474. --*/
  475. {
  476. NTSTATUS Status;
  477. SIZE_T Zero;
  478. PVOID BaseAddress;
  479. #if defined (WX86)
  480. PWX86TIB Wx86Tib;
  481. PTEB Teb;
  482. #endif
  483. Zero = 0;
  484. BaseAddress = OldStack;
  485. Status = NtFreeVirtualMemory(
  486. NtCurrentProcess(),
  487. &BaseAddress,
  488. &Zero,
  489. MEM_RELEASE
  490. );
  491. ASSERT(NT_SUCCESS(Status));
  492. #if defined (WX86)
  493. Teb = NtCurrentTeb();
  494. if (Teb && (Wx86Tib = Wx86CurrentTib())) {
  495. BaseAddress = Wx86Tib->DeallocationStack;
  496. Zero = 0;
  497. Status = NtFreeVirtualMemory(
  498. NtCurrentProcess(),
  499. &BaseAddress,
  500. &Zero,
  501. MEM_RELEASE
  502. );
  503. ASSERT(NT_SUCCESS(Status));
  504. if (Teb->Wx86Thread.DeallocationCpu) {
  505. BaseAddress = Teb->Wx86Thread.DeallocationCpu;
  506. Zero = 0;
  507. Status = NtFreeVirtualMemory(
  508. NtCurrentProcess(),
  509. &BaseAddress,
  510. &Zero,
  511. MEM_RELEASE
  512. );
  513. ASSERT(NT_SUCCESS(Status));
  514. }
  515. }
  516. #endif
  517. //
  518. // Don't worry, no commenting precedent has been set by SteveWo. this
  519. // comment was added by an innocent bystander.
  520. //
  521. // NtTerminateThread will return if this thread is the last one in
  522. // the process. So ExitProcess will only be called if that is the
  523. // case.
  524. //
  525. NtTerminateThread(NULL,(NTSTATUS)ExitCode);
  526. ExitProcess(ExitCode);
  527. }
  528. #if defined(WX86) || defined(_AXP64_)
  529. NTSTATUS
  530. BaseCreateWx86Tib(
  531. HANDLE Process,
  532. HANDLE Thread,
  533. ULONG InitialPc,
  534. ULONG CommittedStackSize,
  535. ULONG MaximumStackSize,
  536. BOOLEAN EmulateInitialPc
  537. )
  538. /*++
  539. Routine Description:
  540. This API is called to create a Wx86Tib for Wx86 emulated threads
  541. Arguments:
  542. Process - Target Process
  543. Thread - Target Thread
  544. Parameter - Supplies the thread's parameter.
  545. InitialPc - Supplies an initial program counter value.
  546. StackSize - BaseCreateStack parameters
  547. MaximumStackSize - BaseCreateStack parameters
  548. BOOLEAN
  549. Return Value:
  550. NtStatus from mem allocations
  551. --*/
  552. {
  553. NTSTATUS Status;
  554. PTEB Teb;
  555. ULONG Size, SizeWx86Tib;
  556. PVOID TargetWx86Tib;
  557. PIMAGE_NT_HEADERS NtHeaders;
  558. WX86TIB Wx86Tib;
  559. INITIAL_TEB InitialTeb;
  560. THREAD_BASIC_INFORMATION ThreadInfo;
  561. Status = NtQueryInformationThread(
  562. Thread,
  563. ThreadBasicInformation,
  564. &ThreadInfo,
  565. sizeof( ThreadInfo ),
  566. NULL
  567. );
  568. if (!NT_SUCCESS(Status)) {
  569. return Status;
  570. }
  571. Teb = ThreadInfo.TebBaseAddress;
  572. //
  573. // if stack size not supplied, get from current image
  574. //
  575. NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
  576. if (!NtHeaders) {
  577. return STATUS_INVALID_IMAGE_FORMAT;
  578. }
  579. if (!MaximumStackSize) {
  580. MaximumStackSize = (ULONG)NtHeaders->OptionalHeader.SizeOfStackReserve;
  581. }
  582. if (!CommittedStackSize) {
  583. CommittedStackSize = (ULONG)NtHeaders->OptionalHeader.SizeOfStackCommit;
  584. }
  585. //
  586. // Increase stack size for Wx86Tib, which sits at the top of the stack.
  587. //
  588. //
  589. // x86 Borland C++ 4.1 (and perhaps other versions) Rudely assumes that
  590. // it can use the top of the stack. Even tho this is completly bogus,
  591. // leave some space on the top of the stack, to avoid problems.
  592. //
  593. SizeWx86Tib = sizeof(WX86TIB) + 16;
  594. SizeWx86Tib = ROUND_UP(SizeWx86Tib, sizeof(ULONG));
  595. Size = (ULONG)ROUND_UP_TO_PAGES(SizeWx86Tib + 4096);
  596. if (CommittedStackSize < 1024 * 1024) { // 1 MB
  597. CommittedStackSize += Size;
  598. }
  599. if (MaximumStackSize < 1024 * 1024 * 16) { // 10 MB
  600. MaximumStackSize += Size;
  601. }
  602. if (MaximumStackSize < 256 * 1024) {
  603. // Enforce a minimum stack size of 256k since the CPU emulator
  604. // grabs several pages of the x86 stack for itself
  605. MaximumStackSize = 256 * 1024;
  606. }
  607. Status = BaseCreateStack( Process,
  608. CommittedStackSize,
  609. MaximumStackSize,
  610. &InitialTeb
  611. );
  612. if (!NT_SUCCESS(Status)) {
  613. return Status;
  614. }
  615. //
  616. // Fill in the Teb->Vdm with pWx86Tib
  617. //
  618. TargetWx86Tib = (PVOID)((ULONG_PTR)InitialTeb.StackBase - SizeWx86Tib);
  619. Status = NtWriteVirtualMemory(Process,
  620. &Teb->Vdm,
  621. &TargetWx86Tib,
  622. sizeof(TargetWx86Tib),
  623. NULL
  624. );
  625. if (NT_SUCCESS(Status)) {
  626. //
  627. // Write the initial Wx86Tib information
  628. //
  629. RtlZeroMemory(&Wx86Tib, sizeof(WX86TIB));
  630. Wx86Tib.Size = sizeof(WX86TIB);
  631. Wx86Tib.InitialPc = InitialPc;
  632. Wx86Tib.InitialSp = (ULONG)((ULONG_PTR)TargetWx86Tib);
  633. Wx86Tib.StackBase = (VOID * POINTER_32) InitialTeb.StackBase;
  634. Wx86Tib.StackLimit = (VOID * POINTER_32) InitialTeb.StackLimit;
  635. Wx86Tib.DeallocationStack = (VOID * POINTER_32) InitialTeb.StackAllocationBase;
  636. Wx86Tib.EmulateInitialPc = EmulateInitialPc;
  637. Status = NtWriteVirtualMemory(Process,
  638. TargetWx86Tib,
  639. &Wx86Tib,
  640. sizeof(WX86TIB),
  641. NULL
  642. );
  643. }
  644. if (!NT_SUCCESS(Status)) {
  645. BaseFreeThreadStack(Process, NULL, &InitialTeb);
  646. }
  647. return Status;
  648. }
  649. #endif
  650. VOID
  651. BaseFreeThreadStack(
  652. HANDLE hProcess,
  653. HANDLE hThread,
  654. PINITIAL_TEB InitialTeb
  655. )
  656. /*++
  657. Routine Description:
  658. Deletes a thread's stack
  659. Arguments:
  660. Process - Target process
  661. Thread - Target thread OPTIONAL
  662. InitialTeb - stack paremeters
  663. Return Value:
  664. VOID
  665. --*/
  666. {
  667. NTSTATUS Status;
  668. DWORD dwStackSize;
  669. SIZE_T stStackSize;
  670. PVOID BaseAddress;
  671. stStackSize = 0;
  672. dwStackSize = 0;
  673. BaseAddress = InitialTeb->StackAllocationBase;
  674. NtFreeVirtualMemory( hProcess,
  675. &BaseAddress,
  676. &stStackSize,
  677. MEM_RELEASE
  678. );
  679. #if defined (WX86)
  680. if (hThread) {
  681. PTEB Teb;
  682. PWX86TIB pWx86Tib;
  683. WX86TIB Wx86Tib;
  684. THREAD_BASIC_INFORMATION ThreadInfo;
  685. Status = NtQueryInformationThread(
  686. hThread,
  687. ThreadBasicInformation,
  688. &ThreadInfo,
  689. sizeof( ThreadInfo ),
  690. NULL
  691. );
  692. Teb = ThreadInfo.TebBaseAddress;
  693. if (!NT_SUCCESS(Status) || !Teb) {
  694. return;
  695. }
  696. Status = NtReadVirtualMemory(
  697. hProcess,
  698. &Teb->Vdm,
  699. &pWx86Tib,
  700. sizeof(pWx86Tib),
  701. NULL
  702. );
  703. if (!NT_SUCCESS(Status) || !pWx86Tib) {
  704. return;
  705. }
  706. Status = NtReadVirtualMemory(
  707. hProcess,
  708. pWx86Tib,
  709. &Wx86Tib,
  710. sizeof(Wx86Tib),
  711. NULL
  712. );
  713. if (NT_SUCCESS(Status) && Wx86Tib.Size == sizeof(WX86TIB)) {
  714. // release the wx86tib stack
  715. dwStackSize = 0;
  716. stStackSize = 0;
  717. BaseAddress = Wx86Tib.DeallocationStack;
  718. NtFreeVirtualMemory(hProcess,
  719. &BaseAddress,
  720. &stStackSize,
  721. MEM_RELEASE
  722. );
  723. // set Teb->Vdm = NULL;
  724. dwStackSize = 0;
  725. Status = NtWriteVirtualMemory(
  726. hProcess,
  727. &Teb->Vdm,
  728. &dwStackSize,
  729. sizeof(pWx86Tib),
  730. NULL
  731. );
  732. }
  733. }
  734. #endif
  735. }
  736. #if defined(BUILD_WOW6432)
  737. typedef HANDLE (WINAPI* __imp_RegisterEventSourceWType) (HANDLE, PWCHAR );
  738. typedef HANDLE (WINAPI* __imp_DeregisterEventSourceType) (HANDLE);
  739. typedef HANDLE (WINAPI* __imp_ReportEventType)(
  740. HANDLE hEventLog, // handle to event log
  741. WORD wType, // event type
  742. WORD wCategory, // event category
  743. DWORD dwEventID, // event identifier
  744. PVOID lpUserSid, // user security identifier
  745. WORD wNumStrings, // number of strings to merge
  746. DWORD dwDataSize, // size of binary data
  747. PWCHAR *lpStrings, // array of strings to merge
  748. LPVOID lpRawData // binary data buffer
  749. );
  750. void
  751. Wow64LogMessageInEventLogger(
  752. PWCHAR *szMsg
  753. )
  754. /*++
  755. Routine Description:
  756. This function logs an event into the application log.
  757. Arguments:
  758. szMsg - event-log message pointer.
  759. Return Value:
  760. None.
  761. --*/
  762. {
  763. HMODULE hMod;
  764. HANDLE h;
  765. __imp_RegisterEventSourceWType __imp_RegisterEventSourceW;
  766. __imp_DeregisterEventSourceType __imp_DeregisterEventSource;
  767. __imp_ReportEventType __imp_ReportEvent;
  768. hMod =LoadLibraryW (L"advapi32.dll");
  769. if (hMod != NULL) {
  770. __imp_RegisterEventSourceW = (__imp_RegisterEventSourceWType)GetProcAddress (hMod, "RegisterEventSourceW");
  771. __imp_DeregisterEventSource = (__imp_DeregisterEventSourceType)GetProcAddress (hMod, "DeregisterEventSource");
  772. __imp_ReportEvent = (__imp_ReportEventType)GetProcAddress (hMod, "ReportEventW");
  773. if ((__imp_RegisterEventSourceW != NULL) &&
  774. (__imp_DeregisterEventSource != NULL) &&
  775. (__imp_ReportEvent != NULL)) {
  776. h = __imp_RegisterEventSourceW (NULL, L"Wow64 Emulation Layer");
  777. if (h != NULL) {
  778. if (!__imp_ReportEvent (
  779. h, // event log handle
  780. EVENTLOG_INFORMATION_TYPE, // EVENTLOG_WARNING_TYPE
  781. 0, // category zero
  782. EVENT_WOW64_RUNNING32BIT_APPLICATION , // event identifier
  783. NULL, // no user security identifier
  784. 1, // one substitution string
  785. 0, // no data
  786. szMsg, // pointer to string array
  787. NULL)) { // pointer to data
  788. DbgPrint ("Wow64-EventLog: Couldn't report event - %lx\n", GetLastError ());
  789. }
  790. __imp_DeregisterEventSource (h);
  791. }
  792. }
  793. FreeLibrary (hMod);
  794. }
  795. }
  796. void
  797. Report32bitAppLaunching ()
  798. /*++
  799. Routine Description:
  800. This routine is called whenever a 32-bit is launched on win64 (inside Wow64). It will
  801. check to see if application loggin is enabled, and if so, will log an event to the
  802. application log.
  803. Arguments:
  804. None.
  805. Return Value:
  806. None.
  807. --*/
  808. {
  809. const static UNICODE_STRING KeyName = RTL_CONSTANT_STRING (L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\wow64\\config");
  810. static UNICODE_STRING ValueName = RTL_CONSTANT_STRING (L"LogAppLaunchingEvent");
  811. static OBJECT_ATTRIBUTES ObjA = RTL_CONSTANT_OBJECT_ATTRIBUTES (&KeyName, OBJ_CASE_INSENSITIVE);
  812. WCHAR Buffer [MAX_PATH];
  813. const PWCHAR Msg [2] = {Buffer, NULL};
  814. PWCHAR pAppName;
  815. HKEY hKey;
  816. PUNICODE_STRING ImageName;
  817. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  818. NTSTATUS Status;
  819. PPEB Peb;
  820. PWSTR PtrToCopy;
  821. DWORD CopyLength;
  822. Status = NtOpenKey (&hKey, KEY_READ | KEY_WOW64_64KEY, &ObjA);
  823. if (NT_SUCCESS(Status)) {
  824. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
  825. Status = NtQueryValueKey(
  826. hKey,
  827. &ValueName,
  828. KeyValuePartialInformation,
  829. KeyValueInformation,
  830. sizeof (Buffer),
  831. &CopyLength
  832. );
  833. NtClose (hKey);
  834. if ((NT_SUCCESS (Status)) &&
  835. (KeyValueInformation->Type == REG_DWORD) &&
  836. (KeyValueInformation->DataLength == sizeof (DWORD))) {
  837. if (*(LONG *)KeyValueInformation->Data == 0x1) {
  838. Peb = NtCurrentPeb ();
  839. PtrToCopy = NULL;
  840. if (Peb->ProcessParameters != NULL) {
  841. ImageName = &Peb->ProcessParameters->ImagePathName;
  842. ASSERT (ImageName->Buffer != NULL);
  843. if (ImageName->Length > (sizeof (Buffer) - sizeof (UNICODE_NULL))) {
  844. CopyLength = (sizeof (Buffer) - sizeof (UNICODE_NULL));
  845. PtrToCopy = (PWSTR)((PSTR)ImageName->Buffer + (ImageName->Length - sizeof (Buffer)) + sizeof (UNICODE_NULL));
  846. } else {
  847. CopyLength = ImageName->Length;
  848. PtrToCopy = ImageName->Buffer;
  849. }
  850. if ( CopyLength){
  851. RtlCopyMemory (Buffer, PtrToCopy, CopyLength);
  852. Buffer [(CopyLength >> 1)] = UNICODE_NULL;
  853. } else swprintf (Buffer, L"PID=%d",NtCurrentTeb()->ClientId.UniqueProcess);
  854. }
  855. Wow64LogMessageInEventLogger ((PWCHAR *)Msg);
  856. }
  857. }
  858. }
  859. }
  860. typedef struct _ENVIRONMENT_THUNK_TABLE
  861. {
  862. WCHAR *Native;
  863. WCHAR *X86;
  864. WCHAR *FakeName;
  865. } ENVIRONMENT_THUNK_TABLE, *PENVIRONMENT_THUNK_TABLE;
  866. ENVIRONMENT_THUNK_TABLE ProgramFilesEnvironment[] =
  867. {
  868. {
  869. L"ProgramFiles",
  870. L"ProgramFiles(x86)",
  871. L"ProgramW6432"
  872. },
  873. {
  874. L"CommonProgramFiles",
  875. L"CommonProgramFiles(x86)",
  876. L"CommonProgramW6432"
  877. },
  878. {
  879. L"PROCESSOR_ARCHITECTURE",
  880. L"PROCESSOR_ARCHITECTURE",
  881. L"PROCESSOR_ARCHITEW6432"
  882. }
  883. };
  884. NTSTATUS
  885. Wow64pThunkEnvironmentVariables (
  886. IN OUT PVOID *Environment
  887. )
  888. /*++
  889. Routine Description:
  890. This routine is called when we are about to create a 64-bit process for
  891. a 32-bit process. It thunks back the ProgramFiles environment
  892. variables so that they point to the native directory.
  893. This routine must stay in sync with what's in \base\wow64\wow64\init.c.
  894. Arguments:
  895. Environment - Address of pointer of environment variable to thunk.
  896. Return Value:
  897. NTSTATUS.
  898. --*/
  899. {
  900. UNICODE_STRING Name, Value;
  901. WCHAR Buffer [ MAX_PATH ];
  902. NTSTATUS NtStatus;
  903. ULONG i=0;
  904. while (i < (sizeof(ProgramFilesEnvironment) / sizeof(ProgramFilesEnvironment[0]))) {
  905. RtlInitUnicodeString (&Name, ProgramFilesEnvironment[i].FakeName);
  906. Value.Length = 0;
  907. Value.MaximumLength = sizeof (Buffer);
  908. Value.Buffer = Buffer;
  909. NtStatus = RtlQueryEnvironmentVariable_U (*Environment,
  910. &Name,
  911. &Value
  912. );
  913. if (NT_SUCCESS (NtStatus)) {
  914. RtlSetEnvironmentVariable (Environment,
  915. &Name,
  916. NULL
  917. );
  918. RtlInitUnicodeString (&Name, ProgramFilesEnvironment[i].Native);
  919. NtStatus = RtlSetEnvironmentVariable (Environment,
  920. &Name,
  921. &Value
  922. );
  923. }
  924. if (!NT_SUCCESS (NtStatus)) {
  925. break;
  926. }
  927. i++;
  928. }
  929. return NtStatus;
  930. }
  931. #endif
  932. BOOL
  933. BasePushProcessParameters(
  934. DWORD dwFlags,
  935. HANDLE Process,
  936. PPEB NewPeb,
  937. LPCWSTR ApplicationPathName,
  938. LPCWSTR CurrentDirectory,
  939. LPCWSTR CommandLine,
  940. LPVOID Environment,
  941. LPSTARTUPINFOW lpStartupInfo,
  942. DWORD dwCreationFlags,
  943. BOOL bInheritHandles,
  944. DWORD dwSubsystem,
  945. PVOID pAppCompatData,
  946. DWORD cbAppCompatData
  947. )
  948. /*++
  949. Routine Description:
  950. This function allocates a process parameters record and
  951. formats it. The parameter record is then written into the
  952. address space of the specified process.
  953. Arguments:
  954. dwFlags - bitmask of flags to affect the behavior of
  955. BasePushProcessParameters.
  956. BASE_PUSH_PROCESS_PARAMETERS_FLAG_APP_MANIFEST_PRESENT
  957. Set to indicate that an application manifest was found/used
  958. for the given executable.
  959. Process - Supplies a handle to the process that is to get the
  960. parameters.
  961. Peb - Supplies the address of the new processes PEB.
  962. ApplicationPathName - Supplies the application path name for the
  963. process.
  964. CurrentDirectory - Supplies an optional current directory for the
  965. process. If not specified, then the current directory is used.
  966. CommandLine - Supplies a command line for the new process.
  967. Environment - Supplies an optional environment variable list for the
  968. process. If not specified, then the current processes arguments
  969. are passed.
  970. lpStartupInfo - Supplies the startup information for the processes
  971. main window.
  972. dwCreationFlags - Supplies creation flags for the process
  973. bInheritHandles - TRUE if child process inherited handles from parent
  974. dwSubsystem - if non-zero, then value will be stored in child process
  975. PEB. Only non-zero for separate VDM applications, where the child
  976. process has NTVDM.EXE subsystem type, not the 16-bit application
  977. type, which is what we want.
  978. pAppCompatData - data that is needed for appcompat backend
  979. cbAppCompatData - data size in bytes
  980. Return Value:
  981. TRUE - The operation was successful.
  982. FALSE - The operation Failed.
  983. --*/
  984. {
  985. BOOL bStatus;
  986. UNICODE_STRING ImagePathName;
  987. UNICODE_STRING CommandLineString;
  988. UNICODE_STRING CurrentDirString;
  989. UNICODE_STRING DllPath;
  990. UNICODE_STRING WindowTitle;
  991. UNICODE_STRING DesktopInfo;
  992. UNICODE_STRING ShellInfo;
  993. UNICODE_STRING RuntimeInfo;
  994. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  995. PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess;
  996. ULONG ParameterLength, EnvironmentLength;
  997. SIZE_T RegionSize;
  998. PWCHAR s;
  999. NTSTATUS Status;
  1000. WCHAR FullPathBuffer[MAX_PATH+5];
  1001. WCHAR *fp;
  1002. DWORD Rvalue;
  1003. LPWSTR DllPathData;
  1004. LPVOID pAppCompatDataInNewProcess;
  1005. BOOLEAN PebLocked = FALSE;
  1006. PPEB Peb;
  1007. #if defined(BUILD_WOW6432)
  1008. ULONG_PTR Peb32;
  1009. PVOID TempEnvironment = NULL;
  1010. #endif
  1011. Peb = NtCurrentPeb ();
  1012. Rvalue = GetFullPathNameW(ApplicationPathName,MAX_PATH+4,FullPathBuffer,&fp);
  1013. if ( Rvalue == 0 || Rvalue > MAX_PATH+4 ) {
  1014. DllPathData = BaseComputeProcessDllPath( ApplicationPathName,
  1015. Environment);
  1016. if (!DllPathData) {
  1017. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1018. return FALSE;
  1019. }
  1020. RtlInitUnicodeString( &DllPath, DllPathData );
  1021. RtlInitUnicodeString( &ImagePathName, ApplicationPathName );
  1022. } else {
  1023. DllPathData = BaseComputeProcessDllPath( FullPathBuffer,
  1024. Environment);
  1025. if ( !DllPathData ) {
  1026. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1027. return FALSE;
  1028. }
  1029. RtlInitUnicodeString( &DllPath, DllPathData );
  1030. RtlInitUnicodeString( &ImagePathName, FullPathBuffer );
  1031. }
  1032. RtlInitUnicodeString( &CommandLineString, CommandLine );
  1033. RtlInitUnicodeString( &CurrentDirString, CurrentDirectory );
  1034. if ( lpStartupInfo->lpDesktop ) {
  1035. RtlInitUnicodeString( &DesktopInfo, lpStartupInfo->lpDesktop );
  1036. } else {
  1037. RtlInitUnicodeString( &DesktopInfo, L"");
  1038. }
  1039. if ( lpStartupInfo->lpReserved ) {
  1040. RtlInitUnicodeString( &ShellInfo, lpStartupInfo->lpReserved );
  1041. } else {
  1042. RtlInitUnicodeString( &ShellInfo, L"");
  1043. }
  1044. RuntimeInfo.Buffer = (PWSTR)lpStartupInfo->lpReserved2;
  1045. RuntimeInfo.Length = lpStartupInfo->cbReserved2;
  1046. RuntimeInfo.MaximumLength = RuntimeInfo.Length;
  1047. if (NULL == pAppCompatData) {
  1048. cbAppCompatData = 0;
  1049. }
  1050. if ( lpStartupInfo->lpTitle ) {
  1051. RtlInitUnicodeString( &WindowTitle, lpStartupInfo->lpTitle );
  1052. } else {
  1053. RtlInitUnicodeString( &WindowTitle, ApplicationPathName );
  1054. }
  1055. Status = RtlCreateProcessParameters( &ProcessParameters,
  1056. &ImagePathName,
  1057. &DllPath,
  1058. (ARGUMENT_PRESENT(CurrentDirectory) ? &CurrentDirString : NULL),
  1059. &CommandLineString,
  1060. Environment,
  1061. &WindowTitle,
  1062. &DesktopInfo,
  1063. &ShellInfo,
  1064. &RuntimeInfo
  1065. );
  1066. if (!NT_SUCCESS( Status )) {
  1067. BaseSetLastNTError(Status);
  1068. return FALSE;
  1069. }
  1070. if ( !bInheritHandles ) {
  1071. ProcessParameters->CurrentDirectory.Handle = NULL;
  1072. }
  1073. try {
  1074. if (Environment == NULL) {
  1075. PebLocked = TRUE;
  1076. RtlAcquirePebLock ();
  1077. Environment = Peb->ProcessParameters->Environment;
  1078. } else {
  1079. Environment = ProcessParameters->Environment;
  1080. }
  1081. if (s = Environment) {
  1082. while (s[0] != L'\0' || s[1] != L'\0') {
  1083. s++;
  1084. }
  1085. s += 2;
  1086. EnvironmentLength = (ULONG)((PUCHAR)s - (PUCHAR)Environment);
  1087. ProcessParameters->Environment = NULL;
  1088. RegionSize = EnvironmentLength;
  1089. Status = NtAllocateVirtualMemory( Process,
  1090. (PVOID *)&ProcessParameters->Environment,
  1091. 0,
  1092. &RegionSize,
  1093. MEM_COMMIT,
  1094. PAGE_READWRITE
  1095. );
  1096. if ( !NT_SUCCESS( Status ) ) {
  1097. BaseSetLastNTError(Status);
  1098. bStatus = FALSE;
  1099. leave;
  1100. }
  1101. #if defined(BUILD_WOW6432)
  1102. //
  1103. // Let's try and thunk back some environment variables if we are about to
  1104. // launch a 64-bit process
  1105. //
  1106. Status = NtQueryInformationProcess (Process,
  1107. ProcessWow64Information,
  1108. &Peb32,
  1109. sizeof (Peb32),
  1110. NULL
  1111. );
  1112. if (NT_SUCCESS (Status) && (Peb32 == 0)) {
  1113. RegionSize = EnvironmentLength;
  1114. Status = NtAllocateVirtualMemory (NtCurrentProcess(),
  1115. &TempEnvironment,
  1116. 0,
  1117. &RegionSize,
  1118. MEM_COMMIT,
  1119. PAGE_READWRITE
  1120. );
  1121. if (NT_SUCCESS (Status)) {
  1122. try {
  1123. RtlCopyMemory (TempEnvironment,
  1124. Environment,
  1125. EnvironmentLength
  1126. );
  1127. } except (EXCEPTION_EXECUTE_HANDLER) {
  1128. Status = GetExceptionCode ();
  1129. }
  1130. if (NT_SUCCESS (Status)) {
  1131. //
  1132. // Thunk back special environment variables so that they won't be inherited
  1133. // for 64-bit processes
  1134. //
  1135. Status = Wow64pThunkEnvironmentVariables (&TempEnvironment);
  1136. if (NT_SUCCESS (Status)) {
  1137. Environment = TempEnvironment;
  1138. }
  1139. }
  1140. }
  1141. }
  1142. #endif
  1143. Status = NtWriteVirtualMemory( Process,
  1144. ProcessParameters->Environment,
  1145. Environment,
  1146. EnvironmentLength,
  1147. NULL
  1148. );
  1149. if (PebLocked) {
  1150. RtlReleasePebLock ();
  1151. PebLocked = FALSE;
  1152. }
  1153. #if defined(BUILD_WOW6432)
  1154. if (TempEnvironment != NULL) {
  1155. RegionSize = 0;
  1156. NtFreeVirtualMemory(NtCurrentProcess(),
  1157. &TempEnvironment,
  1158. &RegionSize,
  1159. MEM_RELEASE
  1160. );
  1161. }
  1162. #endif
  1163. if ( !NT_SUCCESS( Status ) ) {
  1164. BaseSetLastNTError(Status);
  1165. bStatus = FALSE;
  1166. leave;
  1167. }
  1168. }
  1169. //
  1170. // Push the parameters into the new process
  1171. //
  1172. ProcessParameters->StartingX = lpStartupInfo->dwX;
  1173. ProcessParameters->StartingY = lpStartupInfo->dwY;
  1174. ProcessParameters->CountX = lpStartupInfo->dwXSize;
  1175. ProcessParameters->CountY = lpStartupInfo->dwYSize;
  1176. ProcessParameters->CountCharsX = lpStartupInfo->dwXCountChars;
  1177. ProcessParameters->CountCharsY = lpStartupInfo->dwYCountChars;
  1178. ProcessParameters->FillAttribute = lpStartupInfo->dwFillAttribute;
  1179. ProcessParameters->WindowFlags = lpStartupInfo->dwFlags;
  1180. ProcessParameters->ShowWindowFlags = lpStartupInfo->wShowWindow;
  1181. if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  1182. ProcessParameters->StandardInput = lpStartupInfo->hStdInput;
  1183. ProcessParameters->StandardOutput = lpStartupInfo->hStdOutput;
  1184. ProcessParameters->StandardError = lpStartupInfo->hStdError;
  1185. }
  1186. if (dwCreationFlags & DETACHED_PROCESS) {
  1187. ProcessParameters->ConsoleHandle = (HANDLE)CONSOLE_DETACHED_PROCESS;
  1188. } else if (dwCreationFlags & CREATE_NEW_CONSOLE) {
  1189. ProcessParameters->ConsoleHandle = (HANDLE)CONSOLE_NEW_CONSOLE;
  1190. } else if (dwCreationFlags & CREATE_NO_WINDOW) {
  1191. ProcessParameters->ConsoleHandle = (HANDLE)CONSOLE_CREATE_NO_WINDOW;
  1192. } else {
  1193. ProcessParameters->ConsoleHandle = Peb->ProcessParameters->ConsoleHandle;
  1194. if (!(lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_HASSHELLDATA))) {
  1195. if (bInheritHandles ||
  1196. CONSOLE_HANDLE( Peb->ProcessParameters->StandardInput )
  1197. ) {
  1198. ProcessParameters->StandardInput =
  1199. Peb->ProcessParameters->StandardInput;
  1200. }
  1201. if (bInheritHandles ||
  1202. CONSOLE_HANDLE( Peb->ProcessParameters->StandardOutput )
  1203. ) {
  1204. ProcessParameters->StandardOutput =
  1205. Peb->ProcessParameters->StandardOutput;
  1206. }
  1207. if (bInheritHandles ||
  1208. CONSOLE_HANDLE( Peb->ProcessParameters->StandardError )
  1209. ) {
  1210. ProcessParameters->StandardError =
  1211. Peb->ProcessParameters->StandardError;
  1212. }
  1213. }
  1214. }
  1215. //
  1216. // CREATE_NEW_PROCESS_GROUP, in the absence of CREATE_NEW_CONSOLE,
  1217. // means that CTRL+C events should be ignored. This is solely for
  1218. // appcompat.
  1219. //
  1220. if ((dwCreationFlags & CREATE_NEW_PROCESS_GROUP) != 0 &&
  1221. (dwCreationFlags & CREATE_NEW_CONSOLE) == 0) {
  1222. ProcessParameters->ConsoleFlags |= CONSOLE_IGNORE_CTRL_C;
  1223. }
  1224. ProcessParameters->Flags |=
  1225. (Peb->ProcessParameters->Flags & RTL_USER_PROC_DISABLE_HEAP_DECOMMIT);
  1226. ParameterLength = ProcessParameters->Length;
  1227. if (dwFlags & BASE_PUSH_PROCESS_PARAMETERS_FLAG_APP_MANIFEST_PRESENT)
  1228. ProcessParameters->Flags |= RTL_USER_PROC_APP_MANIFEST_PRESENT;
  1229. //
  1230. // Allocate memory in the new process to push the parameters
  1231. //
  1232. ParametersInNewProcess = NULL;
  1233. RegionSize = ParameterLength;
  1234. Status = NtAllocateVirtualMemory(
  1235. Process,
  1236. (PVOID *)&ParametersInNewProcess,
  1237. 0,
  1238. &RegionSize,
  1239. MEM_COMMIT,
  1240. PAGE_READWRITE
  1241. );
  1242. ParameterLength = (ULONG)RegionSize;
  1243. if ( !NT_SUCCESS( Status ) ) {
  1244. BaseSetLastNTError(Status);
  1245. bStatus = FALSE;
  1246. leave;
  1247. }
  1248. ProcessParameters->MaximumLength = ParameterLength;
  1249. if ( dwCreationFlags & PROFILE_USER ) {
  1250. ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_USER;
  1251. }
  1252. if ( dwCreationFlags & PROFILE_KERNEL ) {
  1253. ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_KERNEL;
  1254. }
  1255. if ( dwCreationFlags & PROFILE_SERVER ) {
  1256. ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_SERVER;
  1257. }
  1258. //
  1259. // Push the parameters
  1260. //
  1261. Status = NtWriteVirtualMemory(
  1262. Process,
  1263. ParametersInNewProcess,
  1264. ProcessParameters,
  1265. ProcessParameters->Length,
  1266. NULL
  1267. );
  1268. if ( !NT_SUCCESS( Status ) ) {
  1269. BaseSetLastNTError(Status);
  1270. bStatus = FALSE;
  1271. leave;
  1272. }
  1273. //
  1274. // Make the processes PEB point to the parameters.
  1275. //
  1276. Status = NtWriteVirtualMemory(
  1277. Process,
  1278. &NewPeb->ProcessParameters,
  1279. &ParametersInNewProcess,
  1280. sizeof( ParametersInNewProcess ),
  1281. NULL
  1282. );
  1283. if ( !NT_SUCCESS( Status ) ) {
  1284. BaseSetLastNTError(Status);
  1285. bStatus = FALSE;
  1286. leave;
  1287. }
  1288. //
  1289. // allocate and write appcompat data for the new process
  1290. //
  1291. pAppCompatDataInNewProcess = NULL;
  1292. if ( NULL != pAppCompatData ) {
  1293. RegionSize = cbAppCompatData;
  1294. Status = NtAllocateVirtualMemory(
  1295. Process,
  1296. (PVOID*)&pAppCompatDataInNewProcess,
  1297. 0,
  1298. &RegionSize,
  1299. MEM_COMMIT,
  1300. PAGE_READWRITE
  1301. );
  1302. if ( !NT_SUCCESS( Status ) ) {
  1303. BaseSetLastNTError(Status);
  1304. bStatus = FALSE;
  1305. leave;
  1306. }
  1307. //
  1308. // write the data itself
  1309. //
  1310. Status = NtWriteVirtualMemory(
  1311. Process,
  1312. pAppCompatDataInNewProcess,
  1313. pAppCompatData,
  1314. cbAppCompatData,
  1315. NULL
  1316. );
  1317. if ( !NT_SUCCESS( Status ) ) {
  1318. BaseSetLastNTError(Status);
  1319. bStatus = FALSE;
  1320. leave;
  1321. }
  1322. }
  1323. //
  1324. // save the pointer to appcompat data in peb
  1325. //
  1326. Status = NtWriteVirtualMemory(
  1327. Process,
  1328. &NewPeb->pShimData,
  1329. &pAppCompatDataInNewProcess,
  1330. sizeof( pAppCompatDataInNewProcess ),
  1331. NULL
  1332. );
  1333. if ( !NT_SUCCESS( Status ) ) {
  1334. BaseSetLastNTError(Status);
  1335. bStatus = FALSE;
  1336. leave;
  1337. }
  1338. //
  1339. // Set subsystem type in PEB if requested by caller. Ignore error
  1340. //
  1341. if (dwSubsystem != 0) {
  1342. NtWriteVirtualMemory(
  1343. Process,
  1344. &NewPeb->ImageSubsystem,
  1345. &dwSubsystem,
  1346. sizeof( NewPeb->ImageSubsystem ),
  1347. NULL
  1348. );
  1349. }
  1350. bStatus = TRUE;
  1351. } finally {
  1352. if (PebLocked) {
  1353. RtlReleasePebLock ();
  1354. }
  1355. RtlFreeHeap (RtlProcessHeap(), 0,DllPath.Buffer);
  1356. if ( ProcessParameters ) {
  1357. RtlDestroyProcessParameters(ProcessParameters);
  1358. }
  1359. }
  1360. return bStatus;
  1361. }
  1362. LPCWSTR
  1363. BasepEndOfDirName(
  1364. IN LPCWSTR FileName
  1365. )
  1366. {
  1367. LPCWSTR FileNameEnd,
  1368. FileNameFirstWhack = wcschr(FileName, L'\\');
  1369. if (FileNameFirstWhack) {
  1370. FileNameEnd = wcsrchr(FileNameFirstWhack, L'\\');
  1371. ASSERT(FileNameEnd);
  1372. if (FileNameEnd == FileNameFirstWhack)
  1373. FileNameEnd++;
  1374. } else {
  1375. FileNameEnd = NULL;
  1376. }
  1377. return FileNameEnd;
  1378. }
  1379. VOID
  1380. BasepLocateExeLdrEntry(
  1381. IN PCLDR_DATA_TABLE_ENTRY Entry,
  1382. IN PVOID Context,
  1383. IN OUT BOOLEAN *StopEnumeration
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. This function is a LDR_LOADED_MODULE_ENUMBERATION_CALLBACK_FUNCTION
  1388. which locates the exe's loader data table entry.
  1389. Arguments:
  1390. Entry - the entry currently being enumerated.
  1391. Context - the image base address (NtCurrentPeb()->ImageBaseAddress).
  1392. StopEnumeration - used to stop the enumeration.
  1393. Return Value:
  1394. None. The exe's loader data table entry, if found, is stored in
  1395. the global BasepExeLdrEntry.
  1396. --*/
  1397. {
  1398. ASSERT(Entry);
  1399. ASSERT(Context);
  1400. ASSERT(StopEnumeration);
  1401. if (BasepExeLdrEntry) {
  1402. *StopEnumeration = TRUE;
  1403. } else if (Entry->DllBase == Context) {
  1404. BasepExeLdrEntry = Entry;
  1405. *StopEnumeration = TRUE;
  1406. }
  1407. }
  1408. LPWSTR
  1409. BasepComputeProcessPath(
  1410. IN const BASEP_SEARCH_PATH_ELEMENT *Elements,
  1411. IN LPCWSTR AppName,
  1412. IN LPVOID Environment
  1413. )
  1414. /*++
  1415. Routine Description:
  1416. This function computes a process path.
  1417. Arguments:
  1418. Elements - The elements to build into a path.
  1419. AppName - An optional argument that specifies the name of
  1420. the application. If this parameter is not specified,
  1421. then the current application is used.
  1422. Environment - Supplies the environment block to be used to calculate
  1423. the path variable value.
  1424. Return Value:
  1425. The return value is the value of the requested path.
  1426. --*/
  1427. {
  1428. LPCWSTR AppNameEnd;
  1429. const BASEP_SEARCH_PATH_ELEMENT *Element;
  1430. UNICODE_STRING EnvPath;
  1431. LPWSTR EnvPathBuffer = NULL;
  1432. LPWSTR PathBuffer = NULL,
  1433. PathCurrent;
  1434. ULONG PathLengthInBytes;
  1435. NTSTATUS Status = STATUS_SUCCESS;
  1436. __try {
  1437. // First, figure out how much space we'll need.
  1438. PathLengthInBytes = 0;
  1439. for (Element = Elements;
  1440. *Element != BasepSearchPathEnd;
  1441. Element++) {
  1442. switch (*Element) {
  1443. case BasepSearchPathCurdir:
  1444. PathLengthInBytes += 2 * sizeof(UNICODE_NULL); // .;
  1445. break;
  1446. case BasepSearchPathDlldir:
  1447. ASSERT(BaseDllDirectory.Buffer != NULL);
  1448. PathLengthInBytes += BaseDllDirectory.Length;
  1449. if (BaseDllDirectory.Length) {
  1450. PathLengthInBytes += sizeof(UNICODE_NULL);
  1451. }
  1452. break;
  1453. case BasepSearchPathAppdir:
  1454. if (AppName) {
  1455. // Try to use the passed-in appname
  1456. AppNameEnd = BasepEndOfDirName(AppName);
  1457. }
  1458. if (!AppName || !AppNameEnd) {
  1459. // We didn't have or were unable to use the passed-in
  1460. // appname -- so attempt to use the current exe's name
  1461. if (RtlGetPerThreadCurdir()
  1462. && RtlGetPerThreadCurdir()->ImageName) {
  1463. AppName = RtlGetPerThreadCurdir()->ImageName->Buffer;
  1464. } else {
  1465. BasepCheckExeLdrEntry();
  1466. if (BasepExeLdrEntry) {
  1467. AppName = BasepExeLdrEntry->FullDllName.Buffer;
  1468. }
  1469. }
  1470. if (AppName) {
  1471. AppNameEnd = BasepEndOfDirName(AppName);
  1472. }
  1473. }
  1474. if (AppName && AppNameEnd) {
  1475. // Either we had a passed-in appname which worked, or
  1476. // we found the current exe's name and that worked.
  1477. //
  1478. // AppNameEnd points to the end of the base of the exe
  1479. // name -- so the difference is the number of
  1480. // characters in the base name, and we add one for the
  1481. // trailing semicolon / NULL.
  1482. PathLengthInBytes += ((AppNameEnd - AppName + 1)
  1483. * sizeof(UNICODE_NULL));
  1484. }
  1485. break;
  1486. case BasepSearchPathDefaultDirs:
  1487. ASSERT(! (BaseDefaultPath.Length & 1));
  1488. // We don't need an extra UNICODE_NULL here -- baseinit.c
  1489. // appends our trailing semicolon for us.
  1490. PathLengthInBytes += BaseDefaultPath.Length;
  1491. break;
  1492. case BasepSearchPathEnvPath:
  1493. if (! Environment) {
  1494. RtlAcquirePebLock();
  1495. }
  1496. __try {
  1497. EnvPath.MaximumLength = 0;
  1498. Status = RtlQueryEnvironmentVariable_U(Environment,
  1499. &BasePathVariableName,
  1500. &EnvPath);
  1501. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1502. // Now that we know how much to allocate, attempt
  1503. // to alloc a buffer that's actually big enough.
  1504. EnvPath.MaximumLength = EnvPath.Length + sizeof(UNICODE_NULL);
  1505. EnvPathBuffer = RtlAllocateHeap(RtlProcessHeap(),
  1506. MAKE_TAG(TMP_TAG),
  1507. EnvPath.MaximumLength);
  1508. if (! EnvPathBuffer) {
  1509. Status = STATUS_NO_MEMORY;
  1510. __leave;
  1511. }
  1512. EnvPath.Buffer = EnvPathBuffer;
  1513. Status = RtlQueryEnvironmentVariable_U(Environment,
  1514. &BasePathVariableName,
  1515. &EnvPath);
  1516. }
  1517. } __finally {
  1518. if (! Environment) {
  1519. RtlReleasePebLock();
  1520. }
  1521. }
  1522. if (Status == STATUS_VARIABLE_NOT_FOUND) {
  1523. EnvPath.Length = 0;
  1524. Status = STATUS_SUCCESS;
  1525. } else if (! NT_SUCCESS(Status)) {
  1526. __leave;
  1527. } else {
  1528. // The final tally is the length, in bytes, of whatever
  1529. // we're using for our path, plus a character for the
  1530. // trailing whack or NULL.
  1531. ASSERT(! (EnvPath.Length & 1));
  1532. PathLengthInBytes += EnvPath.Length + sizeof(UNICODE_NULL);
  1533. }
  1534. break;
  1535. DEFAULT_UNREACHABLE;
  1536. } // switch (*Element)
  1537. } // foreach Element (Elements) -- size loop
  1538. ASSERT(PathLengthInBytes > 0);
  1539. ASSERT(! (PathLengthInBytes & 1));
  1540. // Now we have the length, in bytes, of the buffer we'll need for
  1541. // our path. Time to allocate it...
  1542. PathBuffer = RtlAllocateHeap(RtlProcessHeap(),
  1543. MAKE_TAG(TMP_TAG),
  1544. PathLengthInBytes);
  1545. if (! PathBuffer) {
  1546. Status = STATUS_NO_MEMORY;
  1547. __leave;
  1548. }
  1549. // Now go through the loop again, this time appending onto the
  1550. // PathBuffer.
  1551. PathCurrent = PathBuffer;
  1552. for (Element = Elements;
  1553. *Element != BasepSearchPathEnd;
  1554. Element++) {
  1555. switch (*Element) {
  1556. case BasepSearchPathCurdir:
  1557. ASSERT(((PathCurrent - PathBuffer + 2)
  1558. * sizeof(UNICODE_NULL))
  1559. <= PathLengthInBytes);
  1560. *PathCurrent++ = L'.';
  1561. *PathCurrent++ = L';';
  1562. break;
  1563. case BasepSearchPathDlldir:
  1564. if (BaseDllDirectory.Length) {
  1565. ASSERT((((PathCurrent - PathBuffer + 1)
  1566. * sizeof(UNICODE_NULL))
  1567. + BaseDllDirectory.Length)
  1568. <= PathLengthInBytes);
  1569. RtlCopyMemory(PathCurrent,
  1570. BaseDllDirectory.Buffer,
  1571. BaseDllDirectory.Length);
  1572. PathCurrent += (BaseDllDirectory.Length >> 1);
  1573. *PathCurrent++ = L';';
  1574. }
  1575. break;
  1576. case BasepSearchPathAppdir:
  1577. if (AppName && AppNameEnd) {
  1578. ASSERT(((PathCurrent - PathBuffer + 1
  1579. + (AppNameEnd - AppName))
  1580. * sizeof(UNICODE_NULL))
  1581. <= PathLengthInBytes);
  1582. RtlCopyMemory(PathCurrent,
  1583. AppName,
  1584. ((AppNameEnd - AppName)
  1585. * sizeof(UNICODE_NULL)));
  1586. PathCurrent += AppNameEnd - AppName;
  1587. *PathCurrent++ = L';';
  1588. }
  1589. break;
  1590. case BasepSearchPathDefaultDirs:
  1591. ASSERT((((PathCurrent - PathBuffer)
  1592. * sizeof(UNICODE_NULL))
  1593. + BaseDefaultPath.Length)
  1594. <= PathLengthInBytes);
  1595. RtlCopyMemory(PathCurrent,
  1596. BaseDefaultPath.Buffer,
  1597. BaseDefaultPath.Length);
  1598. PathCurrent += (BaseDefaultPath.Length >> 1);
  1599. // We don't need to add a semicolon here -- baseinit.c
  1600. // appends our trailing semicolon for us.
  1601. break;
  1602. case BasepSearchPathEnvPath:
  1603. if (EnvPath.Length) {
  1604. ASSERT((((PathCurrent - PathBuffer + 1)
  1605. * sizeof(UNICODE_NULL))
  1606. + EnvPath.Length)
  1607. <= PathLengthInBytes);
  1608. RtlCopyMemory(PathCurrent,
  1609. EnvPath.Buffer,
  1610. EnvPath.Length);
  1611. PathCurrent += (EnvPath.Length >> 1);
  1612. *PathCurrent++ = L';';
  1613. }
  1614. break;
  1615. DEFAULT_UNREACHABLE;
  1616. } // switch (*Element)
  1617. } // foreach Element (Elements) -- append loop
  1618. // At this point, PathCurrent points just beyond PathBuffer.
  1619. // Let's assert that...
  1620. ASSERT((PathCurrent - PathBuffer) * sizeof(UNICODE_NULL)
  1621. == PathLengthInBytes);
  1622. // ... and turn the final ';' into the string terminator.
  1623. ASSERT(PathCurrent > PathBuffer);
  1624. PathCurrent[-1] = UNICODE_NULL;
  1625. } __finally {
  1626. if (EnvPathBuffer) {
  1627. RtlFreeHeap(RtlProcessHeap(),
  1628. 0,
  1629. EnvPathBuffer);
  1630. }
  1631. if (PathBuffer
  1632. && (AbnormalTermination()
  1633. || ! NT_SUCCESS(Status))) {
  1634. RtlFreeHeap(RtlProcessHeap(),
  1635. 0,
  1636. PathBuffer);
  1637. PathBuffer = NULL;
  1638. }
  1639. }
  1640. return PathBuffer;
  1641. }
  1642. LPWSTR
  1643. BaseComputeProcessDllPath(
  1644. IN LPCWSTR AppName,
  1645. IN LPVOID Environment
  1646. )
  1647. /*++
  1648. Routine Description:
  1649. This function computes a process DLL path.
  1650. Arguments:
  1651. AppName - An optional argument that specifies the name of
  1652. the application. If this parameter is not specified, then the
  1653. current application is used.
  1654. Environment - Supplies the environment block to be used to calculate
  1655. the path variable value.
  1656. Return Value:
  1657. The return value is the value of the processes DLL path.
  1658. --*/
  1659. {
  1660. NTSTATUS Status;
  1661. HANDLE Key;
  1662. static UNICODE_STRING
  1663. KeyName = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager"),
  1664. ValueName = RTL_CONSTANT_STRING(L"SafeDllSearchMode");
  1665. static OBJECT_ATTRIBUTES
  1666. ObjA = RTL_CONSTANT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE);
  1667. CHAR Buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)
  1668. + sizeof(DWORD)];
  1669. PKEY_VALUE_PARTIAL_INFORMATION Info;
  1670. ULONG ResultLength;
  1671. LONG CurrentDirPlacement,
  1672. PrevCurrentDirPlacement;
  1673. LPWSTR Result;
  1674. static const BASEP_SEARCH_PATH_ELEMENT DllDirSearchPath[] = {
  1675. BasepSearchPathAppdir,
  1676. BasepSearchPathDlldir,
  1677. BasepSearchPathDefaultDirs,
  1678. BasepSearchPathEnvPath,
  1679. BasepSearchPathEnd
  1680. };
  1681. RtlEnterCriticalSection(&BaseDllDirectoryLock);
  1682. if (BaseDllDirectory.Buffer) {
  1683. Result = BasepComputeProcessPath(DllDirSearchPath,
  1684. AppName,
  1685. Environment);
  1686. RtlLeaveCriticalSection(&BaseDllDirectoryLock);
  1687. return Result;
  1688. }
  1689. RtlLeaveCriticalSection(&BaseDllDirectoryLock);
  1690. CurrentDirPlacement = BasepDllCurrentDirPlacement;
  1691. if (CurrentDirPlacement == BasepCurrentDirUninitialized) {
  1692. Status = NtOpenKey(&Key,
  1693. KEY_QUERY_VALUE,
  1694. &ObjA);
  1695. if (! NT_SUCCESS(Status)) {
  1696. goto compute_path;
  1697. }
  1698. Info = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
  1699. Status = NtQueryValueKey(Key,
  1700. &ValueName,
  1701. KeyValuePartialInformation,
  1702. Info,
  1703. sizeof(Buffer),
  1704. &ResultLength);
  1705. if (! NT_SUCCESS(Status)) {
  1706. goto close_key;
  1707. }
  1708. if (ResultLength != sizeof(Buffer)) {
  1709. goto close_key;
  1710. }
  1711. RtlCopyMemory(&CurrentDirPlacement,
  1712. Info->Data,
  1713. sizeof(DWORD));
  1714. close_key:
  1715. NtClose(Key);
  1716. compute_path:
  1717. if (! BASEP_VALID_CURDIR_PLACEMENT_P(CurrentDirPlacement)) {
  1718. CurrentDirPlacement = BASEP_DEFAULT_DLL_CURDIR_PLACEMENT;
  1719. }
  1720. PrevCurrentDirPlacement = InterlockedCompareExchange(&BasepDllCurrentDirPlacement,
  1721. CurrentDirPlacement,
  1722. BasepCurrentDirUninitialized);
  1723. if (PrevCurrentDirPlacement != BasepCurrentDirUninitialized) {
  1724. CurrentDirPlacement = PrevCurrentDirPlacement;
  1725. }
  1726. }
  1727. if (! BASEP_VALID_CURDIR_PLACEMENT_P(CurrentDirPlacement)) {
  1728. CurrentDirPlacement = BASEP_DEFAULT_DLL_CURDIR_PLACEMENT;
  1729. }
  1730. return BasepComputeProcessPath(BasepDllSearchPaths[CurrentDirPlacement],
  1731. AppName,
  1732. Environment);
  1733. }
  1734. LPWSTR
  1735. BaseComputeProcessSearchPath(
  1736. VOID
  1737. )
  1738. /*++
  1739. Routine Description:
  1740. This function computes a process search path.
  1741. Arguments:
  1742. None
  1743. Return Value:
  1744. The return value is the value of the processes search path.
  1745. --*/
  1746. {
  1747. static const BASEP_SEARCH_PATH_ELEMENT SearchPath[] = {
  1748. BasepSearchPathAppdir,
  1749. BasepSearchPathCurdir,
  1750. BasepSearchPathDefaultDirs,
  1751. BasepSearchPathEnvPath,
  1752. BasepSearchPathEnd
  1753. };
  1754. return BasepComputeProcessPath(SearchPath,
  1755. NULL,
  1756. NULL);
  1757. }
  1758. LPWSTR
  1759. BaseComputeProcessExePath(
  1760. LPCWSTR ExeName
  1761. )
  1762. /*++
  1763. Routine Description:
  1764. This function computes a process exe path.
  1765. Arguments:
  1766. ExeName - The name of the exe which will be looked for.
  1767. Return Value:
  1768. The return value is the value of the processes exe path.
  1769. --*/
  1770. {
  1771. static const BASEP_SEARCH_PATH_ELEMENT UseDotSearchPath[] = {
  1772. BasepSearchPathAppdir,
  1773. BasepSearchPathCurdir,
  1774. BasepSearchPathDefaultDirs,
  1775. BasepSearchPathEnvPath,
  1776. BasepSearchPathEnd
  1777. };
  1778. static const BASEP_SEARCH_PATH_ELEMENT NoDotSearchPath[] = {
  1779. BasepSearchPathAppdir,
  1780. BasepSearchPathDefaultDirs,
  1781. BasepSearchPathEnvPath,
  1782. BasepSearchPathEnd
  1783. };
  1784. return BasepComputeProcessPath((NeedCurrentDirectoryForExePathW(ExeName)
  1785. ? UseDotSearchPath
  1786. : NoDotSearchPath),
  1787. NULL,
  1788. NULL);
  1789. }
  1790. PUNICODE_STRING
  1791. Basep8BitStringToStaticUnicodeString(
  1792. IN LPCSTR lpSourceString
  1793. )
  1794. /*++
  1795. Routine Description:
  1796. Captures and converts a 8-bit (OEM or ANSI) string into the Teb Static
  1797. Unicode String
  1798. Arguments:
  1799. lpSourceString - string in OEM or ANSI
  1800. Return Value:
  1801. Pointer to the Teb static string if conversion was successful, NULL
  1802. otherwise. If a failure occurred, the last error is set.
  1803. --*/
  1804. {
  1805. PUNICODE_STRING StaticUnicode;
  1806. ANSI_STRING AnsiString;
  1807. NTSTATUS Status;
  1808. //
  1809. // Get pointer to static per-thread string
  1810. //
  1811. StaticUnicode = &NtCurrentTeb()->StaticUnicodeString;
  1812. //
  1813. // Convert input string into unicode string
  1814. //
  1815. Status = RtlInitAnsiStringEx( &AnsiString, lpSourceString );
  1816. if( NT_SUCCESS(Status) ) {
  1817. Status = Basep8BitStringToUnicodeString( StaticUnicode, &AnsiString, FALSE );
  1818. } else {
  1819. Status = STATUS_BUFFER_OVERFLOW;
  1820. }
  1821. //
  1822. // If we couldn't convert the string
  1823. //
  1824. if ( !NT_SUCCESS( Status ) ) {
  1825. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1826. SetLastError( ERROR_FILENAME_EXCED_RANGE );
  1827. } else {
  1828. BaseSetLastNTError( Status );
  1829. }
  1830. return NULL;
  1831. } else {
  1832. return StaticUnicode;
  1833. }
  1834. }
  1835. BOOL
  1836. Basep8BitStringToDynamicUnicodeString(
  1837. OUT PUNICODE_STRING UnicodeString,
  1838. IN LPCSTR lpSourceString
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. Captures and converts a 8-bit (OEM or ANSI) string into a heap-allocated
  1843. UNICODE string
  1844. Arguments:
  1845. UnicodeString - location where UNICODE_STRING is stored
  1846. lpSourceString - string in OEM or ANSI
  1847. Return Value:
  1848. TRUE if string is correctly stored, FALSE if an error occurred. In the
  1849. error case, the last error is correctly set.
  1850. --*/
  1851. {
  1852. ANSI_STRING AnsiString;
  1853. NTSTATUS Status;
  1854. //
  1855. // Convert input into dynamic unicode string
  1856. //
  1857. Status = RtlInitAnsiStringEx( &AnsiString, lpSourceString );
  1858. if( NT_SUCCESS(Status) ) {
  1859. Status = Basep8BitStringToUnicodeString( UnicodeString, &AnsiString, TRUE );
  1860. } else {
  1861. Status = STATUS_BUFFER_OVERFLOW;
  1862. }
  1863. //
  1864. // If we couldn't do this, fail
  1865. //
  1866. if (!NT_SUCCESS( Status )){
  1867. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1868. SetLastError( ERROR_FILENAME_EXCED_RANGE );
  1869. } else {
  1870. BaseSetLastNTError( Status );
  1871. }
  1872. return FALSE;
  1873. }
  1874. return TRUE;
  1875. }
  1876. //
  1877. // Thunks for converting between ANSI/OEM and UNICODE
  1878. //
  1879. ULONG
  1880. BasepAnsiStringToUnicodeSize(
  1881. PANSI_STRING AnsiString
  1882. )
  1883. /*++
  1884. Routine Description:
  1885. Determines the size of a UNICODE version of an ANSI string
  1886. Arguments:
  1887. AnsiString - string to examine
  1888. Return Value:
  1889. Byte size of UNICODE version of string including a trailing L'\0'.
  1890. --*/
  1891. {
  1892. return RtlAnsiStringToUnicodeSize( AnsiString );
  1893. }
  1894. ULONG
  1895. BasepOemStringToUnicodeSize(
  1896. PANSI_STRING OemString
  1897. )
  1898. /*++
  1899. Routine Description:
  1900. Determines the size of a UNICODE version of an OEM string
  1901. Arguments:
  1902. OemString - string to examine
  1903. Return Value:
  1904. Byte size of UNICODE version of string including a trailing L'\0'.
  1905. --*/
  1906. {
  1907. return RtlOemStringToUnicodeSize( OemString );
  1908. }
  1909. ULONG
  1910. BasepUnicodeStringToOemSize(
  1911. PUNICODE_STRING UnicodeString
  1912. )
  1913. /*++
  1914. Routine Description:
  1915. Determines the size of an OEM version of a UNICODE string
  1916. Arguments:
  1917. UnicodeString - string to examine
  1918. Return Value:
  1919. Byte size of OEM version of string including a trailing '\0'.
  1920. --*/
  1921. {
  1922. return RtlUnicodeStringToOemSize( UnicodeString );
  1923. }
  1924. ULONG
  1925. BasepUnicodeStringToAnsiSize(
  1926. PUNICODE_STRING UnicodeString
  1927. )
  1928. /*++
  1929. Routine Description:
  1930. Determines the size of an ANSI version of a UNICODE string
  1931. Arguments:
  1932. UnicodeString - string to examine
  1933. Return Value:
  1934. Byte size of ANSI version of string including a trailing '\0'.
  1935. --*/
  1936. {
  1937. return RtlUnicodeStringToAnsiSize( UnicodeString );
  1938. }
  1939. typedef struct _BASEP_ACQUIRE_STATE {
  1940. HANDLE Token;
  1941. PTOKEN_PRIVILEGES OldPrivileges;
  1942. PTOKEN_PRIVILEGES NewPrivileges;
  1943. ULONG Revert;
  1944. ULONG Spare;
  1945. BYTE OldPrivBuffer[ 1024 ];
  1946. } BASEP_ACQUIRE_STATE, *PBASEP_ACQUIRE_STATE;
  1947. //
  1948. // This function does the correct thing - it checks for the thread token
  1949. // before opening the process token.
  1950. //
  1951. NTSTATUS
  1952. BasepAcquirePrivilegeEx(
  1953. ULONG Privilege,
  1954. PVOID *ReturnedState
  1955. )
  1956. {
  1957. PBASEP_ACQUIRE_STATE State;
  1958. ULONG cbNeeded;
  1959. LUID LuidPrivilege;
  1960. NTSTATUS Status, Status1;
  1961. BOOL St;
  1962. //
  1963. // Make sure we have access to adjust and to get the old token privileges
  1964. //
  1965. *ReturnedState = NULL;
  1966. State = RtlAllocateHeap (RtlProcessHeap(),
  1967. MAKE_TAG( TMP_TAG ),
  1968. sizeof(BASEP_ACQUIRE_STATE) +
  1969. sizeof(TOKEN_PRIVILEGES) +
  1970. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  1971. if (State == NULL) {
  1972. return STATUS_NO_MEMORY;
  1973. }
  1974. State->Revert = 0;
  1975. if (RtlIsImpersonating()) {
  1976. //
  1977. // We're impersonating. So make sure we use the specified
  1978. // impersonation token.
  1979. //
  1980. Status = NtOpenThreadToken (NtCurrentThread(),
  1981. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1982. FALSE,
  1983. &State->Token);
  1984. if (! NT_SUCCESS(Status)) {
  1985. RtlFreeHeap(RtlProcessHeap(), 0, State);
  1986. return Status;
  1987. }
  1988. } else {
  1989. //
  1990. // We're not impersonating. So make a copy of the process
  1991. // token, and impersonate that, so that we're monkeying about
  1992. // with our own privs instead of everyone's.
  1993. //
  1994. Status = RtlImpersonateSelf (SecurityDelegation);
  1995. if (!NT_SUCCESS (Status)) {
  1996. RtlFreeHeap (RtlProcessHeap(), 0, State);
  1997. return Status;
  1998. }
  1999. Status = NtOpenThreadToken (NtCurrentThread(),
  2000. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  2001. FALSE,
  2002. &State->Token);
  2003. if (!NT_SUCCESS (Status)) {
  2004. State->Token = NULL;
  2005. Status1 = NtSetInformationThread (NtCurrentThread(),
  2006. ThreadImpersonationToken,
  2007. &State->Token,
  2008. sizeof (State->Token));
  2009. ASSERT (NT_SUCCESS (Status1));
  2010. RtlFreeHeap( RtlProcessHeap(), 0, State );
  2011. return Status;
  2012. }
  2013. State->Revert = 1;
  2014. }
  2015. State->NewPrivileges = (PTOKEN_PRIVILEGES)(State+1);
  2016. State->OldPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer);
  2017. //
  2018. // Initialize the privilege adjustment structure
  2019. //
  2020. LuidPrivilege = RtlConvertUlongToLuid(Privilege);
  2021. State->NewPrivileges->PrivilegeCount = 1;
  2022. State->NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  2023. State->NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  2024. //
  2025. // Enable the privilege
  2026. //
  2027. cbNeeded = sizeof( State->OldPrivBuffer );
  2028. Status = NtAdjustPrivilegesToken (State->Token,
  2029. FALSE,
  2030. State->NewPrivileges,
  2031. cbNeeded,
  2032. State->OldPrivileges,
  2033. &cbNeeded);
  2034. if (Status == STATUS_BUFFER_TOO_SMALL) {
  2035. State->OldPrivileges = RtlAllocateHeap (RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cbNeeded);
  2036. if (State->OldPrivileges == NULL) {
  2037. Status = STATUS_NO_MEMORY;
  2038. } else {
  2039. Status = NtAdjustPrivilegesToken (State->Token,
  2040. FALSE,
  2041. State->NewPrivileges,
  2042. cbNeeded,
  2043. State->OldPrivileges,
  2044. &cbNeeded);
  2045. }
  2046. }
  2047. //
  2048. // STATUS_NOT_ALL_ASSIGNED means that the privilege isn't
  2049. // in the token, so we can't proceed.
  2050. //
  2051. // This is a warning level status, so map it to an error status.
  2052. //
  2053. if (Status == STATUS_NOT_ALL_ASSIGNED) {
  2054. Status = STATUS_PRIVILEGE_NOT_HELD;
  2055. }
  2056. if (!NT_SUCCESS( Status )) {
  2057. if (State->OldPrivileges != (PTOKEN_PRIVILEGES)State->OldPrivBuffer) {
  2058. RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
  2059. }
  2060. St = CloseHandle (State->Token);
  2061. ASSERT (St);
  2062. State->Token = NULL;
  2063. if (State->Revert) {
  2064. Status1 = NtSetInformationThread (NtCurrentThread(),
  2065. ThreadImpersonationToken,
  2066. &State->Token,
  2067. sizeof (State->Token));
  2068. ASSERT (NT_SUCCESS (Status1));
  2069. }
  2070. RtlFreeHeap( RtlProcessHeap(), 0, State );
  2071. return Status;
  2072. }
  2073. *ReturnedState = State;
  2074. return STATUS_SUCCESS;
  2075. }
  2076. VOID
  2077. BasepReleasePrivilege(
  2078. PVOID StatePointer
  2079. )
  2080. {
  2081. BOOL St;
  2082. NTSTATUS Status;
  2083. PBASEP_ACQUIRE_STATE State = (PBASEP_ACQUIRE_STATE)StatePointer;
  2084. if (!State->Revert) {
  2085. NtAdjustPrivilegesToken (State->Token,
  2086. FALSE,
  2087. State->OldPrivileges,
  2088. 0,
  2089. NULL,
  2090. NULL);
  2091. }
  2092. if (State->OldPrivileges != (PTOKEN_PRIVILEGES)State->OldPrivBuffer) {
  2093. RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
  2094. }
  2095. St = CloseHandle( State->Token );
  2096. ASSERT (St);
  2097. State->Token = NULL;
  2098. if (State->Revert) {
  2099. Status = NtSetInformationThread (NtCurrentThread(),
  2100. ThreadImpersonationToken,
  2101. &State->Token,
  2102. sizeof (State->Token));
  2103. ASSERT (NT_SUCCESS (Status));
  2104. }
  2105. RtlFreeHeap( RtlProcessHeap(), 0, State );
  2106. return;
  2107. }