Windows NT 4.0 source code leak
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.

1378 lines
44 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. rtlexec.c
  5. Abstract:
  6. User Mode routines for creating user mode processes and threads.
  7. Author:
  8. Steve Wood (stevewo) 18-Aug-1989
  9. Environment:
  10. User Mode or Kernel Mode
  11. Revision History:
  12. --*/
  13. #include "ntrtlp.h"
  14. #include <nturtl.h>
  15. #include <string.h>
  16. #include "init.h"
  17. #include "ntos.h"
  18. #define ROUND_UP( x, y ) ((ULONG)(x) + ((y)-1) & ~((y)-1))
  19. extern ULONG NtGlobalFlag;
  20. VOID
  21. RtlpCopyProcString(
  22. IN OUT PWSTR *pDst,
  23. OUT PUNICODE_STRING DestString,
  24. IN PUNICODE_STRING SourceString,
  25. IN ULONG DstAlloc OPTIONAL
  26. );
  27. NTSTATUS
  28. RtlpOpenImageFile(
  29. IN PUNICODE_STRING ImagePathName,
  30. IN ULONG Attributes,
  31. OUT PHANDLE FileHandle,
  32. IN BOOLEAN ReportErrors
  33. );
  34. NTSTATUS
  35. RtlpFreeStack(
  36. IN HANDLE Process,
  37. IN PINITIAL_TEB InitialTeb
  38. );
  39. NTSTATUS
  40. RtlpCreateStack(
  41. IN HANDLE Process,
  42. IN ULONG MaximumStackSize OPTIONAL,
  43. IN ULONG CommittedStackSize OPTIONAL,
  44. IN ULONG ZeroBits OPTIONAL,
  45. OUT PINITIAL_TEB InitialTeb
  46. );
  47. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  48. #pragma alloc_text(INIT,RtlpCopyProcString )
  49. #pragma alloc_text(INIT,RtlCreateProcessParameters )
  50. #pragma alloc_text(INIT,RtlDestroyProcessParameters )
  51. #pragma alloc_text(INIT,RtlNormalizeProcessParams )
  52. #pragma alloc_text(INIT,RtlDeNormalizeProcessParams )
  53. #pragma alloc_text(INIT,RtlpOpenImageFile )
  54. #pragma alloc_text(INIT,RtlpCreateStack )
  55. #pragma alloc_text(INIT,RtlpFreeStack )
  56. #pragma alloc_text(INIT,RtlCreateUserProcess )
  57. #pragma alloc_text(INIT,RtlCreateUserThread )
  58. #endif
  59. VOID
  60. RtlpCopyProcString(
  61. IN OUT PWSTR *pDst,
  62. OUT PUNICODE_STRING DestString,
  63. IN PUNICODE_STRING SourceString,
  64. IN ULONG DstAlloc OPTIONAL
  65. )
  66. {
  67. if (!ARGUMENT_PRESENT( DstAlloc )) {
  68. DstAlloc = SourceString->MaximumLength;
  69. }
  70. if (SourceString->Buffer != NULL && SourceString->Length != 0) {
  71. RtlMoveMemory( *pDst,
  72. SourceString->Buffer,
  73. SourceString->Length
  74. );
  75. }
  76. DestString->Buffer = *pDst;
  77. DestString->Length = SourceString->Length;
  78. DestString->MaximumLength = (USHORT)DstAlloc;
  79. *pDst = (PWSTR)((PCHAR)(*pDst) + ROUND_UP( DstAlloc, sizeof( ULONG ) ) );
  80. return;
  81. }
  82. NTSTATUS
  83. RtlCreateProcessParameters(
  84. OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
  85. IN PUNICODE_STRING ImagePathName,
  86. IN PUNICODE_STRING DllPath OPTIONAL,
  87. IN PUNICODE_STRING CurrentDirectory OPTIONAL,
  88. IN PUNICODE_STRING CommandLine OPTIONAL,
  89. IN PVOID Environment OPTIONAL,
  90. IN PUNICODE_STRING WindowTitle OPTIONAL,
  91. IN PUNICODE_STRING DesktopInfo OPTIONAL,
  92. IN PUNICODE_STRING ShellInfo OPTIONAL,
  93. IN PUNICODE_STRING RuntimeData OPTIONAL
  94. )
  95. /*++
  96. Routine Description:
  97. This function formats NT style RTL_USER_PROCESS_PARAMETERS
  98. record. The record is self-contained in a single block of memory
  99. allocated by this function. The allocation method is opaque and
  100. thus the record must be freed by calling the
  101. RtlDestroyProcessParameters function.
  102. The process parameters record is created in a de-normalized form,
  103. thus making it suitable for passing to the RtlCreateUserProcess
  104. function. It is expected that the caller will fill in additional
  105. fields in the process parameters record after this function returns,
  106. but prior to calling RtlCreateUserProcess.
  107. Arguments:
  108. ProcessParameters - Pointer to a variable that will receive the address
  109. of the process parameter structure created by this routinue. The
  110. memory for the structure is allocated in an opaque manner and must
  111. be freed by calling RtlDestroyProcessParameters.
  112. ImagePathName - Required parameter that is the fully qualified NT
  113. path name of the image file that will be used to create the process
  114. that will received these parameters.
  115. DllPath - An optional parameter that is an NT String variable pointing
  116. to the search path the NT Loader is to use in the target process
  117. when searching for Dll modules. If not specified, then the Dll
  118. search path is filled in from the current process's Dll search
  119. path.
  120. CurrentDirectory - An optional parameter that is an NT String variable
  121. pointing to the default directory string for the target process.
  122. If not specified, then the current directory string is filled in
  123. from the current process's current directory string.
  124. CommandLine - An optional parameter that is an NT String variable that
  125. will be passed to the target process as its command line. If not
  126. specified, then the command line passed to the target process will
  127. be a null string.
  128. Environment - An optional parameter that is an opaque pointer to an
  129. environment variable block of the type created by
  130. RtlCreateEnvironment routine. If not specified, then the target
  131. process will receive a copy of the calling process's environment
  132. variable block.
  133. WindowTitle - An optional parameter that is an NT String variable that
  134. points to the title string the target process is to use for its
  135. main window. If not specified, then a null string will be passed
  136. to the target process as its default window title.
  137. DesktopInfo - An optional parameter that is an NT String variable that
  138. contains uninterpreted data that is passed as is to the target
  139. process. If not specified, the target process will receive a
  140. pointer to an empty string.
  141. ShellInfo - An optional parameter that is an NT String variable that
  142. contains uninterpreted data that is passed as is to the target
  143. process. If not specified, the target process will receive a
  144. pointer to an empty string.
  145. RuntimeData - An optional parameter that is an NT String variable that
  146. contains uninterpreted data that is passed as is to the target
  147. process. If not specified, the target process will receive a
  148. pointer to an empty string.
  149. Return Value:
  150. STATUS_SUCCESS - The process parameters is De-Normalized and
  151. contains entries for each of the specified argument and variable
  152. strings.
  153. STATUS_BUFFER_TOO_SMALL - The specified process parameters buffer is
  154. too small to contain the argument and environment strings. The value
  155. of ProcessParameters->Length is modified to contain the buffer
  156. size needed to contain the argument and variable strings.
  157. --*/
  158. {
  159. PRTL_USER_PROCESS_PARAMETERS p;
  160. NTSTATUS Status;
  161. UNICODE_STRING NullString = {0, 1, L""};
  162. ULONG ByteCount, MaxByteCount;
  163. PWSTR pDst;
  164. PPEB Peb = NtCurrentPeb();
  165. HANDLE CurDirHandle;
  166. //
  167. // Acquire the Peb Lock for the duration while we copy information out
  168. // of it.
  169. //
  170. RtlAcquirePebLock();
  171. Status = STATUS_SUCCESS;
  172. p = NULL;
  173. CurDirHandle = NULL;
  174. try {
  175. //
  176. // For optional pointer parameters, default them to point to their
  177. // corresponding field in the current process's process parameter
  178. // structure or to a null string.
  179. //
  180. if (!ARGUMENT_PRESENT( DllPath )) {
  181. DllPath = &Peb->ProcessParameters->DllPath;
  182. }
  183. if (!ARGUMENT_PRESENT( CurrentDirectory )) {
  184. if ( Peb->ProcessParameters->CurrentDirectory.Handle ) {
  185. CurDirHandle = (HANDLE)((ULONG)Peb->ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS);
  186. CurDirHandle = (HANDLE)((ULONG)CurDirHandle | RTL_USER_PROC_CURDIR_INHERIT);
  187. }
  188. CurrentDirectory = &Peb->ProcessParameters->CurrentDirectory.DosPath;
  189. }
  190. else {
  191. if ( Peb->ProcessParameters->CurrentDirectory.Handle ) {
  192. CurDirHandle = (HANDLE)((ULONG)Peb->ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS);
  193. CurDirHandle = (HANDLE)((ULONG)CurDirHandle | RTL_USER_PROC_CURDIR_CLOSE);
  194. }
  195. }
  196. if (!ARGUMENT_PRESENT( CommandLine )) {
  197. CommandLine = ImagePathName;
  198. }
  199. if (!ARGUMENT_PRESENT( Environment )) {
  200. Environment = Peb->ProcessParameters->Environment;
  201. }
  202. if (!ARGUMENT_PRESENT( WindowTitle )) {
  203. WindowTitle = &NullString;
  204. }
  205. if (!ARGUMENT_PRESENT( DesktopInfo )) {
  206. DesktopInfo = &NullString;
  207. }
  208. if (!ARGUMENT_PRESENT( ShellInfo )) {
  209. ShellInfo = &NullString;
  210. }
  211. if (!ARGUMENT_PRESENT( RuntimeData )) {
  212. RuntimeData = &NullString;
  213. }
  214. //
  215. // Determine size need to contain the process parameter record
  216. // structure and all of the strings it will point to. Each string
  217. // will be aligned on a ULONG byte boundary.
  218. //
  219. ByteCount = sizeof( **ProcessParameters );
  220. ByteCount += ROUND_UP( ImagePathName->Length + sizeof(UNICODE_NULL), sizeof( ULONG ) );
  221. ByteCount += ROUND_UP( DllPath->MaximumLength, sizeof( ULONG ) );
  222. ByteCount += ROUND_UP( DOS_MAX_PATH_LENGTH*2, sizeof( ULONG ) );
  223. ByteCount += ROUND_UP( CommandLine->Length + sizeof(UNICODE_NULL), sizeof( ULONG ) );
  224. ByteCount += ROUND_UP( WindowTitle->MaximumLength, sizeof( ULONG ) );
  225. ByteCount += ROUND_UP( DesktopInfo->MaximumLength, sizeof( ULONG ) );
  226. ByteCount += ROUND_UP( ShellInfo->MaximumLength, sizeof( ULONG ) );
  227. ByteCount += ROUND_UP( RuntimeData->MaximumLength, sizeof( ULONG ) );
  228. //
  229. // Allocate memory for the process parameter record.
  230. //
  231. MaxByteCount = ByteCount;
  232. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  233. (PVOID *)&p,
  234. 0,
  235. &MaxByteCount,
  236. MEM_COMMIT,
  237. PAGE_READWRITE
  238. );
  239. if (!NT_SUCCESS( Status )) {
  240. return( Status );
  241. }
  242. p->MaximumLength = MaxByteCount;
  243. p->Length = ByteCount;
  244. p->Flags = RTL_USER_PROC_PARAMS_NORMALIZED;
  245. p->Environment = Environment;
  246. p->CurrentDirectory.Handle = CurDirHandle;
  247. //
  248. // Inherits ^C inhibit information
  249. //
  250. p->ConsoleFlags = Peb->ProcessParameters->ConsoleFlags;
  251. pDst = (PWSTR)(p + 1);
  252. RtlpCopyProcString( &pDst,
  253. &p->CurrentDirectory.DosPath,
  254. CurrentDirectory,
  255. DOS_MAX_PATH_LENGTH*2
  256. );
  257. RtlpCopyProcString( &pDst, &p->DllPath, DllPath, 0 );
  258. RtlpCopyProcString( &pDst, &p->ImagePathName, ImagePathName, ImagePathName->Length + sizeof(UNICODE_NULL) );
  259. if (CommandLine->Length == CommandLine->MaximumLength) {
  260. RtlpCopyProcString( &pDst, &p->CommandLine, CommandLine, 0 );
  261. }
  262. else {
  263. RtlpCopyProcString( &pDst, &p->CommandLine, CommandLine, CommandLine->Length + sizeof(UNICODE_NULL) );
  264. }
  265. RtlpCopyProcString( &pDst, &p->WindowTitle, WindowTitle, 0 );
  266. RtlpCopyProcString( &pDst, &p->DesktopInfo, DesktopInfo, 0 );
  267. RtlpCopyProcString( &pDst, &p->ShellInfo, ShellInfo, 0 );
  268. if (RuntimeData->Length != 0) {
  269. RtlpCopyProcString( &pDst, &p->RuntimeData, RuntimeData, 0 );
  270. }
  271. else {
  272. p->RuntimeData.Buffer = NULL;
  273. p->RuntimeData.Length = 0;
  274. p->RuntimeData.MaximumLength = 0;
  275. }
  276. *ProcessParameters = RtlDeNormalizeProcessParams( p );
  277. p = NULL;
  278. }
  279. finally {
  280. if (AbnormalTermination()) {
  281. Status = STATUS_ACCESS_VIOLATION;
  282. }
  283. if (p != NULL) {
  284. RtlDestroyProcessParameters( p );
  285. }
  286. RtlReleasePebLock();
  287. }
  288. return( Status );
  289. }
  290. NTSTATUS
  291. RtlDestroyProcessParameters(
  292. IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  293. )
  294. {
  295. NTSTATUS Status;
  296. ULONG RegionSize;
  297. RegionSize = 0;
  298. Status = ZwFreeVirtualMemory( NtCurrentProcess(),
  299. (PVOID *)&ProcessParameters,
  300. &RegionSize,
  301. MEM_RELEASE
  302. );
  303. return( Status );
  304. }
  305. #define RtlpNormalizeProcessParam( Base, p ) \
  306. if ((p) != NULL) { \
  307. (p) = (PWSTR)((PCHAR)(p) + (ULONG)(Base)); \
  308. } \
  309. #define RtlpDeNormalizeProcessParam( Base, p ) \
  310. if ((p) != NULL) { \
  311. (p) = (PWSTR)((PCHAR)(p) - (ULONG)(Base)); \
  312. } \
  313. PRTL_USER_PROCESS_PARAMETERS
  314. RtlNormalizeProcessParams(
  315. IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  316. )
  317. {
  318. if (!ARGUMENT_PRESENT( ProcessParameters )) {
  319. return( NULL );
  320. }
  321. if (ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED) {
  322. return( ProcessParameters );
  323. }
  324. RtlpNormalizeProcessParam( ProcessParameters,
  325. ProcessParameters->CurrentDirectory.DosPath.Buffer
  326. );
  327. RtlpNormalizeProcessParam( ProcessParameters,
  328. ProcessParameters->DllPath.Buffer
  329. );
  330. RtlpNormalizeProcessParam( ProcessParameters,
  331. ProcessParameters->ImagePathName.Buffer
  332. );
  333. RtlpNormalizeProcessParam( ProcessParameters,
  334. ProcessParameters->CommandLine.Buffer
  335. );
  336. RtlpNormalizeProcessParam( ProcessParameters,
  337. ProcessParameters->WindowTitle.Buffer
  338. );
  339. RtlpNormalizeProcessParam( ProcessParameters,
  340. ProcessParameters->DesktopInfo.Buffer
  341. );
  342. RtlpNormalizeProcessParam( ProcessParameters,
  343. ProcessParameters->ShellInfo.Buffer
  344. );
  345. RtlpNormalizeProcessParam( ProcessParameters,
  346. ProcessParameters->RuntimeData.Buffer
  347. );
  348. ProcessParameters->Flags |= RTL_USER_PROC_PARAMS_NORMALIZED;
  349. return( ProcessParameters );
  350. }
  351. PRTL_USER_PROCESS_PARAMETERS
  352. RtlDeNormalizeProcessParams(
  353. IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  354. )
  355. {
  356. if (!ARGUMENT_PRESENT( ProcessParameters )) {
  357. return( NULL );
  358. }
  359. if (!(ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
  360. return( ProcessParameters );
  361. }
  362. RtlpDeNormalizeProcessParam( ProcessParameters,
  363. ProcessParameters->CurrentDirectory.DosPath.Buffer
  364. );
  365. RtlpDeNormalizeProcessParam( ProcessParameters,
  366. ProcessParameters->DllPath.Buffer
  367. );
  368. RtlpDeNormalizeProcessParam( ProcessParameters,
  369. ProcessParameters->ImagePathName.Buffer
  370. );
  371. RtlpDeNormalizeProcessParam( ProcessParameters,
  372. ProcessParameters->CommandLine.Buffer
  373. );
  374. RtlpDeNormalizeProcessParam( ProcessParameters,
  375. ProcessParameters->WindowTitle.Buffer
  376. );
  377. RtlpDeNormalizeProcessParam( ProcessParameters,
  378. ProcessParameters->DesktopInfo.Buffer
  379. );
  380. RtlpDeNormalizeProcessParam( ProcessParameters,
  381. ProcessParameters->ShellInfo.Buffer
  382. );
  383. RtlpDeNormalizeProcessParam( ProcessParameters,
  384. ProcessParameters->RuntimeData.Buffer
  385. );
  386. ProcessParameters->Flags &= ~RTL_USER_PROC_PARAMS_NORMALIZED;
  387. return( ProcessParameters );
  388. }
  389. NTSTATUS
  390. RtlpOpenImageFile(
  391. IN PUNICODE_STRING ImagePathName,
  392. IN ULONG Attributes,
  393. OUT PHANDLE FileHandle,
  394. IN BOOLEAN ReportErrors
  395. )
  396. {
  397. NTSTATUS Status;
  398. OBJECT_ATTRIBUTES ObjectAttributes;
  399. HANDLE File;
  400. IO_STATUS_BLOCK IoStatus;
  401. *FileHandle = NULL;
  402. InitializeObjectAttributes( &ObjectAttributes,
  403. ImagePathName,
  404. Attributes,
  405. NULL,
  406. NULL
  407. );
  408. Status = ZwOpenFile( &File,
  409. SYNCHRONIZE | FILE_EXECUTE,
  410. &ObjectAttributes,
  411. &IoStatus,
  412. FILE_SHARE_READ | FILE_SHARE_DELETE,
  413. FILE_NON_DIRECTORY_FILE
  414. );
  415. if (!NT_SUCCESS( Status )) {
  416. #if DBG
  417. if (ReportErrors) {
  418. DbgPrint( "NTRTL: RtlpOpenImageFile - NtCreateFile( %wZ ) failed. Status == %X\n",
  419. ImagePathName,
  420. Status
  421. );
  422. }
  423. #endif // DBG
  424. return( Status );
  425. }
  426. *FileHandle = File;
  427. return( STATUS_SUCCESS );
  428. }
  429. NTSTATUS
  430. RtlpCreateStack(
  431. IN HANDLE Process,
  432. IN ULONG MaximumStackSize OPTIONAL,
  433. IN ULONG CommittedStackSize OPTIONAL,
  434. IN ULONG ZeroBits OPTIONAL,
  435. OUT PINITIAL_TEB InitialTeb
  436. )
  437. {
  438. NTSTATUS Status;
  439. PCH Stack;
  440. SYSTEM_BASIC_INFORMATION SysInfo;
  441. BOOLEAN GuardPage;
  442. ULONG RegionSize;
  443. ULONG OldProtect;
  444. Status = ZwQuerySystemInformation( SystemBasicInformation,
  445. (PVOID)&SysInfo,
  446. sizeof( SysInfo ),
  447. NULL
  448. );
  449. if ( !NT_SUCCESS( Status ) ) {
  450. return( Status );
  451. }
  452. //
  453. // if stack is in the current process, then default to
  454. // the parameters from the image
  455. //
  456. if ( Process == NtCurrentProcess() ) {
  457. PPEB Peb;
  458. PIMAGE_NT_HEADERS NtHeaders;
  459. Peb = NtCurrentPeb();
  460. NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
  461. if (!MaximumStackSize) {
  462. MaximumStackSize = NtHeaders->OptionalHeader.SizeOfStackReserve;
  463. }
  464. if (!CommittedStackSize) {
  465. CommittedStackSize = NtHeaders->OptionalHeader.SizeOfStackCommit;
  466. }
  467. }
  468. else {
  469. if (!CommittedStackSize) {
  470. CommittedStackSize = SysInfo.PageSize;
  471. }
  472. if (!MaximumStackSize) {
  473. MaximumStackSize = SysInfo.AllocationGranularity;
  474. }
  475. }
  476. if ( CommittedStackSize >= MaximumStackSize ) {
  477. MaximumStackSize = ROUND_UP(CommittedStackSize, (1024*1024));
  478. }
  479. CommittedStackSize = ROUND_UP( CommittedStackSize, SysInfo.PageSize );
  480. MaximumStackSize = ROUND_UP( MaximumStackSize,
  481. SysInfo.AllocationGranularity
  482. );
  483. Stack = NULL,
  484. Status = ZwAllocateVirtualMemory( Process,
  485. (PVOID *)&Stack,
  486. ZeroBits,
  487. &MaximumStackSize,
  488. MEM_RESERVE,
  489. PAGE_READWRITE
  490. );
  491. if ( !NT_SUCCESS( Status ) ) {
  492. #if DBG
  493. DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed. Stack Reservation Status == %X\n",
  494. Process,
  495. Status
  496. );
  497. #endif // DBG
  498. return( Status );
  499. }
  500. InitialTeb->OldInitialTeb.OldStackBase = NULL;
  501. InitialTeb->OldInitialTeb.OldStackLimit = NULL;
  502. InitialTeb->StackAllocationBase = Stack;
  503. InitialTeb->StackBase = Stack + MaximumStackSize;
  504. Stack += MaximumStackSize - CommittedStackSize;
  505. if (MaximumStackSize > CommittedStackSize) {
  506. Stack -= SysInfo.PageSize;
  507. CommittedStackSize += SysInfo.PageSize;
  508. GuardPage = TRUE;
  509. }
  510. else {
  511. GuardPage = FALSE;
  512. }
  513. Status = ZwAllocateVirtualMemory( Process,
  514. (PVOID *)&Stack,
  515. 0,
  516. &CommittedStackSize,
  517. MEM_COMMIT,
  518. PAGE_READWRITE
  519. );
  520. InitialTeb->StackLimit = Stack;
  521. if ( !NT_SUCCESS( Status ) ) {
  522. #if DBG
  523. DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed. Stack Commit Status == %X\n",
  524. Process,
  525. Status
  526. );
  527. #endif // DBG
  528. return( Status );
  529. }
  530. //
  531. // if we have space, create a guard page.
  532. //
  533. if (GuardPage) {
  534. RegionSize = SysInfo.PageSize;
  535. Status = ZwProtectVirtualMemory( Process,
  536. (PVOID *)&Stack,
  537. &RegionSize,
  538. PAGE_GUARD | PAGE_READWRITE,
  539. &OldProtect);
  540. if ( !NT_SUCCESS( Status ) ) {
  541. #if DBG
  542. DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed. Guard Page Creation Status == %X\n",
  543. Process,
  544. Status
  545. );
  546. #endif // DBG
  547. return( Status );
  548. }
  549. InitialTeb->StackLimit = (PVOID)((PUCHAR)InitialTeb->StackLimit - RegionSize);
  550. }
  551. return( STATUS_SUCCESS );
  552. }
  553. NTSTATUS
  554. RtlpFreeStack(
  555. IN HANDLE Process,
  556. IN PINITIAL_TEB InitialTeb
  557. )
  558. {
  559. NTSTATUS Status;
  560. ULONG Zero;
  561. Zero = 0;
  562. Status = ZwFreeVirtualMemory( Process,
  563. &InitialTeb->StackAllocationBase,
  564. &Zero,
  565. MEM_RELEASE
  566. );
  567. if ( !NT_SUCCESS( Status ) ) {
  568. #if DBG
  569. DbgPrint( "NTRTL: RtlpFreeStack( %lx ) failed. Stack DeCommit Status == %X\n",
  570. Process,
  571. Status
  572. );
  573. #endif // DBG
  574. return( Status );
  575. }
  576. RtlZeroMemory( InitialTeb, sizeof( *InitialTeb ) );
  577. return( STATUS_SUCCESS );
  578. }
  579. NTSTATUS
  580. RtlCreateUserProcess(
  581. IN PUNICODE_STRING NtImagePathName,
  582. IN ULONG Attributes,
  583. IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
  584. IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
  585. IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
  586. IN HANDLE ParentProcess OPTIONAL,
  587. IN BOOLEAN InheritHandles,
  588. IN HANDLE DebugPort OPTIONAL,
  589. IN HANDLE ExceptionPort OPTIONAL,
  590. OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation
  591. )
  592. /*++
  593. Routine Description:
  594. This function creates a user mode process with a single thread with
  595. a suspend count of one. The address space of the new process is
  596. initialized with the contents of specified image file. The caller
  597. can specify the Access Control List for the new process and thread.
  598. The caller can also specify the parent process to inherit process
  599. priority and processor affinity from. The default is to inherit
  600. these from the current process. Finally the caller can specify
  601. whether the new process is to inherit any of the object handles
  602. from the specified parent process or not.
  603. Information about the new process and thread is returned via
  604. the ProcessInformation parameter.
  605. Arguments:
  606. NtImagePathName - A required pointer that points to the NT Path string
  607. that identifies the image file that is to be loaded into the
  608. child process.
  609. ProcessParameters - A required pointer that points to parameters that
  610. are to passed to the child process.
  611. ProcessSecurityDescriptor - An optional pointer to the Security Descriptor
  612. give to the new process.
  613. ThreadSecurityDescriptor - An optional pointer to the Security Descriptor
  614. give to the new thread.
  615. ParentProcess - An optional process handle that will used to inherit
  616. certain properties from.
  617. InheritHandles - A boolean value. TRUE specifies that object handles
  618. associated with the specified parent process are to be inherited
  619. by the new process, provided they have the OBJ_INHERIT attribute.
  620. FALSE specifies that the new process is to inherit no handles.
  621. DebugPort - An optional handle to the debug port associated with this
  622. process.
  623. ExceptionPort - An optional handle to the exception port associated with this
  624. process.
  625. ProcessInformation - A pointer to a variable that receives information
  626. about the new process and thread.
  627. Return Value:
  628. TBS.
  629. --*/
  630. {
  631. NTSTATUS Status;
  632. HANDLE Section, File;
  633. OBJECT_ATTRIBUTES ObjectAttributes;
  634. PRTL_USER_PROCESS_PARAMETERS Parameters;
  635. ULONG ParameterLength;
  636. PVOID Environment;
  637. PWCHAR s;
  638. ULONG EnvironmentLength;
  639. ULONG RegionSize;
  640. PROCESS_BASIC_INFORMATION ProcessInfo;
  641. PPEB Peb;
  642. UNICODE_STRING Unicode;
  643. //
  644. // Zero output parameter and probe the addresses at the same time
  645. //
  646. RtlZeroMemory( ProcessInformation, sizeof( *ProcessInformation ) );
  647. ProcessInformation->Length = sizeof( *ProcessInformation );
  648. //
  649. // Open the specified image file.
  650. //
  651. Status = RtlpOpenImageFile( NtImagePathName,
  652. Attributes & (OBJ_INHERIT | OBJ_CASE_INSENSITIVE),
  653. &File,
  654. TRUE
  655. );
  656. if (!NT_SUCCESS( Status )) {
  657. return( Status );
  658. }
  659. //
  660. // Create a memory section backed by the opened image file
  661. //
  662. Status = ZwCreateSection( &Section,
  663. SECTION_ALL_ACCESS,
  664. NULL,
  665. NULL,
  666. PAGE_EXECUTE,
  667. SEC_IMAGE,
  668. File
  669. );
  670. ZwClose( File );
  671. if ( !NT_SUCCESS( Status ) ) {
  672. #if DBG
  673. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtCreateSection Status == %X \n",
  674. NtImagePathName,
  675. Status
  676. );
  677. #endif // DBG
  678. return( Status );
  679. }
  680. //
  681. // Create the user mode process, defaulting the parent process to the
  682. // current process if one is not specified. The new process will not
  683. // have a name nor will the handle be inherited by other processes.
  684. //
  685. if (!ARGUMENT_PRESENT( ParentProcess )) {
  686. ParentProcess = NtCurrentProcess();
  687. }
  688. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL,
  689. ProcessSecurityDescriptor );
  690. if ( RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG ) {
  691. if ( wcsstr(NtImagePathName->Buffer,L"csrss") ||
  692. wcsstr(NtImagePathName->Buffer,L"CSRSS")
  693. ) {
  694. RtlInitUnicodeString(&Unicode,L"\\WindowsSS");
  695. InitializeObjectAttributes( &ObjectAttributes, &Unicode, 0, NULL,
  696. ProcessSecurityDescriptor );
  697. }
  698. }
  699. if ( !InheritHandles ) {
  700. ProcessParameters->CurrentDirectory.Handle = NULL;
  701. }
  702. Status = ZwCreateProcess( &ProcessInformation->Process,
  703. PROCESS_ALL_ACCESS,
  704. &ObjectAttributes,
  705. ParentProcess,
  706. InheritHandles,
  707. Section,
  708. DebugPort,
  709. ExceptionPort
  710. );
  711. if ( !NT_SUCCESS( Status ) ) {
  712. #if DBG
  713. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtCreateProcess Status == %X\n",
  714. NtImagePathName,
  715. Status
  716. );
  717. #endif // DBG
  718. ZwClose( Section );
  719. return( Status );
  720. }
  721. //
  722. // Retreive the interesting information from the image header
  723. //
  724. Status = ZwQuerySection( Section,
  725. SectionImageInformation,
  726. &ProcessInformation->ImageInformation,
  727. sizeof( ProcessInformation->ImageInformation ),
  728. NULL
  729. );
  730. if ( !NT_SUCCESS( Status ) ) {
  731. #if DBG
  732. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtQuerySection Status == %X\n",
  733. NtImagePathName,
  734. Status
  735. );
  736. #endif // DBG
  737. ZwClose( ProcessInformation->Process );
  738. ZwClose( Section );
  739. return( Status );
  740. }
  741. Status = ZwQueryInformationProcess( ProcessInformation->Process,
  742. ProcessBasicInformation,
  743. &ProcessInfo,
  744. sizeof( ProcessInfo ),
  745. NULL
  746. );
  747. if ( !NT_SUCCESS( Status ) ) {
  748. #if DBG
  749. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtQueryProcessInformation Status == %X\n",
  750. NtImagePathName,
  751. Status
  752. );
  753. #endif // DBG
  754. ZwClose( ProcessInformation->Process );
  755. ZwClose( Section );
  756. return( Status );
  757. }
  758. Peb = ProcessInfo.PebBaseAddress;
  759. //
  760. // Duplicate Native handles into new process if any specified.
  761. // Note that the duplicated handles will overlay the input values.
  762. //
  763. try {
  764. Status = STATUS_SUCCESS;
  765. if ( ProcessParameters->StandardInput ) {
  766. Status = ZwDuplicateObject(
  767. ParentProcess,
  768. ProcessParameters->StandardInput,
  769. ProcessInformation->Process,
  770. &ProcessParameters->StandardInput,
  771. 0L,
  772. 0L,
  773. DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
  774. );
  775. if ( !NT_SUCCESS(Status) ) {
  776. return Status;
  777. }
  778. }
  779. if ( ProcessParameters->StandardOutput ) {
  780. Status = ZwDuplicateObject(
  781. ParentProcess,
  782. ProcessParameters->StandardOutput,
  783. ProcessInformation->Process,
  784. &ProcessParameters->StandardOutput,
  785. 0L,
  786. 0L,
  787. DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
  788. );
  789. if ( !NT_SUCCESS(Status) ) {
  790. return Status;
  791. }
  792. }
  793. if ( ProcessParameters->StandardError ) {
  794. Status = ZwDuplicateObject(
  795. ParentProcess,
  796. ProcessParameters->StandardError,
  797. ProcessInformation->Process,
  798. &ProcessParameters->StandardError,
  799. 0L,
  800. 0L,
  801. DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
  802. );
  803. if ( !NT_SUCCESS(Status) ) {
  804. return Status;
  805. }
  806. }
  807. } finally {
  808. if ( !NT_SUCCESS(Status) ) {
  809. #if DBG
  810. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. Duplicate Standard I/O Handle Status == %lx\n",
  811. NtImagePathName,
  812. Status
  813. );
  814. #endif // DBG
  815. ZwClose( ProcessInformation->Process );
  816. ZwClose( Section );
  817. }
  818. //
  819. // Possibly reserve some address space in the new process
  820. //
  821. if (ProcessInformation->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE ) {
  822. if ( ProcessParameters->Flags & RTL_USER_PROC_RESERVE_1MB ) {
  823. Environment = (PVOID)4;
  824. RegionSize = (1024*1024)-(256);
  825. Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
  826. (PVOID *)&Environment,
  827. 0,
  828. &RegionSize,
  829. MEM_RESERVE,
  830. PAGE_READWRITE
  831. );
  832. if ( !NT_SUCCESS( Status ) ) {
  833. #if DBG
  834. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtAllocateReserveMemory Status == %X\n",
  835. NtImagePathName,
  836. Status
  837. );
  838. #endif // DBG
  839. ZwClose( ProcessInformation->Process );
  840. ZwClose( Section );
  841. return( Status );
  842. }
  843. }
  844. }
  845. //
  846. // Allocate virtual memory in the new process and use NtWriteVirtualMemory
  847. // to write a copy of the process environment block into the address
  848. // space of the new process. Save the address of the allocated block in
  849. // the process parameter block so the new process can access it.
  850. //
  851. if (s = (PWCHAR)ProcessParameters->Environment) {
  852. while (*s++) {
  853. while (*s++) {
  854. }
  855. }
  856. EnvironmentLength = (s - (PWCHAR)ProcessParameters->Environment) * sizeof(WCHAR);
  857. Environment = NULL;
  858. RegionSize = EnvironmentLength;
  859. Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
  860. (PVOID *)&Environment,
  861. 0,
  862. &RegionSize,
  863. MEM_COMMIT,
  864. PAGE_READWRITE
  865. );
  866. if ( !NT_SUCCESS( Status ) ) {
  867. #if DBG
  868. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtAllocateVirtualMemory Status == %X\n",
  869. NtImagePathName,
  870. Status
  871. );
  872. #endif // DBG
  873. ZwClose( ProcessInformation->Process );
  874. ZwClose( Section );
  875. return( Status );
  876. }
  877. Status = ZwWriteVirtualMemory( ProcessInformation->Process,
  878. Environment,
  879. ProcessParameters->Environment,
  880. EnvironmentLength,
  881. NULL
  882. );
  883. if ( !NT_SUCCESS( Status ) ) {
  884. #if DBG
  885. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtWriteVirtualMemory Status == %X\n",
  886. NtImagePathName,
  887. Status
  888. );
  889. #endif // DBG
  890. ZwClose( ProcessInformation->Process );
  891. ZwClose( Section );
  892. return( Status );
  893. }
  894. ProcessParameters->Environment = Environment;
  895. }
  896. //
  897. // Allocate virtual memory in the new process and use NtWriteVirtualMemory
  898. // to write a copy of the process parameters block into the address
  899. // space of the new process. Set the initial parameter to the new thread
  900. // to be the address of the block in the new process's address space.
  901. //
  902. Parameters = NULL;
  903. ParameterLength = ProcessParameters->MaximumLength;
  904. Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
  905. (PVOID *)&Parameters,
  906. 0,
  907. &ParameterLength,
  908. MEM_COMMIT,
  909. PAGE_READWRITE
  910. );
  911. if ( !NT_SUCCESS( Status ) ) {
  912. #if DBG
  913. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtAllocateVirtualMemory Status == %X\n",
  914. NtImagePathName,
  915. Status
  916. );
  917. #endif // DBG
  918. ZwClose( ProcessInformation->Process );
  919. ZwClose( Section );
  920. return( Status );
  921. }
  922. Status = ZwWriteVirtualMemory( ProcessInformation->Process,
  923. Parameters,
  924. ProcessParameters,
  925. ProcessParameters->Length,
  926. NULL
  927. );
  928. if ( !NT_SUCCESS( Status ) ) {
  929. #if DBG
  930. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtWriteVirtualMemory Status == %X\n",
  931. NtImagePathName,
  932. Status
  933. );
  934. #endif // DBG
  935. ZwClose( ProcessInformation->Process );
  936. ZwClose( Section );
  937. return( Status );
  938. }
  939. }
  940. Status = ZwWriteVirtualMemory( ProcessInformation->Process,
  941. &Peb->ProcessParameters,
  942. &Parameters,
  943. sizeof( Parameters ),
  944. NULL
  945. );
  946. if ( !NT_SUCCESS( Status ) ) {
  947. #if DBG
  948. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. NtWriteVirtualMemory Status == %X\n",
  949. NtImagePathName,
  950. Status
  951. );
  952. #endif // DBG
  953. ZwClose( ProcessInformation->Process );
  954. ZwClose( Section );
  955. return( Status );
  956. }
  957. //
  958. // Create a suspended thread in the new process. Specify the size and
  959. // position of the stack, along with the start address, initial parameter
  960. // and an SECURITY_DESCRIPTOR. The new thread will not have a name and its handle will
  961. // not be inherited by other processes.
  962. //
  963. Status = RtlCreateUserThread(
  964. ProcessInformation->Process,
  965. ThreadSecurityDescriptor,
  966. TRUE,
  967. ProcessInformation->ImageInformation.ZeroBits,
  968. ProcessInformation->ImageInformation.MaximumStackSize,
  969. ProcessInformation->ImageInformation.CommittedStackSize,
  970. (PUSER_THREAD_START_ROUTINE)
  971. ProcessInformation->ImageInformation.TransferAddress,
  972. (PVOID)Peb,
  973. &ProcessInformation->Thread,
  974. &ProcessInformation->ClientId
  975. );
  976. if ( !NT_SUCCESS( Status ) ) {
  977. #if DBG
  978. DbgPrint( "NTRTL: RtlCreateUserProcess( %Z ) failed. RtlCreateUserThread Status == %X\n",
  979. NtImagePathName,
  980. Status
  981. );
  982. #endif // DBG
  983. ZwClose( ProcessInformation->Process );
  984. ZwClose( Section );
  985. return( Status );
  986. }
  987. //
  988. // Now close the section and file handles. The objects they represent
  989. // will not actually go away until the process is destroyed.
  990. //
  991. ZwClose( Section );
  992. //
  993. // Return success status
  994. //
  995. return( STATUS_SUCCESS );
  996. }
  997. NTSTATUS
  998. RtlCreateUserThread(
  999. IN HANDLE Process,
  1000. IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
  1001. IN BOOLEAN CreateSuspended,
  1002. IN ULONG ZeroBits OPTIONAL,
  1003. IN ULONG MaximumStackSize OPTIONAL,
  1004. IN ULONG CommittedStackSize OPTIONAL,
  1005. IN PUSER_THREAD_START_ROUTINE StartAddress,
  1006. IN PVOID Parameter OPTIONAL,
  1007. OUT PHANDLE Thread OPTIONAL,
  1008. OUT PCLIENT_ID ClientId OPTIONAL
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This function creates a user mode thread in a user process. The caller
  1013. specifies the attributes of the new thread. A handle to the thread, along
  1014. with its Client Id are returned to the caller.
  1015. Arguments:
  1016. Process - Handle to the target process in which to create the new thread.
  1017. ThreadSecurityDescriptor - An optional pointer to the Security Descriptor
  1018. give to the new thread.
  1019. CreateSuspended - A boolean parameter that specifies whether or not the new
  1020. thread is to be created suspended or not. If TRUE, the new thread
  1021. will be created with an initial suspend count of 1. If FALSE then
  1022. the new thread will be ready to run when this call returns.
  1023. ZeroBits - This parameter is passed to the virtual memory manager
  1024. when the stack is allocated. Stacks are always allocated with the
  1025. MEM_TOP_DOWN allocation attribute.
  1026. MaximumStackSize - This is the maximum size of the stack. This size
  1027. will be rounded up to the next highest page boundary. If zero is
  1028. specified, then the default size will be 64K bytes.
  1029. CommittedStackSize - This is the initial committed size of the stack. This
  1030. size is rounded up to the next highest page boundary and then an
  1031. additional page is added for the guard page. The resulting size
  1032. will then be commited and the guard page protection initialized
  1033. for the last committed page in the stack.
  1034. StartAddress - The initial starting address of the thread.
  1035. Parameter - An optional pointer to a 32-bit pointer parameter that is
  1036. passed as a single argument to the procedure at the start address
  1037. location.
  1038. Thread - An optional pointer that, if specified, points to a variable that
  1039. will receive the handle of the new thread.
  1040. ClientId - An optional pointer that, if specified, points to a variable
  1041. that will receive the Client Id of the new thread.
  1042. Return Value:
  1043. TBS
  1044. --*/
  1045. {
  1046. NTSTATUS Status;
  1047. CONTEXT ThreadContext;
  1048. OBJECT_ATTRIBUTES ObjectAttributes;
  1049. INITIAL_TEB InitialTeb;
  1050. HANDLE ThreadHandle;
  1051. CLIENT_ID ThreadClientId;
  1052. //
  1053. // Allocate a stack for this thread in the address space of the target
  1054. // process.
  1055. //
  1056. Status = RtlpCreateStack( Process,
  1057. MaximumStackSize,
  1058. CommittedStackSize,
  1059. ZeroBits,
  1060. &InitialTeb
  1061. );
  1062. if ( !NT_SUCCESS( Status ) ) {
  1063. return( Status );
  1064. }
  1065. //
  1066. // Create an initial context for the new thread.
  1067. //
  1068. RtlInitializeContext( Process,
  1069. &ThreadContext,
  1070. Parameter,
  1071. (PVOID)StartAddress,
  1072. InitialTeb.StackBase
  1073. );
  1074. //
  1075. // Now create a thread in the target process. The new thread will
  1076. // not have a name and its handle will not be inherited by other
  1077. // processes.
  1078. //
  1079. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL,
  1080. ThreadSecurityDescriptor );
  1081. Status = ZwCreateThread( &ThreadHandle,
  1082. THREAD_ALL_ACCESS,
  1083. &ObjectAttributes,
  1084. Process,
  1085. &ThreadClientId,
  1086. &ThreadContext,
  1087. &InitialTeb,
  1088. CreateSuspended
  1089. );
  1090. if (!NT_SUCCESS( Status )) {
  1091. #if DBG
  1092. DbgPrint( "NTRTL: RtlCreateUserThread Failed. NtCreateThread Status == %X\n",
  1093. Status );
  1094. #endif // DBG
  1095. RtlpFreeStack( Process, &InitialTeb );
  1096. }
  1097. else {
  1098. if (ARGUMENT_PRESENT( Thread )) {
  1099. *Thread = ThreadHandle;
  1100. }
  1101. if (ARGUMENT_PRESENT( ClientId )) {
  1102. *ClientId = ThreadClientId;
  1103. }
  1104. }
  1105. //
  1106. // Return status
  1107. //
  1108. return( Status );
  1109. }
  1110. VOID
  1111. RtlFreeUserThreadStack(
  1112. HANDLE hProcess,
  1113. HANDLE hThread
  1114. )
  1115. {
  1116. NTSTATUS Status;
  1117. PTEB Teb;
  1118. THREAD_BASIC_INFORMATION ThreadInfo;
  1119. PVOID StackDeallocationBase;
  1120. ULONG Size;
  1121. Status = NtQueryInformationThread( hThread,
  1122. ThreadBasicInformation,
  1123. &ThreadInfo,
  1124. sizeof( ThreadInfo ),
  1125. NULL
  1126. );
  1127. Teb = ThreadInfo.TebBaseAddress;
  1128. if (!NT_SUCCESS( Status ) || !Teb) {
  1129. return;
  1130. }
  1131. Status = NtReadVirtualMemory( hProcess,
  1132. &Teb->DeallocationStack,
  1133. &StackDeallocationBase,
  1134. sizeof( StackDeallocationBase ),
  1135. &Size
  1136. );
  1137. if (!NT_SUCCESS( Status ) || !StackDeallocationBase) {
  1138. return;
  1139. }
  1140. Size = 0;
  1141. NtFreeVirtualMemory( hProcess, &StackDeallocationBase, &Size, MEM_RELEASE );
  1142. return;
  1143. }