Files
reactos/reactos/lib/kernel32/process/create.c
T
Eric Kohl b001203a86 - implemented process parameter block (PPB) code
- improved process environment block (PEB) code
- improved environment code

svn path=/trunk/; revision=828
1999-12-06 00:25:14 +00:00

553 lines
13 KiB
C

/* $Id: create.c,v 1.14 1999/12/06 00:23:40 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 ( [email protected])
* UPDATE HISTORY:
* Created 01/11/98
*/
/* INCLUDES ****************************************************************/
#define WIN32_NO_PEHDR
#include <ddk/ntddk.h>
#include <windows.h>
#include <kernel32/proc.h>
#include <kernel32/thread.h>
#include <wchar.h>
#include <string.h>
#include <pe.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
*/
{
WCHAR ApplicationNameW[MAX_PATH];
WCHAR CommandLineW[MAX_PATH];
WCHAR CurrentDirectoryW[MAX_PATH];
PWSTR PApplicationNameW;
PWSTR PCommandLineW;
PWSTR PCurrentDirectoryW;
DPRINT("CreateProcessA\n");
PApplicationNameW = InternalAnsiToUnicode(ApplicationNameW,
lpApplicationName,
MAX_PATH);
PCommandLineW = InternalAnsiToUnicode(CommandLineW,
lpCommandLine,
MAX_PATH);
PCurrentDirectoryW = InternalAnsiToUnicode(CurrentDirectoryW,
lpCurrentDirectory,
MAX_PATH);
return CreateProcessW(PApplicationNameW,
PCommandLineW,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
PCurrentDirectoryW,
(LPSTARTUPINFOW)lpStartupInfo,
lpProcessInformation);
}
#define STACK_TOP (0xb0000000)
HANDLE STDCALL CreateFirstThread(HANDLE ProcessHandle,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId,
PWSTR lpCommandLine,
HANDLE NTDllSectionHandle,
HANDLE SectionHandle,
PVOID ImageBase)
{
NTSTATUS Status;
HANDLE ThreadHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
CLIENT_ID ClientId;
CONTEXT ThreadContext;
INITIAL_TEB InitialTeb;
BOOLEAN CreateSuspended = FALSE;
PVOID BaseAddress;
ULONG BytesWritten;
HANDLE DupNTDllSectionHandle, DupSectionHandle;
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 - 16;
ThreadContext.EFlags = (1<<1) + (1<<9);
DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
NtDuplicateObject(NtCurrentProcess(),
&SectionHandle,
ProcessHandle,
&DupSectionHandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
NtDuplicateObject(NtCurrentProcess(),
&NTDllSectionHandle,
ProcessHandle,
&DupNTDllSectionHandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
NtWriteVirtualMemory(ProcessHandle,
(PVOID)(STACK_TOP - 4),
&DupNTDllSectionHandle,
sizeof(DupNTDllSectionHandle),
&BytesWritten);
NtWriteVirtualMemory(ProcessHandle,
(PVOID)(STACK_TOP - 8),
&ImageBase,
sizeof(ImageBase),
&BytesWritten);
NtWriteVirtualMemory(ProcessHandle,
(PVOID)(STACK_TOP - 12),
&DupSectionHandle,
sizeof(DupSectionHandle),
&BytesWritten);
Status = NtCreateThread(&ThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
ProcessHandle,
&ClientId,
&ThreadContext,
&InitialTeb,
CreateSuspended);
if ( lpThreadId != NULL )
memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
return ThreadHandle;
}
HANDLE KERNEL32_MapFile(LPCWSTR lpApplicationName,
LPCWSTR lpCommandLine,
PIMAGE_NT_HEADERS Headers,
PIMAGE_DOS_HEADER DosHeader)
{
WCHAR TempApplicationName[256];
WCHAR TempFileName[256];
HANDLE hFile;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
ULONG i;
WCHAR TempDirectoryName[256];
UNICODE_STRING ApplicationNameString;
OBJECT_ATTRIBUTES ObjectAttributes;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
NTSTATUS Status;
HANDLE hSection;
DWORD len = 0;
hFile = NULL;
/*
* Find the application name
*/
TempApplicationName[0] = '\\';
TempApplicationName[1] = '?';
TempApplicationName[2] = '?';
TempApplicationName[3] = '\\';
TempApplicationName[4] = 0;
DPRINT("TempApplicationName '%w'\n",TempApplicationName);
if (lpApplicationName != NULL)
{
wcscpy(TempFileName, lpApplicationName);
DPRINT("TempFileName '%w'\n",TempFileName);
}
else
{
wcscpy(TempFileName, lpCommandLine);
DPRINT("TempFileName '%w'\n",TempFileName);
for (i=0; TempFileName[i]!=' ' && TempFileName[i] != 0; i++);
TempFileName[i]=0;
}
if (TempFileName[1] != ':')
{
len = GetCurrentDirectoryW(MAX_PATH,TempDirectoryName);
if (TempDirectoryName[len - 1] != L'\\')
{
TempDirectoryName[len] = L'\\';
TempDirectoryName[len + 1] = 0;
}
wcscat(TempApplicationName,TempDirectoryName);
}
wcscat(TempApplicationName,TempFileName);
RtlInitUnicodeString(&ApplicationNameString, TempApplicationName);
DPRINT("ApplicationName %w\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);
if (!NT_SUCCESS(Status))
{
SetLastError(RtlNtStatusToDosError(Status));
return(NULL);
}
Status = NtReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
DosHeader,
sizeof(IMAGE_DOS_HEADER),
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
SetLastError(RtlNtStatusToDosError(Status));
return(NULL);
}
FileOffset.u.LowPart = DosHeader->e_lfanew;
FileOffset.u.HighPart = 0;
Status = NtReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
Headers,
sizeof(IMAGE_NT_HEADERS),
&FileOffset,
NULL);
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
CreatePeb (
HANDLE ProcessHandle,
PPPB Ppb)
{
NTSTATUS Status;
PVOID PebBase;
ULONG PebSize;
PEB Peb;
PVOID PpbBase;
ULONG PpbSize;
ULONG BytesWritten;
PebBase = (PVOID)PEB_BASE;
PebSize = 0x1000;
NtReadVirtualMemory(ProcessHandle,
(PVOID)PEB_BASE,
&Peb,
sizeof(Peb),
&BytesWritten);
Peb.Ppb = (PPPB)PEB_STARTUPINFO;
NtWriteVirtualMemory(ProcessHandle,
(PVOID)PEB_BASE,
&Peb,
sizeof(Peb),
&BytesWritten);
PpbBase = (PVOID)PEB_STARTUPINFO;
PpbSize = Ppb->TotalSize;
Status = NtAllocateVirtualMemory(ProcessHandle,
&PpbBase,
0,
&PpbSize,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
DPRINT("Ppb size %x\n", Ppb->TotalSize);
ZwWriteVirtualMemory(ProcessHandle,
(PVOID)PEB_STARTUPINFO,
&Ppb,
Ppb->TotalSize,
&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;
LPVOID lpParameter = NULL;
WCHAR TempCommandLine[256];
PVOID BaseAddress;
LARGE_INTEGER SectionOffset;
IMAGE_NT_HEADERS Headers;
IMAGE_DOS_HEADER DosHeader;
HANDLE NTDllSection;
ULONG InitialViewSize;
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
ULONG retlen;
DWORD len = 0;
PPPB Ppb;
UNICODE_STRING CommandLine_U;
DPRINT("CreateProcessW(lpApplicationName '%w', lpCommandLine '%w')\n",
lpApplicationName,lpCommandLine);
if (lpApplicationName[1] != ':')
{
len = GetCurrentDirectoryW(MAX_PATH,TempCommandLine);
if (TempCommandLine[len - 1] != L'\\')
{
TempCommandLine[len] = L'\\';
TempCommandLine[len + 1] = 0;
}
wcscat(TempCommandLine,lpApplicationName);
}
else
wcscpy(TempCommandLine, lpApplicationName);
if (lpCommandLine != NULL)
{
wcscat(TempCommandLine, L" ");
wcscat(TempCommandLine, lpCommandLine);
}
RtlInitUnicodeString (
&CommandLine_U,
TempCommandLine);
RtlCreateProcessParameters (
&Ppb,
&CommandLine_U,
NULL,
NULL,
NULL,
lpEnvironment,
NULL,
NULL,
NULL,
NULL);
hSection = KERNEL32_MapFile (
lpApplicationName,
lpCommandLine,
&Headers,
&DosHeader);
Status = NtCreateProcess(&hProcess,
PROCESS_ALL_ACCESS,
NULL,
NtCurrentProcess(),
bInheritHandles,
NULL,
NULL,
NULL);
ZwQueryInformationProcess(hProcess,
ProcessBasicInformation,
&ProcessBasicInfo,
sizeof(ProcessBasicInfo),
&retlen);
DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
ProcessBasicInfo.UniqueProcessId);
lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
/*
* Map NT DLL into the process
*/
Status = LdrMapNTDllForProcess(hProcess,
&NTDllSection);
InitialViewSize = DosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS)
+ sizeof(IMAGE_SECTION_HEADER) * Headers.FileHeader.NumberOfSections;
BaseAddress = (PVOID)Headers.OptionalHeader.ImageBase;
SectionOffset.QuadPart = 0;
Status = NtMapViewOfSection(hSection,
hProcess,
&BaseAddress,
0,
InitialViewSize,
&SectionOffset,
&InitialViewSize,
0,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
RtlDestroyProcessParameters (Ppb);
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
/*
* Create Process Environment Block
*/
DPRINT("Creating peb\n");
CreatePeb(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 = CreateFirstThread(hProcess,
lpThreadAttributes,
Headers.OptionalHeader.SizeOfStackReserve,
lpStartAddress,
lpParameter,
dwCreationFlags,
&lpProcessInformation->dwThreadId,
TempCommandLine,
NTDllSection,
hSection,
(PVOID)Headers.OptionalHeader.ImageBase);
if ( hThread == NULL )
return FALSE;
lpProcessInformation->hProcess = hProcess;
lpProcessInformation->hThread = hThread;
return TRUE;
}
/* EOF */