mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 06:22:58 +00:00
494 lines
13 KiB
C
494 lines
13 KiB
C
/* $Id: create.c,v 1.24 2000/03/18 19:55:53 ekohl Exp $
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/kernel32/proc/proc.c
|
|
* PURPOSE: Process functions
|
|
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
|
|
* UPDATE HISTORY:
|
|
* Created 01/11/98
|
|
*/
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
#include <ddk/ntddk.h>
|
|
#include <windows.h>
|
|
#include <kernel32/proc.h>
|
|
#include <kernel32/thread.h>
|
|
#include <wchar.h>
|
|
#include <string.h>
|
|
#include <internal/i386/segment.h>
|
|
#include <ntdll/ldr.h>
|
|
#include <internal/teb.h>
|
|
#include <ntdll/base.h>
|
|
#include <ntdll/rtl.h>
|
|
|
|
#define NDEBUG
|
|
#include <kernel32/kernel32.h>
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
WINBOOL
|
|
STDCALL
|
|
CreateProcessA (
|
|
LPCSTR lpApplicationName,
|
|
LPSTR lpCommandLine,
|
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
WINBOOL bInheritHandles,
|
|
DWORD dwCreationFlags,
|
|
LPVOID lpEnvironment,
|
|
LPCSTR lpCurrentDirectory,
|
|
LPSTARTUPINFOA lpStartupInfo,
|
|
LPPROCESS_INFORMATION lpProcessInformation
|
|
)
|
|
/*
|
|
* FUNCTION: The CreateProcess function creates a new process and its
|
|
* primary thread. The new process executes the specified executable file
|
|
* ARGUMENTS:
|
|
*
|
|
* lpApplicationName = Pointer to name of executable module
|
|
* lpCommandLine = Pointer to command line string
|
|
* lpProcessAttributes = Process security attributes
|
|
* lpThreadAttributes = Thread security attributes
|
|
* bInheritHandles = Handle inheritance flag
|
|
* dwCreationFlags = Creation flags
|
|
* lpEnvironment = Pointer to new environment block
|
|
* lpCurrentDirectory = Pointer to current directory name
|
|
* lpStartupInfo = Pointer to startup info
|
|
* lpProcessInformation = Pointer to process information
|
|
*/
|
|
{
|
|
UNICODE_STRING ApplicationNameU;
|
|
UNICODE_STRING CurrentDirectoryU;
|
|
UNICODE_STRING CommandLineU;
|
|
ANSI_STRING ApplicationName;
|
|
ANSI_STRING CurrentDirectory;
|
|
ANSI_STRING CommandLine;
|
|
WINBOOL Result;
|
|
|
|
DPRINT("CreateProcessA\n");
|
|
|
|
RtlInitAnsiString (&CommandLine,
|
|
lpCommandLine);
|
|
RtlInitAnsiString (&ApplicationName,
|
|
(LPSTR)lpApplicationName);
|
|
RtlInitAnsiString (&CurrentDirectory,
|
|
(LPSTR)lpCurrentDirectory);
|
|
|
|
/* convert ansi (or oem) strings to unicode */
|
|
if (bIsFileApiAnsi)
|
|
{
|
|
RtlAnsiStringToUnicodeString (&CommandLineU,
|
|
&CommandLine,
|
|
TRUE);
|
|
RtlAnsiStringToUnicodeString (&ApplicationNameU,
|
|
&ApplicationName,
|
|
TRUE);
|
|
RtlAnsiStringToUnicodeString (&CurrentDirectoryU,
|
|
&CurrentDirectory,
|
|
TRUE);
|
|
}
|
|
else
|
|
{
|
|
RtlOemStringToUnicodeString (&CommandLineU,
|
|
&CommandLine,
|
|
TRUE);
|
|
RtlOemStringToUnicodeString (&ApplicationNameU,
|
|
&ApplicationName,
|
|
TRUE);
|
|
RtlOemStringToUnicodeString (&CurrentDirectoryU,
|
|
&CurrentDirectory,
|
|
TRUE);
|
|
}
|
|
|
|
Result = CreateProcessW (ApplicationNameU.Buffer,
|
|
CommandLineU.Buffer,
|
|
lpProcessAttributes,
|
|
lpThreadAttributes,
|
|
bInheritHandles,
|
|
dwCreationFlags,
|
|
lpEnvironment,
|
|
CurrentDirectoryU.Buffer,
|
|
(LPSTARTUPINFOW)lpStartupInfo,
|
|
lpProcessInformation);
|
|
|
|
RtlFreeUnicodeString (&ApplicationNameU);
|
|
RtlFreeUnicodeString (&CommandLineU);
|
|
RtlFreeUnicodeString (&CurrentDirectoryU);
|
|
|
|
return Result;
|
|
}
|
|
|
|
#define STACK_TOP (0xb0000000)
|
|
|
|
HANDLE STDCALL KlCreateFirstThread(HANDLE ProcessHandle,
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
DWORD dwStackSize,
|
|
LPTHREAD_START_ROUTINE lpStartAddress,
|
|
DWORD dwCreationFlags,
|
|
LPDWORD lpThreadId)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE ThreadHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
CLIENT_ID ClientId;
|
|
CONTEXT ThreadContext;
|
|
INITIAL_TEB InitialTeb;
|
|
BOOLEAN CreateSuspended = FALSE;
|
|
PVOID BaseAddress;
|
|
|
|
ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
|
|
ObjectAttributes.RootDirectory = NULL;
|
|
ObjectAttributes.ObjectName = NULL;
|
|
ObjectAttributes.Attributes = 0;
|
|
if (lpThreadAttributes != NULL)
|
|
{
|
|
if (lpThreadAttributes->bInheritHandle)
|
|
ObjectAttributes.Attributes = OBJ_INHERIT;
|
|
ObjectAttributes.SecurityDescriptor =
|
|
lpThreadAttributes->lpSecurityDescriptor;
|
|
}
|
|
ObjectAttributes.SecurityQualityOfService = NULL;
|
|
|
|
if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
|
|
CreateSuspended = TRUE;
|
|
else
|
|
CreateSuspended = FALSE;
|
|
|
|
|
|
BaseAddress = (PVOID)(STACK_TOP - dwStackSize);
|
|
Status = NtAllocateVirtualMemory(ProcessHandle,
|
|
&BaseAddress,
|
|
0,
|
|
(PULONG)&dwStackSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
memset(&ThreadContext,0,sizeof(CONTEXT));
|
|
ThreadContext.Eip = (ULONG)lpStartAddress;
|
|
ThreadContext.SegGs = USER_DS;
|
|
ThreadContext.SegFs = USER_DS;
|
|
ThreadContext.SegEs = USER_DS;
|
|
ThreadContext.SegDs = USER_DS;
|
|
ThreadContext.SegCs = USER_CS;
|
|
ThreadContext.SegSs = USER_DS;
|
|
ThreadContext.Esp = STACK_TOP - 20;
|
|
ThreadContext.EFlags = (1<<1) + (1<<9);
|
|
|
|
DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
|
|
|
|
Status = NtCreateThread(&ThreadHandle,
|
|
THREAD_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
ProcessHandle,
|
|
&ClientId,
|
|
&ThreadContext,
|
|
&InitialTeb,
|
|
CreateSuspended);
|
|
if (lpThreadId != NULL)
|
|
{
|
|
memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
|
|
}
|
|
|
|
return(ThreadHandle);
|
|
}
|
|
|
|
HANDLE KlMapFile(LPCWSTR lpApplicationName,
|
|
LPCWSTR lpCommandLine)
|
|
{
|
|
HANDLE hFile;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UNICODE_STRING ApplicationNameString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
NTSTATUS Status;
|
|
HANDLE hSection;
|
|
|
|
hFile = NULL;
|
|
|
|
/*
|
|
* Find the application name
|
|
*/
|
|
|
|
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
|
|
&ApplicationNameString,
|
|
NULL,
|
|
NULL))
|
|
return NULL;
|
|
|
|
DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&ApplicationNameString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
SecurityDescriptor);
|
|
|
|
/*
|
|
* Try to open the executable
|
|
*/
|
|
|
|
Status = NtOpenFile(&hFile,
|
|
SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_DELETE|FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
|
|
|
|
RtlFreeUnicodeString (&ApplicationNameString);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
return(NULL);
|
|
}
|
|
|
|
Status = NtCreateSection(&hSection,
|
|
SECTION_ALL_ACCESS,
|
|
NULL,
|
|
NULL,
|
|
PAGE_EXECUTE,
|
|
SEC_IMAGE,
|
|
hFile);
|
|
NtClose(hFile);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
return(NULL);
|
|
}
|
|
|
|
return(hSection);
|
|
}
|
|
|
|
static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
|
|
PRTL_USER_PROCESS_PARAMETERS Ppb)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID PpbBase;
|
|
ULONG PpbSize;
|
|
ULONG BytesWritten;
|
|
ULONG Offset;
|
|
PVOID ParentEnv = NULL;
|
|
PVOID EnvPtr = NULL;
|
|
ULONG EnvSize = 0;
|
|
|
|
/* create the Environment */
|
|
if (Ppb->Environment != NULL)
|
|
ParentEnv = Ppb->Environment;
|
|
else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
|
|
ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
|
|
|
|
if (ParentEnv != NULL)
|
|
{
|
|
MEMORY_BASIC_INFORMATION MemInfo;
|
|
|
|
Status = NtQueryVirtualMemory (NtCurrentProcess (),
|
|
ParentEnv,
|
|
MemoryBasicInformation,
|
|
&MemInfo,
|
|
sizeof(MEMORY_BASIC_INFORMATION),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
EnvSize = MemInfo.RegionSize;
|
|
}
|
|
DPRINT("EnvironmentSize %ld\n", EnvSize);
|
|
|
|
/* allocate and initialize new environment block */
|
|
if (EnvSize != 0)
|
|
{
|
|
Status = NtAllocateVirtualMemory(ProcessHandle,
|
|
&EnvPtr,
|
|
0,
|
|
&EnvSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
NtWriteVirtualMemory(ProcessHandle,
|
|
EnvPtr,
|
|
ParentEnv,
|
|
EnvSize,
|
|
&BytesWritten);
|
|
}
|
|
|
|
/* create the PPB */
|
|
PpbBase = (PVOID)PEB_STARTUPINFO;
|
|
PpbSize = Ppb->MaximumLength;
|
|
Status = NtAllocateVirtualMemory(ProcessHandle,
|
|
&PpbBase,
|
|
0,
|
|
&PpbSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
|
|
NtWriteVirtualMemory(ProcessHandle,
|
|
PpbBase,
|
|
Ppb,
|
|
Ppb->MaximumLength,
|
|
&BytesWritten);
|
|
|
|
/* write pointer to environment */
|
|
Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
|
|
NtWriteVirtualMemory(ProcessHandle,
|
|
(PVOID)(PpbBase + Offset),
|
|
&EnvPtr,
|
|
sizeof(EnvPtr),
|
|
&BytesWritten);
|
|
|
|
/* write pointer to process parameter block */
|
|
Offset = FIELD_OFFSET(PEB, ProcessParameters);
|
|
NtWriteVirtualMemory(ProcessHandle,
|
|
(PVOID)(PEB_BASE + Offset),
|
|
&PpbBase,
|
|
sizeof(PpbBase),
|
|
&BytesWritten);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
WINBOOL STDCALL CreateProcessW(LPCWSTR lpApplicationName,
|
|
LPWSTR lpCommandLine,
|
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
WINBOOL bInheritHandles,
|
|
DWORD dwCreationFlags,
|
|
LPVOID lpEnvironment,
|
|
LPCWSTR lpCurrentDirectory,
|
|
LPSTARTUPINFOW lpStartupInfo,
|
|
LPPROCESS_INFORMATION lpProcessInformation)
|
|
{
|
|
HANDLE hSection, hProcess, hThread;
|
|
NTSTATUS Status;
|
|
LPTHREAD_START_ROUTINE lpStartAddress = NULL;
|
|
WCHAR TempCommandLine[256];
|
|
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
|
|
ULONG retlen;
|
|
PRTL_USER_PROCESS_PARAMETERS Ppb;
|
|
UNICODE_STRING CommandLine_U;
|
|
|
|
DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
|
|
lpApplicationName,lpCommandLine);
|
|
|
|
/*
|
|
* Process the application name and command line
|
|
*/
|
|
|
|
RtlGetFullPathName_U ((LPWSTR)lpApplicationName,
|
|
256 * sizeof(WCHAR),
|
|
TempCommandLine,
|
|
NULL);
|
|
|
|
if (lpCommandLine != NULL)
|
|
{
|
|
wcscat(TempCommandLine, L" ");
|
|
wcscat(TempCommandLine, lpCommandLine);
|
|
}
|
|
|
|
/*
|
|
* Create the PPB
|
|
*/
|
|
|
|
RtlInitUnicodeString(&CommandLine_U, TempCommandLine);
|
|
|
|
DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
|
|
|
|
RtlCreateProcessParameters(&Ppb,
|
|
&CommandLine_U,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
lpEnvironment,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
/*
|
|
* Create a section for the executable
|
|
*/
|
|
|
|
hSection = KlMapFile (lpApplicationName, lpCommandLine);
|
|
if (hSection == NULL)
|
|
{
|
|
RtlDestroyProcessParameters (Ppb);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Create a new process
|
|
*/
|
|
|
|
Status = NtCreateProcess(&hProcess,
|
|
PROCESS_ALL_ACCESS,
|
|
NULL,
|
|
NtCurrentProcess(),
|
|
bInheritHandles,
|
|
hSection,
|
|
NULL,
|
|
NULL);
|
|
|
|
/*
|
|
* Get some information about the process
|
|
*/
|
|
|
|
ZwQueryInformationProcess(hProcess,
|
|
ProcessBasicInformation,
|
|
&ProcessBasicInfo,
|
|
sizeof(ProcessBasicInfo),
|
|
&retlen);
|
|
DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
|
|
ProcessBasicInfo.UniqueProcessId);
|
|
lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
|
|
|
|
/*
|
|
* Create Process Environment Block
|
|
*/
|
|
DPRINT("Creating peb\n");
|
|
KlInitPeb(hProcess, Ppb);
|
|
|
|
RtlDestroyProcessParameters (Ppb);
|
|
|
|
DPRINT("Creating thread for process\n");
|
|
lpStartAddress = (LPTHREAD_START_ROUTINE)
|
|
((PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET(NTDLL_BASE))->
|
|
AddressOfEntryPoint +
|
|
((PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET(NTDLL_BASE))->ImageBase;
|
|
|
|
hThread = KlCreateFirstThread(hProcess,
|
|
lpThreadAttributes,
|
|
// Headers.OptionalHeader.SizeOfStackReserve,
|
|
0x200000,
|
|
lpStartAddress,
|
|
dwCreationFlags,
|
|
&lpProcessInformation->dwThreadId);
|
|
|
|
if (hThread == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
lpProcessInformation->hProcess = hProcess;
|
|
lpProcessInformation->hThread = hThread;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* EOF */
|