Second part of patch, implements the new RTL functions which will be used (not used by kernel yet).

- RtlCreateUserProcess:
        * Created RtlpInitEnvironment to manage Environment Block creation. Rougly based on
          old KlInitPeb code but with some optimizations.
        * Don't ignore Process Security Descriptor if one was specified.
        * Don't ignore ZeroBits, get correct entrypoint, and don't assume PEB address.
        * Don't close handle of section before closing process handle on failure.
        * Support new undocumented flag which pre-allocates 1MB of memory for Native Processes
        * FIXME: Hande duplication should be done, but wasn't and still isn't.
    
    - RtlpCreateUserStack:
        * New function to create a stack for a Thread, similar to BasepCreateStack but
          has some differences related to StackCommit/StackReserve.
        * Also create Guard Page
        
    - RtlpFreeUserStack:
        * Undoes what the function above does, in case of failure in code using it.
        
    - RtlCreateUserThread:
        * Use the new functions instead of rosrtl.
        
    - RtlInitializeContext:
        * New function similar to BasepInitializeContext but;
            > Uses a single entrypoint, not many possible thunks like Kernel32 (no need)
            > The starting EFLAGS is Interrupts Enabled, not IOPL 3.
            > We don't initialize the same Context Flags
            > The initial context registers are different
            
    - RtlFreeUserThreadStack
        * Don't assume the TEB address
          
    - RtlExitUserThread
        * Remove deprecated stack-switching semantics and use new TEB flag to tell the Kernel
          to deallocate the stack for us.

svn path=/trunk/; revision=16542
This commit is contained in:
Alex Ionescu 2005-07-12 04:41:41 +00:00
parent 36a1230e2b
commit e6523bb71e
5 changed files with 611 additions and 350 deletions

View file

@ -16,7 +16,7 @@
/* FIXME */
#include <rosrtl/thread.h>
//#define NDEBUG
#define NDEBUG
#include "../include/debug.h"
/* FUNCTIONS ****************************************************************/
@ -1378,11 +1378,11 @@ CreateProcessW(LPCWSTR lpApplicationName,
* Create the thread for the kernel
*/
DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress));
Sii.TransferAddress);
hThread = KlCreateFirstThread(hProcess,
lpThreadAttributes,
&Sii,
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress),
Sii.TransferAddress,
dwCreationFlags,
&lpProcessInformation->dwThreadId);
if (hThread == NULL)

View file

@ -90,4 +90,19 @@ RtlGetVersion(RTL_OSVERSIONINFOW *Info)
return STATUS_INVALID_PARAMETER;
}
/*
* @implemented
*/
VOID
STDCALL
RtlExitUserThread(NTSTATUS Status)
{
/* Call the Loader and tell him to notify the DLLs */
LdrShutdownThread();
/* Shut us down */
NtCurrentTeb()->FreeStackOnTermination = TRUE;
NtTerminateThread(NtCurrentThread(), Status);
}
/* EOF */

View file

