/* @implemented */ NTSTATUS NTAPI RtlCreateUserThread(IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG StackZeroBits OPTIONAL, IN SIZE_T StackReserve OPTIONAL, IN SIZE_T StackCommit OPTIONAL, IN PTHREAD_START_ROUTINE StartAddress, IN PVOID Parameter OPTIONAL, OUT PHANDLE ThreadHandle OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL) { NTSTATUS Status; HANDLE Handle; CLIENT_ID ThreadCid; INITIAL_TEB InitialTeb; OBJECT_ATTRIBUTES ObjectAttributes; CONTEXT Context; /* First, we'll create the Stack */ Status = RtlpCreateUserStack(ProcessHandle, StackReserve, StackCommit, StackZeroBits, &InitialTeb); if (!NT_SUCCESS(Status)) return Status; /* Next, we'll set up the Initial Context */ RtlInitializeContext(ProcessHandle, &Context, Parameter, StartAddress, InitialTeb.StackBase); /* We are now ready to create the Kernel Thread Object */ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, SecurityDescriptor); Status = ZwCreateThread(&Handle, THREAD_ALL_ACCESS, &ObjectAttributes, ProcessHandle, &ThreadCid, &Context, &InitialTeb, CreateSuspended); if (!NT_SUCCESS(Status)) { /* Free the stack */ RtlpFreeUserStack(ProcessHandle, &InitialTeb); } else { /* Return thread data */ if (ThreadHandle) *ThreadHandle = Handle; else NtClose(Handle); if (ClientId) *ClientId = ThreadCid; } /* Return success or the previous failure */ return Status; }
NTSTATUS RtlCreateUserThread( IN HANDLE Process, IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG ZeroBits OPTIONAL, IN SIZE_T MaximumStackSize OPTIONAL, IN SIZE_T CommittedStackSize OPTIONAL, IN PUSER_THREAD_START_ROUTINE StartAddress, IN PVOID Parameter OPTIONAL, OUT PHANDLE Thread OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL ) /*++ Routine Description: This function creates a user mode thread in a user process. The caller specifies the attributes of the new thread. A handle to the thread, along with its Client Id are returned to the caller. Arguments: Process - Handle to the target process in which to create the new thread. ThreadSecurityDescriptor - An optional pointer to the Security Descriptor give to the new thread. CreateSuspended - A boolean parameter that specifies whether or not the new thread is to be created suspended or not. If TRUE, the new thread will be created with an initial suspend count of 1. If FALSE then the new thread will be ready to run when this call returns. ZeroBits - This parameter is passed to the virtual memory manager when the stack is allocated. Stacks are always allocated with the MEM_TOP_DOWN allocation attribute. MaximumStackSize - This is the maximum size of the stack. This size will be rounded up to the next highest page boundary. If zero is specified, then the default size will be 64K bytes. CommittedStackSize - This is the initial committed size of the stack. This size is rounded up to the next highest page boundary and then an additional page is added for the guard page. The resulting size will then be commited and the guard page protection initialized for the last committed page in the stack. StartAddress - The initial starting address of the thread. Parameter - An optional pointer to a 32-bit pointer parameter that is passed as a single argument to the procedure at the start address location. Thread - An optional pointer that, if specified, points to a variable that will receive the handle of the new thread. ClientId - An optional pointer that, if specified, points to a variable that will receive the Client Id of the new thread. --*/ { NTSTATUS Status; CONTEXT ThreadContext={0}; OBJECT_ATTRIBUTES ObjectAttributes; INITIAL_TEB InitialTeb; HANDLE ThreadHandle; CLIENT_ID ThreadClientId; // // Allocate a stack for this thread in the address space of the target // process. // Status = RtlpCreateStack( Process, MaximumStackSize, CommittedStackSize, ZeroBits, &InitialTeb ); if ( !NT_SUCCESS( Status ) ) { return( Status ); } // // Create an initial context for the new thread. // try { RtlInitializeContext( Process, &ThreadContext, Parameter, (PVOID)StartAddress, InitialTeb.StackBase ); } except (EXCEPTION_EXECUTE_HANDLER) { RtlpFreeStack( Process, &InitialTeb ); return GetExceptionCode (); } // // Now create a thread in the target process. The new thread will // not have a name and its handle will not be inherited by other // processes. // InitializeObjectAttributes( &ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, ThreadSecurityDescriptor ); Status = ZwCreateThread( &ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, Process, &ThreadClientId, &ThreadContext, &InitialTeb, CreateSuspended ); if (!NT_SUCCESS( Status )) { #if DBG DbgPrint( "NTRTL: RtlCreateUserThread Failed. NtCreateThread Status == %X\n", Status ); #endif // DBG RtlpFreeStack( Process, &InitialTeb ); } else { if (ARGUMENT_PRESENT( Thread )) { *Thread = ThreadHandle; } else { ZwClose (ThreadHandle); } if (ARGUMENT_PRESENT( ClientId )) { *ClientId = ThreadClientId; } } // // Return status // return( Status ); }