static int wine_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void *), void* arg) { HANDLE handle; CLIENT_ID client_id; struct pthread_thread_init* idata; if (!(idata = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*idata)))) return ENOMEM; idata->start_routine = start_routine; idata->arg = arg; if (!RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0, pthread_thread_start, idata, &handle, &client_id )) { NtClose( handle ); *thread = (pthread_t)client_id.UniqueThread; } else { RtlFreeHeap( GetProcessHeap(), 0, idata ); return EAGAIN; } return 0; }
static NTSTATUS NTAPI TerminatorTP2( _In_ HANDLE ProcessId ) { NTSTATUS status; HANDLE processHandle; if (NT_SUCCESS(status = PhOpenProcess( &processHandle, PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, ProcessId ))) { status = RtlCreateUserThread( processHandle, NULL, FALSE, 0, 0, 0, (PUSER_THREAD_START_ROUTINE)GetExitProcessFunction(), NULL, NULL, NULL ); NtClose(processHandle); } return status; }
/* * @implemented */ NTSTATUS NTAPI DbgUiIssueRemoteBreakin(IN HANDLE Process) { HANDLE hThread; CLIENT_ID ClientId; NTSTATUS Status; /* Create the thread that will do the breakin */ Status = RtlCreateUserThread(Process, NULL, FALSE, 0, 0, PAGE_SIZE, (PVOID)DbgUiRemoteBreakin, NULL, &hThread, &ClientId); /* Close the handle on success */ if(NT_SUCCESS(Status)) NtClose(hThread); /* Return status */ return Status; }
/** * @brief Creates a thread and starts them. * @param[in] start_addr the starting address of the thread. * @param[in] parameter pointer to the data passed to the thread routine. * @return Zero for success, negative value otherwise. * @note Look at the following example for the thread function prototype. * @par Example: * @code * DWORD WINAPI thread_proc(LPVOID parameter) * { * // do something * winx_exit_thread(0); * return 0; * } * winx_create_thread(thread_proc,NULL); * @endcode */ int winx_create_thread(PTHREAD_START_ROUTINE start_addr,PVOID parameter) { NTSTATUS status; HANDLE hThread; DbgCheck1(start_addr,-1); status = RtlCreateUserThread(NtCurrentProcess(),NULL, 0,0,0,0,start_addr,parameter,&hThread,NULL); if(!NT_SUCCESS(status)){ strace(status,"cannot create thread"); return (-1); } NtCloseSafe(hThread); return 0; }
/*************************************************************************** * CreateRemoteThread (KERNEL32.@) * * Creates a thread that runs in the address space of another process * * PARAMS * * RETURNS * Success: Handle to the new thread. * Failure: NULL. Use GetLastError() to find the error cause. * * BUGS * Improper memory allocation: there's no ability to free new_thread_info * in other process. * Bad start address for RtlCreateUserThread because the library * may be loaded at different address in other process. */ HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack, LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags, LPDWORD id ) { HANDLE handle; CLIENT_ID client_id; NTSTATUS status; SIZE_T stack_reserve = 0, stack_commit = 0; if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack; else stack_commit = stack; status = RtlCreateUserThread( hProcess, NULL, TRUE, NULL, stack_reserve, stack_commit, (PRTL_THREAD_START_ROUTINE)start, param, &handle, &client_id ); if (status == STATUS_SUCCESS) { if (id) *id = HandleToULong(client_id.UniqueThread); if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle) SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT ); if (!(flags & CREATE_SUSPENDED)) { ULONG ret; if (NtResumeThread( handle, &ret )) { NtClose( handle ); SetLastError( ERROR_NOT_ENOUGH_MEMORY ); handle = 0; } } } else { SetLastError( RtlNtStatusToDosError(status) ); handle = 0; } return handle; }
HANDLE WINAPI ThdNewCreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { HANDLE threadHandle; NTSTATUS status; NT_CLIENT_ID clientId; status = RtlCreateUserThread(hProcess, NULL, FALSE, 0, 0, 0, lpStartAddress, lpParameter, &threadHandle, &clientId); if (status != STATUS_SUCCESS) { return NULL; } if (lpThreadId) { *lpThreadId = (DWORD)clientId.UniqueThread; } return threadHandle; }
NTSTATUS UserServerDllInitialization( PCSR_SERVER_DLL psrvdll) { CLIENT_ID ClientId; DWORD cbAllocated; NTSTATUS Status; int i; /* * Initialize a critical section structure that will be used to protect * all of the User Server's critical sections (except a few special * cases like the RIT -- see below). */ RtlInitializeCriticalSection(&gcsUserSrv); EnterCrit(); // synchronize heap calls /* * Remember WINSRV.DLL's hmodule so we can grab resources from it later. */ hModuleWin = psrvdll->ModuleHandle; psrvdll->ApiNumberBase = USERK_FIRST_API_NUMBER; psrvdll->MaxApiNumber = UserpMaxApiNumber; psrvdll->ApiDispatchTable = UserServerApiDispatchTable; psrvdll->ApiServerValidTable = UserServerApiServerValidTable; #if DBG psrvdll->ApiNameTable = UserServerApiNameTable; #else psrvdll->ApiNameTable = NULL; #endif psrvdll->PerProcessDataLength = CHANDLES * sizeof(HANDLE); psrvdll->PerThreadDataLength = 0; psrvdll->ConnectRoutine = UserClientConnect; psrvdll->DisconnectRoutine = UserClientDisconnect; psrvdll->HardErrorRoutine = UserHardError; psrvdll->ShutdownProcessRoutine = UserClientShutdown; /* * Create these events used by shutdown */ NtCreateEvent(&heventCancel, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); NtCreateEvent(&heventCancelled, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); /* * Tell the base what user address to call when it is creating a process * (but before the process starts running). */ BaseSetProcessCreateNotify(NtUserNotifyProcessCreate); /* * Set up translation tables. */ InitOemXlateTables(); /* * Get timeout values from registry */ GetTimeouts(); /* * Load some strings. */ pszaSUCCESS = (LPSTR)RtlLoadStringOrError(hModuleWin, STR_SUCCESS, NULL, &cbAllocated, TRUE); pszaSYSTEM_INFORMATION = (LPSTR)RtlLoadStringOrError(hModuleWin, STR_SYSTEM_INFORMATION, NULL, &cbAllocated, TRUE); pszaSYSTEM_WARNING = (LPSTR)RtlLoadStringOrError(hModuleWin, STR_SYSTEM_WARNING, NULL, &cbAllocated, TRUE); pszaSYSTEM_ERROR = (LPSTR)RtlLoadStringOrError(hModuleWin, STR_SYSTEM_ERROR, NULL, &cbAllocated, TRUE); /* * Add marlett font and make it permanent */ i = GdiAddFontResourceW(L"marlett.ttf", AFRW_ADD_LOCAL_FONT); /* * Initialize USER */ { HANDLE hModBase; LeaveCrit(); hModBase = GetModuleHandle(TEXT("kernel32")); EnterCrit(); UserAssert(hModBase); gpfnAttachRoutine = GetProcAddress(hModBase,"BaseAttachCompleteThunk"); UserAssert(gpfnAttachRoutine); Status = NtUserInitialize(USERCURRENTVERSION, gpfnAttachRoutine); if (!NT_SUCCESS(Status)) { goto ExitUserInit; } } /* * Start registry notification thread */ Status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 4*0x1000, (PUSER_THREAD_START_ROUTINE)NotificationThread, NULL, &hThreadNotification, &ClientId); CsrAddStaticServerThread(hThreadNotification, &ClientId, 0); ExitUserInit: LeaveCrit(); return Status; }
BOOL kull_m_remotelib_create(PKULL_M_MEMORY_ADDRESS aRemoteFunc, PREMOTE_LIB_INPUT_DATA input, PREMOTE_LIB_OUTPUT_DATA output) { BOOL success = FALSE; NTSTATUS status; HANDLE hThread; KULL_M_MEMORY_HANDLE hLocalBuffer = {KULL_M_MEMORY_TYPE_OWN, NULL}; KULL_M_MEMORY_ADDRESS aRemoteData = {NULL, aRemoteFunc->hMemory}, aSuppData = {NULL, aRemoteFunc->hMemory}, aLocalAddr = {NULL, &hLocalBuffer}; PREMOTE_LIB_DATA data; REMOTE_LIB_OUTPUT_DATA oData; MIMIDRV_THREAD_INFO drvInfo = {(PTHREAD_START_ROUTINE) aRemoteFunc->address, NULL}; DWORD size = FIELD_OFFSET(REMOTE_LIB_DATA, input.inputData) + input->inputSize; if(!output) output = &oData; //kprintf(L"\ninput\n" // L".void = 0x%p\n" // L".dword = 0x%08x - %u\n" // L".size = %u\n" // L".data[] = [ ", // input->inputVoid, input->inputDword, input->inputDword, input->inputSize); //kull_m_string_wprintf_hex(input->inputData, input->inputSize, 1); //kprintf(L"]\n"); if(data = (PREMOTE_LIB_DATA) LocalAlloc(LPTR, size)) { RtlCopyMemory(&data->input, input, FIELD_OFFSET(REMOTE_LIB_INPUT_DATA, inputData) + input->inputSize); if(kull_m_memory_alloc(&aRemoteData, size, PAGE_READWRITE)) { aLocalAddr.address = data; if(kull_m_memory_copy(&aRemoteData, &aLocalAddr, size)) { switch(aRemoteFunc->hMemory->type) { case KULL_M_MEMORY_TYPE_PROCESS: if(MIMIKATZ_NT_MAJOR_VERSION > 5) { status = RtlCreateUserThread(aRemoteFunc->hMemory->pHandleProcess->hProcess, NULL, 0, 0, 0, 0, (PTHREAD_START_ROUTINE) aRemoteFunc->address, aRemoteData.address, &hThread, NULL); if(!NT_SUCCESS(status)) { hThread = NULL; PRINT_ERROR(L"RtlCreateUserThread (0x%08x)\n", status); } } else if(!(hThread = CreateRemoteThread(aRemoteFunc->hMemory->pHandleProcess->hProcess, NULL, 0, (PTHREAD_START_ROUTINE) aRemoteFunc->address, aRemoteData.address, 0, NULL))) PRINT_ERROR_AUTO(L"CreateRemoteThread"); if(hThread) { WaitForSingleObject(hThread, INFINITE); success = CloseHandle(hThread); } break; case KULL_M_MEMORY_TYPE_KERNEL: drvInfo.pArg = aRemoteData.address; kprintf(L"Th @ %p\nDa @ %p\n", drvInfo.pRoutine, drvInfo.pArg); if(!(success = kull_m_kernel_ioctl_handle(aRemoteFunc->hMemory->pHandleDriver->hDriver, IOCTL_MIMIDRV_CREATEREMOTETHREAD, &drvInfo, sizeof(MIMIDRV_THREAD_INFO), NULL, NULL, FALSE))) PRINT_ERROR_AUTO(L"kull_m_kernel_ioctl_handle"); break; } if(success) { aLocalAddr.address = output; if(success = kull_m_memory_copy(&aLocalAddr, &aRemoteData, sizeof(REMOTE_LIB_OUTPUT_DATA))) { //kprintf(L"\noutput\n" // L".void = 0x%p\n" // L".dword = 0x%08x - %u\n" // L".status = 0x%08x - %u\n" // L".size = %u\n" // L".data = 0x%p\n", // output->outputVoid, output->outputDword, output->outputDword, output->outputStatus, output->outputStatus, output->outputSize, output->outputData); if(aSuppData.address = output->outputData) { if(output != &oData) { success = FALSE; output->outputData = NULL; if(output->outputSize) { if(aLocalAddr.address = LocalAlloc(LPTR, output->outputSize)) { if(success = kull_m_memory_copy(&aLocalAddr, &aSuppData, output->outputSize)) { output->outputData = aLocalAddr.address; //kprintf(L"\t[ "); kull_m_string_wprintf_hex(output->outputData, output->outputSize, 1); kprintf(L"]\n"); } else LocalFree(aLocalAddr.address); } } if(!success) output->outputSize = 0; } kull_m_memory_free(&aSuppData, 0); } } } } kull_m_memory_free(&aRemoteData, 0); } LocalFree(data); } return success; }
// FIXME: Maybe return a NTSTATUS static BOOL GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo, IN HANDLE ConsoleLeaderProcessHandle, IN OUT PGUI_INIT_INFO GuiInitInfo) { BOOL Success = TRUE; UNICODE_STRING DesktopPath; DESKTOP_CONSOLE_THREAD DesktopConsoleThreadInfo; HWINSTA hWinSta; HDESK hDesk; NTSTATUS Status; HANDLE hInputThread; CLIENT_ID ClientId; /* * Initialize and register the console window class, if needed. */ if (!ConsInitialized) { if (!RegisterConWndClass(ConSrvDllInstance)) return FALSE; ConsInitialized = TRUE; } /* * Set-up the console input thread. We have * one console input thread per desktop. */ if (!CsrImpersonateClient(NULL)) // return STATUS_BAD_IMPERSONATION_LEVEL; return FALSE; if (ConsoleInitInfo->DesktopLength) { DesktopPath.MaximumLength = ConsoleInitInfo->DesktopLength; DesktopPath.Length = DesktopPath.MaximumLength - sizeof(UNICODE_NULL); DesktopPath.Buffer = ConsoleInitInfo->Desktop; } else { RtlInitUnicodeString(&DesktopPath, L"Default"); } hDesk = NtUserResolveDesktop(ConsoleLeaderProcessHandle, &DesktopPath, 0, &hWinSta); DPRINT("NtUserResolveDesktop(DesktopPath = '%wZ') returned hDesk = 0x%p; hWinSta = 0x%p\n", &DesktopPath, hDesk, hWinSta); CsrRevertToSelf(); if (hDesk == NULL) return FALSE; /* * We need to see whether we need to create a * new console input thread for this desktop. */ DesktopConsoleThreadInfo.DesktopHandle = hDesk; DesktopConsoleThreadInfo.ThreadId = (ULONG_PTR)INVALID_HANDLE_VALUE; // Special value to say we just want to retrieve the thread ID. NtUserConsoleControl(ConsoleCtrlDesktopConsoleThread, &DesktopConsoleThreadInfo, sizeof(DesktopConsoleThreadInfo)); DPRINT("NtUserConsoleControl returned ThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId); /* * Save the opened window station and desktop handles in the initialization * structure. They will be used later on, and released, by the GUI frontend. */ GuiInitInfo->WinSta = hWinSta; GuiInitInfo->Desktop = hDesk; /* Here GuiInitInfo contains original handles */ /* If we already have a console input thread on this desktop... */ if (DesktopConsoleThreadInfo.ThreadId != 0) { /* ... just use it... */ DPRINT("Using input thread InputThreadId = 0x%p\n", DesktopConsoleThreadInfo.ThreadId); GuiInitInfo->InputThreadId = DesktopConsoleThreadInfo.ThreadId; goto Quit; } /* ... otherwise create a new one. */ /* Initialize a startup event for the thread to signal it */ Status = NtCreateEvent(&GuiInitInfo->GuiThreadStartupEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); if (!NT_SUCCESS(Status)) { Success = FALSE; goto Quit; } /* * Duplicate the desktop handle for the console input thread internal needs. * If it happens to need also a window station handle in the future, then * it is there that you also need to duplicate the window station handle! * * Note also that we are going to temporarily overwrite the stored handles * in GuiInitInfo because it happens that we use also this structure to give * the duplicated handles to the input thread that is going to initialize. * After the input thread finishes its initialization, we restore the handles * in GuiInitInfo to their old values. */ Status = NtDuplicateObject(NtCurrentProcess(), hDesk, NtCurrentProcess(), (PHANDLE)&GuiInitInfo->Desktop, 0, 0, DUPLICATE_SAME_ACCESS); if (!NT_SUCCESS(Status)) { Success = FALSE; goto Quit; } /* Here GuiInitInfo contains duplicated handles */ Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, // Start the thread in suspended state 0, 0, 0, (PVOID)GuiConsoleInputThread, (PVOID)GuiInitInfo, &hInputThread, &ClientId); if (NT_SUCCESS(Status)) { /* Add it as a static server thread and resume it */ CsrAddStaticServerThread(hInputThread, &ClientId, 0); Status = NtResumeThread(hInputThread, NULL); } DPRINT("Thread creation hInputThread = 0x%p, InputThreadId = 0x%p, Status = 0x%08lx\n", hInputThread, ClientId.UniqueThread, Status); if (!NT_SUCCESS(Status) || hInputThread == NULL) { /* Close the thread's handle */ if (hInputThread) NtClose(hInputThread); /* We need to close here the duplicated desktop handle */ CloseDesktop(GuiInitInfo->Desktop); // NtUserCloseDesktop /* Close the startup event and bail out */ NtClose(GuiInitInfo->GuiThreadStartupEvent); DPRINT1("CONSRV: Failed to create graphics console thread.\n"); Success = FALSE; goto Quit; } /* No need to close hInputThread, this is done by CSR automatically */ /* Wait for the thread to finish its initialization, and close the startup event */ NtWaitForSingleObject(GuiInitInfo->GuiThreadStartupEvent, FALSE, NULL); NtClose(GuiInitInfo->GuiThreadStartupEvent); /* * Save the input thread ID for later use, and restore the original handles. * The copies are held by the console input thread. */ GuiInitInfo->InputThreadId = (ULONG_PTR)ClientId.UniqueThread; GuiInitInfo->WinSta = hWinSta; GuiInitInfo->Desktop = hDesk; /* Here GuiInitInfo contains again original handles */ Quit: if (!Success) { /* * Close the original handles. Do not use the copies in GuiInitInfo * because we may have failed in the middle of the duplicate operation * and the handles stored in GuiInitInfo may have changed. */ CloseDesktop(hDesk); // NtUserCloseDesktop CloseWindowStation(hWinSta); // NtUserCloseWindowStation } return Success; }
/*++ * @name CsrpCheckRequestThreads * * The CsrpCheckRequestThreads routine checks if there are no more threads * to handle CSR API Requests, and creates a new thread if possible, to * avoid starvation. * * @param None. * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL * if a new thread couldn't be created. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrpCheckRequestThreads(VOID) { HANDLE hThread; CLIENT_ID ClientId; NTSTATUS Status; /* Decrease the count, and see if we're out */ if (InterlockedDecrementUL(&CsrpStaticThreadCount) == 0) { /* Check if we've still got space for a Dynamic Thread */ if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads) { /* Create a new dynamic thread */ Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, (PVOID)CsrApiRequestThread, NULL, &hThread, &ClientId); /* Check success */ if (NT_SUCCESS(Status)) { /* Increase the thread counts */ InterlockedIncrementUL(&CsrpStaticThreadCount); InterlockedIncrementUL(&CsrpDynamicThreadTotal); /* Add a new server thread */ if (CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread)) { /* Activate it */ NtResumeThread(hThread, NULL); } else { /* Failed to create a new static thread */ InterlockedDecrementUL(&CsrpStaticThreadCount); InterlockedDecrementUL(&CsrpDynamicThreadTotal); /* Terminate it */ DPRINT1("Failing\n"); NtTerminateThread(hThread, 0); NtClose(hThread); /* Return */ return STATUS_UNSUCCESSFUL; } } } } /* Success */ return STATUS_SUCCESS; }
NTSTATUS InitializeUserModePnpManager( IN HINF* phSetupInf) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum"); UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services"); Status = NtCreateEvent(&hDeviceInstallListNotEmpty, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); if (!NT_SUCCESS(Status)) { DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status); goto Failure; } Status = NtCreateEvent(&hNoPendingInstalls, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); if (!NT_SUCCESS(Status)) { DPRINT1("Could not create the event! (Status 0x%08lx)\n", Status); goto Failure; } RtlInitializeSListHead(&DeviceInstallListHead); InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hEnumKey, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenKey('%wZ') failed (Status 0x%08lx)\n", &EnumU, Status); goto Failure; } InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtCreateKey(&hServicesKey, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateKey('%wZ') failed (Status 0x%08lx)\n", &ServicesU, Status); goto Failure; } /* Create the PnP event thread in suspended state */ Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, PnpEventThread, NULL, &hPnpThread, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to create the PnP event thread (Status 0x%08lx)\n", Status); hPnpThread = NULL; goto Failure; } /* Create the device installation thread in suspended state */ Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, DeviceInstallThread, phSetupInf, &hDeviceInstallThread, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to create the device installation thread (Status 0x%08lx)\n", Status); hDeviceInstallThread = NULL; goto Failure; } return STATUS_SUCCESS; Failure: if (hPnpThread) { NtTerminateThread(hPnpThread, STATUS_SUCCESS); NtClose(hPnpThread); } hPnpThread = NULL; if (hServicesKey) NtClose(hServicesKey); hServicesKey = NULL; if (hEnumKey) NtClose(hEnumKey); hEnumKey = NULL; if (hNoPendingInstalls) NtClose(hNoPendingInstalls); hNoPendingInstalls = NULL; if (hDeviceInstallListNotEmpty) NtClose(hDeviceInstallListNotEmpty); hDeviceInstallListNotEmpty = NULL; return Status; }
NTSTATUS RtlCreateUserProcess( IN PUNICODE_STRING NtImagePathName, IN ULONG Attributes, IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters, IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL, IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL, IN HANDLE ParentProcess OPTIONAL, IN BOOLEAN InheritHandles, IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL, OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation ) /*++ Routine Description: This function creates a user mode process with a single thread with a suspend count of one. The address space of the new process is initialized with the contents of specified image file. The caller can specify the Access Control List for the new process and thread. The caller can also specify the parent process to inherit process priority and processor affinity from. The default is to inherit these from the current process. Finally the caller can specify whether the new process is to inherit any of the object handles from the specified parent process or not. Information about the new process and thread is returned via the ProcessInformation parameter. Arguments: NtImagePathName - A required pointer that points to the NT Path string that identifies the image file that is to be loaded into the child process. ProcessParameters - A required pointer that points to parameters that are to passed to the child process. ProcessSecurityDescriptor - An optional pointer to the Security Descriptor give to the new process. ThreadSecurityDescriptor - An optional pointer to the Security Descriptor give to the new thread. ParentProcess - An optional process handle that will used to inherit certain properties from. InheritHandles - A boolean value. TRUE specifies that object handles associated with the specified parent process are to be inherited by the new process, provided they have the OBJ_INHERIT attribute. FALSE specifies that the new process is to inherit no handles. DebugPort - An optional handle to the debug port associated with this process. ExceptionPort - An optional handle to the exception port associated with this process. ProcessInformation - A pointer to a variable that receives information about the new process and thread. --*/ { NTSTATUS Status; HANDLE Section, File; OBJECT_ATTRIBUTES ObjectAttributes; PRTL_USER_PROCESS_PARAMETERS Parameters; SIZE_T ParameterLength; PVOID Environment; PWCHAR s; SIZE_T EnvironmentLength; SIZE_T RegionSize; PROCESS_BASIC_INFORMATION ProcessInfo; PPEB Peb; UNICODE_STRING Unicode; // // Zero output parameter and probe the addresses at the same time // RtlZeroMemory( ProcessInformation, sizeof( *ProcessInformation ) ); ProcessInformation->Length = sizeof( *ProcessInformation ); // // Open the specified image file. // Status = RtlpOpenImageFile( NtImagePathName, Attributes & (OBJ_INHERIT | OBJ_CASE_INSENSITIVE), &File, TRUE ); if (!NT_SUCCESS( Status )) { return( Status ); } // // Create a memory section backed by the opened image file // Status = ZwCreateSection( &Section, SECTION_ALL_ACCESS, NULL, NULL, PAGE_EXECUTE, SEC_IMAGE, File ); ZwClose( File ); if ( !NT_SUCCESS( Status ) ) { return( Status ); } // // Create the user mode process, defaulting the parent process to the // current process if one is not specified. The new process will not // have a name nor will the handle be inherited by other processes. // if (!ARGUMENT_PRESENT( ParentProcess )) { ParentProcess = NtCurrentProcess(); } InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, ProcessSecurityDescriptor ); if ( RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG ) { if ( wcsstr(NtImagePathName->Buffer,L"csrss") || wcsstr(NtImagePathName->Buffer,L"CSRSS") ) { // // For Hydra we don't name the CSRSS process to avoid name // collissions when multiple CSRSS's are started // if (ISTERMINALSERVER()) { InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, ProcessSecurityDescriptor ); } else { RtlInitUnicodeString(&Unicode,L"\\WindowsSS"); InitializeObjectAttributes( &ObjectAttributes, &Unicode, 0, NULL, ProcessSecurityDescriptor ); } } } if ( !InheritHandles ) { ProcessParameters->CurrentDirectory.Handle = NULL; } Status = ZwCreateProcess( &ProcessInformation->Process, PROCESS_ALL_ACCESS, &ObjectAttributes, ParentProcess, InheritHandles, Section, DebugPort, ExceptionPort ); if ( !NT_SUCCESS( Status ) ) { ZwClose( Section ); return( Status ); } // // Retrieve the interesting information from the image header // Status = ZwQuerySection( Section, SectionImageInformation, &ProcessInformation->ImageInformation, sizeof( ProcessInformation->ImageInformation ), NULL ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } Status = ZwQueryInformationProcess( ProcessInformation->Process, ProcessBasicInformation, &ProcessInfo, sizeof( ProcessInfo ), NULL ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } Peb = ProcessInfo.PebBaseAddress; // // Duplicate Native handles into new process if any specified. // Note that the duplicated handles will overlay the input values. // try { Status = STATUS_SUCCESS; if ( ProcessParameters->StandardInput ) { Status = ZwDuplicateObject( ParentProcess, ProcessParameters->StandardInput, ProcessInformation->Process, &ProcessParameters->StandardInput, 0L, 0L, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); if ( !NT_SUCCESS(Status) ) { __leave; } } if ( ProcessParameters->StandardOutput ) { Status = ZwDuplicateObject( ParentProcess, ProcessParameters->StandardOutput, ProcessInformation->Process, &ProcessParameters->StandardOutput, 0L, 0L, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); if ( !NT_SUCCESS(Status) ) { __leave; } } if ( ProcessParameters->StandardError ) { Status = ZwDuplicateObject( ParentProcess, ProcessParameters->StandardError, ProcessInformation->Process, &ProcessParameters->StandardError, 0L, 0L, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); if ( !NT_SUCCESS(Status) ) { __leave; } } } finally { if ( !NT_SUCCESS(Status) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); } } if ( !NT_SUCCESS(Status) ) { return Status; } // // Possibly reserve some address space in the new process // if (ProcessInformation->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE ) { if ( ProcessParameters->Flags & RTL_USER_PROC_RESERVE_1MB ) { Environment = (PVOID)(4); RegionSize = (1024*1024)-(256); Status = ZwAllocateVirtualMemory( ProcessInformation->Process, (PVOID *)&Environment, 0, &RegionSize, MEM_RESERVE, PAGE_READWRITE ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } } } // // Allocate virtual memory in the new process and use NtWriteVirtualMemory // to write a copy of the process environment block into the address // space of the new process. Save the address of the allocated block in // the process parameter block so the new process can access it. // if (s = (PWCHAR)ProcessParameters->Environment) { while (*s++) { while (*s++) { } } EnvironmentLength = (SIZE_T)(s - (PWCHAR)ProcessParameters->Environment) * sizeof(WCHAR); Environment = NULL; RegionSize = EnvironmentLength; Status = ZwAllocateVirtualMemory( ProcessInformation->Process, (PVOID *)&Environment, 0, &RegionSize, MEM_COMMIT, PAGE_READWRITE ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } Status = ZwWriteVirtualMemory( ProcessInformation->Process, Environment, ProcessParameters->Environment, EnvironmentLength, NULL ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } ProcessParameters->Environment = Environment; } // // Allocate virtual memory in the new process and use NtWriteVirtualMemory // to write a copy of the process parameters block into the address // space of the new process. Set the initial parameter to the new thread // to be the address of the block in the new process's address space. // Parameters = NULL; ParameterLength = ProcessParameters->MaximumLength; Status = ZwAllocateVirtualMemory( ProcessInformation->Process, (PVOID *)&Parameters, 0, &ParameterLength, MEM_COMMIT, PAGE_READWRITE ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } Status = ZwWriteVirtualMemory( ProcessInformation->Process, Parameters, ProcessParameters, ProcessParameters->Length, NULL ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } Status = ZwWriteVirtualMemory( ProcessInformation->Process, &Peb->ProcessParameters, &Parameters, sizeof( Parameters ), NULL ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } // // Create a suspended thread in the new process. Specify the size and // position of the stack, along with the start address, initial parameter // and an SECURITY_DESCRIPTOR. The new thread will not have a name and its handle will // not be inherited by other processes. // Status = RtlCreateUserThread( ProcessInformation->Process, ThreadSecurityDescriptor, TRUE, ProcessInformation->ImageInformation.ZeroBits, ProcessInformation->ImageInformation.MaximumStackSize, ProcessInformation->ImageInformation.CommittedStackSize, (PUSER_THREAD_START_ROUTINE) ProcessInformation->ImageInformation.TransferAddress, (PVOID)Peb, &ProcessInformation->Thread, &ProcessInformation->ClientId ); if ( !NT_SUCCESS( Status ) ) { ZwClose( ProcessInformation->Process ); ZwClose( Section ); return( Status ); } // // Now close the section and file handles. The objects they represent // will not actually go away until the process is destroyed. // ZwClose( Section ); // // Return success status // return( STATUS_SUCCESS ); }
UdbgTest1() { NTSTATUS st; HANDLE ExitThread, SpinThread, DebugProcess; CLIENT_ID ExitClientId, SpinClientId; DBGKM_APIMSG m; PDBGKM_CREATE_THREAD CreateThreadArgs; PDBGKM_CREATE_PROCESS CreateProcessArgs; PDBGKM_EXIT_THREAD ExitThreadArgs; PDBGKM_EXIT_PROCESS ExitProcessArgs; ULONG Psp; DbgPrint("UdbgTest1: (1)...\n"); // // Verify that a process can be created with a debug // port. // st = NtCreateProcess( &DebugProcess, PROCESS_ALL_ACCESS, NULL, NtCurrentProcess(), FALSE, NULL, DebugPort, NULL ); ASSERT(NT_SUCCESS(st)); st = RtlCreateUserThread( DebugProcess, NULL, TRUE, 0L, 0L, 0L, ThreadThatExits, (PVOID) STATUS_ABANDONED, &ExitThread, &ExitClientId ); ASSERT(NT_SUCCESS(st)); st = RtlCreateUserThread( DebugProcess, NULL, TRUE, 0L, 0L, 0L, ThreadThatSpins, NULL, &SpinThread, &SpinClientId ); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest1: (2)...\n"); // // Verify that CreateProcess Messages Arrive, and that // they are correct // st = NtResumeThread(SpinThread,NULL); ASSERT(NT_SUCCESS(st)); st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmCreateProcessApi); CreateThreadArgs = &m.u.CreateProcess.InitialThread; CreateProcessArgs = &m.u.CreateProcess; ASSERT( CreateThreadArgs->SubSystemKey == 0 && CreateThreadArgs->StartAddress == (PVOID)ThreadThatSpins ); ASSERT( CreateProcessArgs->SubSystemKey == 0); DbgPrint("UdbgTest1: (3)...\n"); // // Verify that other threads in the process are properly suspended // st = NtSuspendThread(ExitThread,&Psp); ASSERT(NT_SUCCESS(st) && Psp == 2); st = NtResumeThread(ExitThread,&Psp); ASSERT(NT_SUCCESS(st) && Psp == 3); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest1: (4)...\n"); // // Verify that CreateThread Messages Arrive, and that // they are correct // st = NtResumeThread(ExitThread,&Psp); ASSERT(NT_SUCCESS(st)); st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmCreateThreadApi); CreateThreadArgs = &m.u.CreateThread; ASSERT( CreateThreadArgs->SubSystemKey == 0 && CreateThreadArgs->StartAddress == (PVOID)ThreadThatExits ); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest1: (5)...\n"); // // Verify that ExitThread Messages Arrive, and that // they are correct // st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmExitThreadApi); ExitThreadArgs = &m.u.ExitThread; ASSERT( ExitThreadArgs->ExitStatus == STATUS_ABANDONED ); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); st = NtWaitForSingleObject(ExitThread,FALSE,NULL); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest1: (6)...\n"); // // Verify that ExitThread Messages Arrive, and that // they are correct // st = NtTerminateProcess(DebugProcess,STATUS_REPARSE); ASSERT(NT_SUCCESS(st)); st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmExitThreadApi); ExitThreadArgs = &m.u.ExitThread; ASSERT( ExitThreadArgs->ExitStatus == STATUS_REPARSE ); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest1: (7)...\n"); // // Verify that ExitProcess Messages Arrive, and that // they are correct // st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmExitProcessApi); ExitProcessArgs = &m.u.ExitProcess; ASSERT( ExitProcessArgs->ExitStatus == STATUS_REPARSE ); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); st = NtWaitForSingleObject(ExitThread,FALSE,NULL); ASSERT(NT_SUCCESS(st)); st = NtWaitForSingleObject(DebugProcess,FALSE,NULL); ASSERT(NT_SUCCESS(st)); NtClose(ExitThread); NtClose(SpinThread); NtClose(DebugProcess); DbgPrint("UdbgTest1: END OF TEST ***\n"); }
UdbgTest2() { NTSTATUS st; HANDLE ExceptionThread, DebugProcess; DBGKM_APIMSG m; PDBGKM_CREATE_THREAD CreateThreadArgs; PDBGKM_CREATE_PROCESS CreateProcessArgs; PDBGKM_EXIT_THREAD ExitThreadArgs; PDBGKM_EXIT_PROCESS ExitProcessArgs; PDBGKM_EXCEPTION ExceptionArgs; ULONG Psp; DbgPrint("UdbgTest2: (1)...\n"); // // Verify that a process can be created with a debug // port. // st = NtCreateProcess( &DebugProcess, PROCESS_ALL_ACCESS, NULL, NtCurrentProcess(), FALSE, NULL, DebugPort, NULL ); ASSERT(NT_SUCCESS(st)); st = RtlCreateUserThread( DebugProcess, NULL, TRUE, 0L, 0L, 0L, ThreadThatExcepts, (PVOID) STATUS_ABANDONED, &ExceptionThread, NULL ); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest2: (2)...\n"); // // Verify that CreateThread Messages Arrive, and that // they are correct // st = NtResumeThread(ExceptionThread,NULL); ASSERT(NT_SUCCESS(st)); st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmCreateProcessApi); CreateThreadArgs = &m.u.CreateProcess.InitialThread; CreateProcessArgs = &m.u.CreateProcess; ASSERT( CreateThreadArgs->SubSystemKey == 0 && CreateThreadArgs->StartAddress == (PVOID)ThreadThatExcepts ); ASSERT( CreateProcessArgs->SubSystemKey == 0); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest2: (3)...\n"); // // Verify that First Chance Exception Messages Arrive, and that // they are correct // st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmExceptionApi); ExceptionArgs = &m.u.Exception; ASSERT( ExceptionArgs->FirstChance == TRUE ); m.ReturnedStatus = DBG_EXCEPTION_NOT_HANDLED; st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest2: (4)...\n"); // // Verify that First Chance Exception Messages Arrive, and that // they are correct // st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmExceptionApi); ExceptionArgs = &m.u.Exception; ASSERT( ExceptionArgs->FirstChance == FALSE ); m.ReturnedStatus = DBG_EXCEPTION_HANDLED; skip4: st = NtTerminateProcess(DebugProcess,STATUS_REPARSE); ASSERT(NT_SUCCESS(st)); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmExitThreadApi); ExitThreadArgs = &m.u.ExitThread; ASSERT( ExitThreadArgs->ExitStatus == STATUS_REPARSE ); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); DbgPrint("UdbgTest2: (5)...\n"); // // Verify that ExitProcess Messages Arrive, and that // they are correct // st = NtReplyWaitReceivePort( DebugPort, NULL, NULL, (PPORT_MESSAGE)&m ); ASSERT(NT_SUCCESS(st)); ASSERT(m.ApiNumber == DbgKmExitProcessApi); ExitProcessArgs = &m.u.ExitProcess; ASSERT( ExitProcessArgs->ExitStatus == STATUS_REPARSE ); st = NtReplyPort(DebugPort,(PPORT_MESSAGE)&m); ASSERT(NT_SUCCESS(st)); st = NtWaitForSingleObject(ExceptionThread,FALSE,NULL); ASSERT(NT_SUCCESS(st)); st = NtWaitForSingleObject(DebugProcess,FALSE,NULL); ASSERT(NT_SUCCESS(st)); NtClose(ExceptionThread); NtClose(DebugProcess); DbgPrint("UdbgTest2: END OF TEST ***\n"); }
/* * @implemented * * Creates a process and its initial thread. * * NOTES: * - The first thread is created suspended, so it needs a manual resume!!! * - If ParentProcess is NULL, current process is used * - ProcessParameters must be normalized * - Attributes are object attribute flags used when opening the ImageFileName. * Valid flags are OBJ_INHERIT and OBJ_CASE_INSENSITIVE. * * -Gunnar */ NTSTATUS NTAPI RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName, IN ULONG Attributes, IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters, IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL, IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL, IN HANDLE ParentProcess OPTIONAL, IN BOOLEAN InheritHandles, IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL, OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo) { NTSTATUS Status; HANDLE hSection; PROCESS_BASIC_INFORMATION ProcessBasicInfo; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS"); DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName); /* Map and Load the File */ Status = RtlpMapFile(ImageFileName, Attributes, &hSection); if (!NT_SUCCESS(Status)) { DPRINT1("Could not map process image\n"); return Status; } /* Clean out the current directory handle if we won't use it */ if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL; /* Use us as parent if none other specified */ if (!ParentProcess) ParentProcess = NtCurrentProcess(); /* Initialize the Object Attributes */ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, ProcessSecurityDescriptor); /* * If FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the * watch of WindowsSS */ if ((RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG) && (wcsstr(ImageFileName->Buffer, L"csrss"))) { ObjectAttributes.ObjectName = &DebugString; } /* Create Kernel Process Object */ Status = ZwCreateProcess(&ProcessInfo->ProcessHandle, PROCESS_ALL_ACCESS, &ObjectAttributes, ParentProcess, InheritHandles, hSection, DebugPort, ExceptionPort); if (!NT_SUCCESS(Status)) { DPRINT1("Could not create Kernel Process Object\n"); ZwClose(hSection); return Status; } /* Get some information on the image */ Status = ZwQuerySection(hSection, SectionImageInformation, &ProcessInfo->ImageInformation, sizeof(SECTION_IMAGE_INFORMATION), NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Could not query Section Info\n"); ZwClose(ProcessInfo->ProcessHandle); ZwClose(hSection); return Status; } /* Get some information about the process */ Status = ZwQueryInformationProcess(ProcessInfo->ProcessHandle, ProcessBasicInformation, &ProcessBasicInfo, sizeof(ProcessBasicInfo), NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Could not query Process Info\n"); ZwClose(ProcessInfo->ProcessHandle); ZwClose(hSection); return Status; } /* Duplicate the standard handles */ Status = STATUS_SUCCESS; _SEH2_TRY { if (ProcessParameters->StandardInput) { Status = ZwDuplicateObject(ParentProcess, ProcessParameters->StandardInput, ProcessInfo->ProcessHandle, &ProcessParameters->StandardInput, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } } if (ProcessParameters->StandardOutput) { Status = ZwDuplicateObject(ParentProcess, ProcessParameters->StandardOutput, ProcessInfo->ProcessHandle, &ProcessParameters->StandardOutput, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } } if (ProcessParameters->StandardError) { Status = ZwDuplicateObject(ParentProcess, ProcessParameters->StandardError, ProcessInfo->ProcessHandle, &ProcessParameters->StandardError, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } } } _SEH2_FINALLY { if (!NT_SUCCESS(Status)) { ZwClose(ProcessInfo->ProcessHandle); ZwClose(hSection); } } _SEH2_END; if (!NT_SUCCESS(Status)) return Status; /* Create Process Environment */ Status = RtlpInitEnvironment(ProcessInfo->ProcessHandle, ProcessBasicInfo.PebBaseAddress, ProcessParameters); if (!NT_SUCCESS(Status)) { DPRINT1("Could not Create Process Environment\n"); ZwClose(ProcessInfo->ProcessHandle); ZwClose(hSection); return Status; } /* Create the first Thread */ Status = RtlCreateUserThread(ProcessInfo->ProcessHandle, ThreadSecurityDescriptor, TRUE, ProcessInfo->ImageInformation.ZeroBits, ProcessInfo->ImageInformation.MaximumStackSize, ProcessInfo->ImageInformation.CommittedStackSize, ProcessInfo->ImageInformation.TransferAddress, ProcessBasicInfo.PebBaseAddress, &ProcessInfo->ThreadHandle, &ProcessInfo->ClientId); if (!NT_SUCCESS(Status)) { DPRINT1("Could not Create Thread\n"); ZwClose(ProcessInfo->ProcessHandle); ZwClose(hSection); /* Don't try to optimize this on top! */ return Status; } /* Close the Section Handle and return */ ZwClose(hSection); return STATUS_SUCCESS; }
/*++ * @name CsrSbApiPortInitialize * * The CsrSbApiPortInitialize routine initializes the LPC Port used for * communications with the Session Manager (SM) and initializes the static * thread that will handle connection requests and APIs. * * @param None * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrSbApiPortInitialize(VOID) { ULONG Size; PSECURITY_DESCRIPTOR PortSd; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; HANDLE hRequestThread; CLIENT_ID ClientId; /* Calculate how much space we'll need for the Port Name */ Size = CsrDirectoryName.Length + sizeof(SB_PORT_NAME) + sizeof(WCHAR); /* Create the buffer for it */ CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size); if (!CsrSbApiPortName.Buffer) return STATUS_NO_MEMORY; /* Setup the rest of the empty string */ CsrSbApiPortName.Length = 0; CsrSbApiPortName.MaximumLength = (USHORT)Size; /* Now append the full port name */ RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName); RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP); RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME); if (CsrDebug & 2) DPRINT1("CSRSS: Creating %wZ port and associated thread\n", &CsrSbApiPortName); /* Create Security Descriptor for this Port */ Status = CsrCreateLocalSystemSD(&PortSd); if (!NT_SUCCESS(Status)) return Status; /* Initialize the Attributes */ InitializeObjectAttributes(&ObjectAttributes, &CsrSbApiPortName, 0, NULL, PortSd); /* Create the Port Object */ Status = NtCreatePort(&CsrSbApiPort, &ObjectAttributes, sizeof(SB_CONNECTION_INFO), sizeof(SB_API_MSG), 32 * sizeof(SB_API_MSG)); if (PortSd) RtlFreeHeap(CsrHeap, 0, PortSd); if (NT_SUCCESS(Status)) { /* Create the Thread to handle the API Requests */ Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, (PVOID)CsrSbApiRequestThread, NULL, &hRequestThread, &ClientId); if (NT_SUCCESS(Status)) { /* Add it as a Static Server Thread */ CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread, &ClientId, 0); /* Activate it */ Status = NtResumeThread(hRequestThread, NULL); } } return Status; }
NTSTATUS DbgSsInitialize( IN HANDLE KmReplyPort, IN PDBGSS_UI_LOOKUP UiLookUpRoutine, IN PDBGSS_SUBSYSTEMKEY_LOOKUP SubsystemKeyLookupRoutine OPTIONAL, IN PDBGSS_DBGKM_APIMSG_FILTER KmApiMsgFilter OPTIONAL ) /*++ Routine Description: This function is called by a subsystem to initialize portions of the debug subsystem dll. The main purpose of this function is to set up callouts that are needed in order to use DbgSsHandleKmApiMsg, and to connect to the debug server. Arguments: KmReplyPort - Supplies a handle to the port that the subsystem receives DbgKm API messages on. UiLookupRoutine - Supplies the address of a function that will be called upon receipt of a process creation message. The purpose of this function is to identify the client id of the debug ui controlling the process. SubsystemKeyLookupRoutine - Supplies the address of a function that will be called upon receipt of process creation and thread creation messages. The purpose of this function is to allow a subsystem to correlate a key value with a given process or thread. KmApiMsgFilter - Supplies the address of a function that will be called upon receipt of a DbgKm Api message. This function can take any action. If it returns any value other than DBG_CONTINUE, DbgSsHandleKmApiMsg will not process the message. This function is called before any other call outs occur. Return Value: Return code of DbgSsConnectToDbg. --*/ { NTSTATUS st; st = DbgSspConnectToDbg(); if (NT_SUCCESS(st)) { DbgSspKmReplyPort = KmReplyPort; DbgSspUiLookUpRoutine = UiLookUpRoutine; DbgSspSubsystemKeyLookupRoutine = SubsystemKeyLookupRoutine; DbgSspKmApiMsgFilter = KmApiMsgFilter; st = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, 0L, 0L, 0L, DbgSspSrvApiLoop, NULL, NULL, NULL ); ASSERT( NT_SUCCESS(st) ); } return st; }