@ -16,176 +16,161 @@
#define NDEBUG
#include <debug.h>
/* INTERNAL FUNCTIONS *******************************************************/
NTSTATUS
STDCALL
RtlpMapFile(PUNICODE_STRING ImageFileName,
ULONG Attributes,
PHANDLE Section)
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE hFile = NULL;
IO_STATUS_BLOCK IoStatusBlock;
/* Open the Image File */
InitializeObjectAttributes(&ObjectAttributes,
ImageFileName,
Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
NULL,
NULL);
Status = ZwOpenFile(&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))
{
DPRINT1("Failed to read image file from disk\n");
return(Status);
}
/* Now create a section for this image */
Status = ZwCreateSection(Section,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_EXECUTE,
SEC_IMAGE,
hFile);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create section for image file\n");
}
ZwClose(hFile);
return Status;
}
/* FUNCTIONS ****************************************************************/
static NTSTATUS
RtlpMapFile(PUNICODE_STRING ImageFileName,
PRTL_USER_PROCESS_PARAMETERS Ppb,
ULONG Attributes,
PHANDLE Section)
NTSTATUS
STDCALL
RtlpInitEnvironment(HANDLE ProcessHandle,
PPEB Peb,
PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
{
HANDLE hFile;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
NTSTATUS Status;
NTSTATUS Status;
PVOID BaseAddress = NULL;
ULONG EnviroSize;
ULONG Size;
PWCHAR Environment = 0;
DPRINT("RtlpInitEnvironment (hProcess: %lx, Peb: %p Params: %p)\n",
ProcessHandle, Peb, ProcessParameters);
/* Give the caller 1MB if he requested it */
if (ProcessParameters->Flags & PPF_RESERVE_1MB)
{
/* Give 1MB starting at 0x4 */
BaseAddress = (PVOID)4;
EnviroSize = 1024 * 1024;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&BaseAddress,
0,
&EnviroSize,
MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to reserve 1MB of space \n");
return(Status);
}
}
/* Find the end of the Enviroment Block */
if ((Environment = (PWCHAR)ProcessParameters->Environment))
{
while (*Environment++) while (*Environment++);
hFile = NULL;
/* Calculate the size of the block */
EnviroSize = (ULONG)((ULONG_PTR)Environment -
(ULONG_PTR)ProcessParameters->Environment);
DPRINT("EnvironmentSize %ld\n", EnviroSize);
RtlDeNormalizeProcessParams (Ppb);
/* Allocate and Initialize new Environment Block */
Size = EnviroSize;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&BaseAddress,
0,
&Size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to allocate Environment Block\n");
return(Status);
}
/* Write the Environment Block */
ZwWriteVirtualMemory(ProcessHandle,
BaseAddress,
ProcessParameters->Environment,
EnviroSize,
NULL);
/* Save pointer */
ProcessParameters->Environment = BaseAddress;
}
DPRINT("EnvironmentPointer %p\n", BaseAddress);
DPRINT("Ppb->MaximumLength %x\n", ProcessParameters->MaximumLength);
/* DbgPrint("ImagePathName 0x%p\n", Ppb->ImagePathName.Buffer); */
/* Now allocate space for the Parameter Block */
BaseAddress = NULL;
Size = ProcessParameters->MaximumLength;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&BaseAddress,
0,
&Size,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to allocate Parameter Block\n");
return(Status);
}
/* Write the Parameter Block */
ZwWriteVirtualMemory(ProcessHandle,
BaseAddress,
ProcessParameters,
ProcessParameters->Length,
NULL);
/* Write pointer to Parameter Block */
ZwWriteVirtualMemory(ProcessHandle,
&Peb->ProcessParameters,
&BaseAddress,
sizeof(BaseAddress),
NULL);
InitializeObjectAttributes(&ObjectAttributes,
ImageFileName,
Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
NULL,
SecurityDescriptor);
RtlNormalizeProcessParams (Ppb);
/*
* Try to open the executable
*/
Status = ZwOpenFile(&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))
{
return(Status);
}
Status = ZwCreateSection(Section,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_EXECUTE,
SEC_IMAGE,
hFile);
ZwClose(hFile);
if (!NT_SUCCESS(Status))
{
return(Status);
}
return(STATUS_SUCCESS);
/* Return */
return STATUS_SUCCESS;
}
static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
PRTL_USER_PROCESS_PARAMETERS Ppb,
PVOID* ImageBaseAddress)
{
NTSTATUS Status;
PVOID PpbBase;
ULONG PpbSize;
ULONG BytesWritten;
ULONG Offset;
PVOID EnvPtr = NULL;
ULONG EnvSize = 0;
/* create the Environment */
if (Ppb->Environment != NULL)
{
MEMORY_BASIC_INFORMATION MemInfo;
Status = ZwQueryVirtualMemory (NtCurrentProcess (),
Ppb->Environment,
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 = ZwAllocateVirtualMemory(ProcessHandle,
&EnvPtr,
0,
&EnvSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
ZwWriteVirtualMemory(ProcessHandle,
EnvPtr,
Ppb->Environment,
EnvSize,
&BytesWritten);
}
DPRINT("EnvironmentPointer %p\n", EnvPtr);
/* create the PPB */
PpbBase = NULL;
PpbSize = Ppb->MaximumLength;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&PpbBase,
0,
&PpbSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
/* write process parameters block*/
RtlDeNormalizeProcessParams (Ppb);
ZwWriteVirtualMemory(ProcessHandle,
PpbBase,
Ppb,
Ppb->MaximumLength,
&BytesWritten);
RtlNormalizeProcessParams (Ppb);
/* write pointer to environment */
Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
ZwWriteVirtualMemory(ProcessHandle,
(PVOID)((ULONG_PTR)PpbBase + Offset),
&EnvPtr,
sizeof(EnvPtr),
&BytesWritten);
/* write pointer to process parameter block */
Offset = FIELD_OFFSET(PEB, ProcessParameters);
ZwWriteVirtualMemory(ProcessHandle,
(PVOID)(PEB_BASE + Offset),
&PpbBase,
sizeof(PpbBase),
&BytesWritten);
/* Read image base address. */
Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
ZwReadVirtualMemory(ProcessHandle,
(PVOID)(PEB_BASE + Offset),
ImageBaseAddress,
sizeof(PVOID),
&BytesWritten);
return(STATUS_SUCCESS);
}
/*
* @implemented
*
@ -200,114 +185,136 @@ static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
*
* -Gunnar
*/
NTSTATUS STDCALL
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
STDCALL
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)
{
HANDLE hSection;
NTSTATUS Status;
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
ULONG retlen;
SECTION_IMAGE_INFORMATION Sii;
ULONG ResultLength;
PVOID ImageBaseAddress;
NTSTATUS Status;
HANDLE hSection;
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
DPRINT("RtlCreateUserProcess\n");
DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName);
Status = RtlpMapFile(ImageFileName,
ProcessParameters,
Attributes,
&hSection);
if( !NT_SUCCESS( Status ) )
return Status;
/* 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 CurDir 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);
/*
* Create a new process
*/
if (ParentProcess == NULL)
ParentProcess = NtCurrentProcess();
/*
* 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")))
{
UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS");
InitializeObjectAttributes(&ObjectAttributes,
&DebugString,
0,
NULL,
ProcessSecurityDescriptor);
}
/* 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);
}
Status = ZwCreateProcess(&(ProcessInfo->ProcessHandle),
PROCESS_ALL_ACCESS,
NULL,
ParentProcess,
InheritHandles,
hSection,
DebugPort,
ExceptionPort);
if (!NT_SUCCESS(Status))
{
ZwClose(hSection);
return(Status);
}
/* Get some information about the process */
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);
}
/*
* Get some information about the process
*/
ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
ProcessBasicInformation,
&ProcessBasicInfo,
sizeof(ProcessBasicInfo),
&retlen);
DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
ProcessBasicInfo.UniqueProcessId);
ProcessInfo->ClientId.UniqueProcess = (HANDLE)ProcessBasicInfo.UniqueProcessId;
/* Create Process Environment */
RtlpInitEnvironment(ProcessInfo->ProcessHandle,
ProcessBasicInfo.PebBaseAddress,
ProcessParameters);
/*
* Create Process Environment Block
*/
DPRINT("Creating peb\n");
KlInitPeb(ProcessInfo->ProcessHandle,
ProcessParameters,
&ImageBaseAddress);
Status = ZwQuerySection(hSection,
SectionImageInformation,
&Sii,
sizeof(Sii),
&ResultLength);
if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii))
{
DPRINT("Failed to get section image information.\n");
ZwClose(hSection);
return(Status);
}
DPRINT("Creating thread for process\n");
Status = RtlCreateUserThread(
ProcessInfo->ProcessHandle,
NULL,
TRUE, /* CreateSuspended? */
0,
Sii.MaximumStackSize,
Sii.CommittedStackSize,
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress),
(PVOID)PEB_BASE,
&ProcessInfo->ThreadHandle,
&ProcessInfo->ClientId
);
ZwClose(hSection);
if (!NT_SUCCESS(Status))
{
DPRINT("Failed to create thread\n");
return(Status);
}
return(STATUS_SUCCESS);
/* 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;
}
/* EOF */

View file

@ -3,113 +3,349 @@
* PROJECT: ReactOS kernel
* PURPOSE: Rtl user thread functions
* FILE: lib/ntdll/rtl/thread.c
* PROGRAMER: Eric Kohl
* REVISION HISTORY:
* 09/07/99: Created
* 09/10/99: Cleanup and full stack support.
* 25/04/03: Near rewrite. Made code more readable, replaced
* INITIAL_TEB with USER_STACK, added support for
* fixed-size stacks
* 28/04/03: Moved all code to a new statically linked
* library (ROSRTL) so it can be shared with
* kernel32.dll without exporting non-standard
* functions from ntdll.dll
* PROGRAMERS:
* Alex Ionescu (alex@relsoft.net)
* Eric Kohl
* KJK::Hyperion
*/
/* INCLUDES *****************************************************************/
#include "rtl.h"
#include <rosrtl/thread.h>
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS *******************************************************/
NTSTATUS
STDCALL
RtlpCreateUserStack(HANDLE hProcess,
ULONG StackReserve,
ULONG StackCommit,
ULONG StackZeroBits,
PINITIAL_TEB InitialTeb)
{
NTSTATUS Status;
SYSTEM_BASIC_INFORMATION SystemBasicInfo;
PIMAGE_NT_HEADERS Headers;
ULONG_PTR Stack = 0;
BOOLEAN UseGuard = FALSE;
DPRINT("RtlpCreateUserStack\n");
/* Get some memory information */
Status = NtQuerySystemInformation(SystemBasicInformation,
&SystemBasicInfo,
sizeof(SYSTEM_BASIC_INFORMATION),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to query system info\n");
return Status;
}
/* Use the Image Settings if we are dealing with the current Process */
if (hProcess == NtCurrentProcess())
{
/* Get the Image Headers */
Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
DPRINT("Headers: %p\n", Headers);
/* If we didn't get the parameters, find them ourselves */
StackReserve = (StackReserve) ?
StackReserve : Headers->OptionalHeader.SizeOfStackReserve;
StackCommit = (StackCommit) ?
StackCommit : Headers->OptionalHeader.SizeOfStackCommit;
}
else
{
/* Use the System Settings if needed */
StackReserve = (StackReserve) ? StackReserve :
SystemBasicInfo.AllocationGranularity;
StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize;
}
/* Align everything to Page Size */
StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
#if 1 // FIXME: Remove once Guard Page support is here
StackCommit = StackReserve;
#endif
DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit);
/* Reserve memory for the stack */
Status = ZwAllocateVirtualMemory(hProcess,
(PVOID*)&Stack,
StackZeroBits,
&StackReserve,
MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to reserve stack\n");
return Status;
}
/* Now set up some basic Initial TEB Parameters */
InitialTeb->AllocatedStackBase = (PVOID)Stack;
InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
/* Update the Stack Position */
Stack += StackReserve - StackCommit;
/* Check if we will need a guard page */
if (StackReserve > StackCommit)
{
Stack -= SystemBasicInfo.PageSize;
StackCommit += SystemBasicInfo.PageSize;
UseGuard = TRUE;
}
DPRINT("AllocatedBase: %p, StackBase: %p, Stack: %p, StackCommit: %lx\n",
InitialTeb->AllocatedStackBase, InitialTeb->StackBase, Stack,
StackCommit);
/* Allocate memory for the stack */
Status = ZwAllocateVirtualMemory(hProcess,
(PVOID*)&Stack,
0,
&StackCommit,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to allocate stack\n");
return Status;
}
/* Now set the current Stack Limit */
InitialTeb->StackLimit = (PVOID)Stack;
DPRINT("StackLimit: %p\n", Stack);
/* Create a guard page */
if (UseGuard)
{
ULONG GuardPageSize = SystemBasicInfo.PageSize;
ULONG Dummy;
/* Attempt maximum space possible */
Status = ZwProtectVirtualMemory(hProcess,
(PVOID*)&Stack,
&GuardPageSize,
PAGE_GUARD | PAGE_READWRITE,
&Dummy);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to create guard page\n");
return Status;
}
/* Update the Stack Limit keeping in mind the Guard Page */
InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit -
GuardPageSize);
DPRINT1("StackLimit: %p\n", Stack);
}
/* We are done! */
return Status;
}
NTSTATUS
STDCALL
RtlpFreeUserStack(HANDLE hProcess,
PINITIAL_TEB InitialTeb)
{
ULONG Dummy = 0;
/* Free the Stack */
return ZwFreeVirtualMemory(hProcess,
&InitialTeb->AllocatedStackBase,
&Dummy,
MEM_RELEASE);
}
/* FUNCTIONS ***************************************************************/
/*
@implemented
*/
NTSTATUS STDCALL RtlCreateUserThread
(
HANDLE ProcessHandle,
PSECURITY_DESCRIPTOR SecurityDescriptor,
BOOLEAN CreateSuspended,
LONG StackZeroBits,
ULONG StackReserve,
ULONG StackCommit,
PTHREAD_START_ROUTINE StartAddress,
PVOID Parameter,
PHANDLE ThreadHandle,
PCLIENT_ID ClientId
)
NTSTATUS
STDCALL
RtlCreateUserThread(HANDLE ProcessHandle,
PSECURITY_DESCRIPTOR SecurityDescriptor,
BOOLEAN CreateSuspended,
LONG StackZeroBits,
ULONG StackReserve,
ULONG StackCommit,
PTHREAD_START_ROUTINE StartAddress,
PVOID Parameter,
PHANDLE ThreadHandle,
PCLIENT_ID ClientId)
{
OBJECT_ATTRIBUTES oaThreadAttribs;
NTSTATUS Status;
HANDLE Handle;
CLIENT_ID ThreadCid;
INITIAL_TEB InitialTeb;
OBJECT_ATTRIBUTES ObjectAttributes;
CONTEXT Context;
DPRINT("RtlCreateUserThread: (hProcess: %lx, Suspended: %lx,"
"ZeroBits: %lx, StackReserve: %lx, StackCommit: %lx,"
"StartAddress: %p, Parameter: %lx)\n", ProcessHandle,
CreateSuspended, StackZeroBits, StackReserve, StackCommit,
StartAddress, Parameter);
/* First, we'll create the Stack */
Status = RtlpCreateUserStack(ProcessHandle,
StackReserve,
StackCommit,
StackZeroBits,
&InitialTeb);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to create User Stack\n");
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))
{
DPRINT1("Failure to create Thread\n");
/* Free the stack */
RtlpFreeUserStack(ProcessHandle, &InitialTeb);
}
else
{
DPRINT("Thread created: %lx\n", Handle);
if (ThreadHandle) *ThreadHandle = Handle;
if (ClientId) *ClientId = ThreadCid;
}
/* Return success or the previous failure */
return Status;
}
InitializeObjectAttributes
(
&oaThreadAttribs,
NULL,
0,
NULL,
SecurityDescriptor
);
/*
* FIXME: Should go in /i386
@implemented
*/
VOID
STDCALL
RtlInitializeContext(IN HANDLE ProcessHandle,
OUT PCONTEXT ThreadContext,
IN PVOID ThreadStartParam OPTIONAL,
IN PTHREAD_START_ROUTINE ThreadStartAddress,
IN PINITIAL_TEB InitialTeb)
{
DPRINT("RtlInitializeContext: (hProcess: %lx, ThreadContext: %p, Teb: %p\n",
ProcessHandle, ThreadContext, InitialTeb);
return RtlRosCreateUserThread
(
ProcessHandle,
&oaThreadAttribs,
CreateSuspended,
StackZeroBits,
&StackReserve,
&StackCommit,
StartAddress,
ThreadHandle,
ClientId,
1,
(ULONG_PTR *)&Parameter
);
/*
* Set the Initial Registers
* This is based on NT's default values -- crazy apps might expect this...
*/
ThreadContext->Ebp = 0;
ThreadContext->Eax = 0;
ThreadContext->Ebx = 1;
ThreadContext->Ecx = 2;
ThreadContext->Edx = 3;
ThreadContext->Esi = 4;
ThreadContext->Edi = 5;
/* Set the Selectors */
ThreadContext->SegGs = 0;
ThreadContext->SegFs = TEB_SELECTOR;
ThreadContext->SegEs = USER_DS;
ThreadContext->SegDs = USER_DS;
ThreadContext->SegCs = USER_CS;
ThreadContext->SegSs = USER_DS;
/* Enable Interrupts */
ThreadContext->EFlags = 0x200; /*X86_EFLAGS_IF */
/* Settings passed */
ThreadContext->Eip = (ULONG)ThreadStartAddress;
ThreadContext->Esp = (ULONG)InitialTeb;
/* Only the basic Context is initialized */
ThreadContext->ContextFlags = CONTEXT_CONTROL |
CONTEXT_INTEGER |
CONTEXT_SEGMENTS;
/* Set up ESP to the right value */
ThreadContext->Esp -= sizeof(PVOID);
ZwWriteVirtualMemory(ProcessHandle,
(PVOID)ThreadContext->Esp,
(PVOID)&ThreadStartParam,
sizeof(PVOID),
NULL);
/* Push it down one more notch for RETEIP */
ThreadContext->Esp -= sizeof(PVOID);
}
/*
@implemented
*/
VOID STDCALL
RtlInitializeContext(
IN HANDLE ProcessHandle,
OUT PCONTEXT ThreadContext,
IN PVOID ThreadStartParam OPTIONAL,
IN PTHREAD_START_ROUTINE ThreadStartAddress,
IN PINITIAL_TEB InitialTeb)
VOID
STDCALL
RtlFreeUserThreadStack(HANDLE ProcessHandle,
HANDLE ThreadHandle)
{
RtlRosInitializeContext
(
ProcessHandle,
ThreadContext,
ThreadStartAddress,
InitialTeb,
1,
(ULONG_PTR *)&ThreadStartParam
);
}
/*
@implemented
*/
NTSTATUS STDCALL RtlFreeUserThreadStack
(
HANDLE ProcessHandle,
HANDLE ThreadHandle
)
{
return RtlRosFreeUserThreadStack(ProcessHandle, ThreadHandle);
}
/*
@implemented
*/
VOID STDCALL RtlExitUserThread(NTSTATUS Status)
{
RtlRosExitUserThread(Status);
NTSTATUS Status;
THREAD_BASIC_INFORMATION ThreadBasicInfo;
ULONG Dummy, Size = 0;
PVOID StackLocation;
/* Query the Basic Info */
Status = NtQueryInformationThread(ThreadHandle,
ThreadBasicInformation,
&ThreadBasicInfo,
sizeof(THREAD_BASIC_INFORMATION),
NULL);
if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress)
{
DPRINT1("Could not query info, or TEB is NULL\n");
return;
}
/* Get the deallocation stack */
Status = NtReadVirtualMemory(ProcessHandle,
&((PTEB)ThreadBasicInfo.TebBaseAddress)->
DeallocationStack,
&StackLocation,
sizeof(PVOID),
&Dummy);
if (!NT_SUCCESS(Status) || !StackLocation)
{
DPRINT1("Could not read Deallocation Base\n");
return;
}
/* Free it */
NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);
}
/* EOF */

View file

@ -483,7 +483,10 @@ l_ReadHeaderFromFile:
ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
ImageSectionObject->EntryPoint = piohOptHeader->AddressOfEntryPoint;
{
ImageSectionObject->EntryPoint = piohOptHeader->ImageBase +
piohOptHeader->AddressOfEntryPoint;
}
ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));