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

View file

@ -90,4 +90,19 @@ RtlGetVersion(RTL_OSVERSIONINFOW *Info)
return STATUS_INVALID_PARAMETER; 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 */ /* EOF */

View file

@ -16,176 +16,161 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #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 ****************************************************************/ /* FUNCTIONS ****************************************************************/
NTSTATUS
static NTSTATUS STDCALL
RtlpMapFile(PUNICODE_STRING ImageFileName, RtlpInitEnvironment(HANDLE ProcessHandle,
PRTL_USER_PROCESS_PARAMETERS Ppb, PPEB Peb,
ULONG Attributes, PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
PHANDLE Section)
{ {
HANDLE hFile; NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock; PVOID BaseAddress = NULL;
OBJECT_ATTRIBUTES ObjectAttributes; ULONG EnviroSize;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; ULONG Size;
NTSTATUS Status; 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, /* Return */
ImageFileName, return STATUS_SUCCESS;
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);
} }
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 * @implemented
* *
@ -200,114 +185,136 @@ static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
* *
* -Gunnar * -Gunnar
*/ */
NTSTATUS STDCALL NTSTATUS
RtlCreateUserProcess( STDCALL
IN PUNICODE_STRING ImageFileName, RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName,
IN ULONG Attributes, IN ULONG Attributes,
IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters, IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL, IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL, IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
IN HANDLE ParentProcess OPTIONAL, IN HANDLE ParentProcess OPTIONAL,
IN BOOLEAN InheritHandles, IN BOOLEAN InheritHandles,
IN HANDLE DebugPort OPTIONAL, IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL,
OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo)
)
{ {
HANDLE hSection; NTSTATUS Status;
NTSTATUS Status; HANDLE hSection;
PROCESS_BASIC_INFORMATION ProcessBasicInfo; PROCESS_BASIC_INFORMATION ProcessBasicInfo;
ULONG retlen; OBJECT_ATTRIBUTES ObjectAttributes;
SECTION_IMAGE_INFORMATION Sii;
ULONG ResultLength;
PVOID ImageBaseAddress;
DPRINT("RtlCreateUserProcess\n"); DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName);
Status = RtlpMapFile(ImageFileName, /* Map and Load the File */
ProcessParameters, Status = RtlpMapFile(ImageFileName,
Attributes, Attributes,
&hSection); &hSection);
if( !NT_SUCCESS( Status ) ) if(!NT_SUCCESS(Status))
return 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 FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the
*/ * watch of WindowsSS
if (ParentProcess == NULL) */
ParentProcess = NtCurrentProcess(); 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), /* Get some information about the process */
PROCESS_ALL_ACCESS, ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
NULL, ProcessBasicInformation,
ParentProcess, &ProcessBasicInfo,
InheritHandles, sizeof(ProcessBasicInfo),
hSection, NULL);
DebugPort, if (!NT_SUCCESS(Status))
ExceptionPort); {
if (!NT_SUCCESS(Status)) DPRINT1("Could not query Process Info\n");
{ ZwClose(ProcessInfo->ProcessHandle);
ZwClose(hSection); ZwClose(hSection);
return(Status); return(Status);
} }
/* /* Create Process Environment */
* Get some information about the process RtlpInitEnvironment(ProcessInfo->ProcessHandle,
*/ ProcessBasicInfo.PebBaseAddress,
ZwQueryInformationProcess(ProcessInfo->ProcessHandle, ProcessParameters);
ProcessBasicInformation,
&ProcessBasicInfo,
sizeof(ProcessBasicInfo),
&retlen);
DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
ProcessBasicInfo.UniqueProcessId);
ProcessInfo->ClientId.UniqueProcess = (HANDLE)ProcessBasicInfo.UniqueProcessId;
/* /* Create the first Thread */
* Create Process Environment Block Status = RtlCreateUserThread(ProcessInfo->ProcessHandle,
*/ ThreadSecurityDescriptor,
DPRINT("Creating peb\n"); TRUE,
KlInitPeb(ProcessInfo->ProcessHandle, ProcessInfo->ImageInformation.ZeroBits,
ProcessParameters, ProcessInfo->ImageInformation.MaximumStackSize,
&ImageBaseAddress); ProcessInfo->ImageInformation.CommittedStackSize,
ProcessInfo->ImageInformation.TransferAddress,
Status = ZwQuerySection(hSection, ProcessBasicInfo.PebBaseAddress,
SectionImageInformation, &ProcessInfo->ThreadHandle,
&Sii, &ProcessInfo->ClientId);
sizeof(Sii), if (!NT_SUCCESS(Status))
&ResultLength); {
if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii)) DPRINT1("Could not Create Thread\n");
{ ZwClose(ProcessInfo->ProcessHandle);
DPRINT("Failed to get section image information.\n"); ZwClose(hSection); /* Don't try to optimize this on top! */
ZwClose(hSection); return Status;
return(Status); }
}
/* Close the Section Handle and return */
DPRINT("Creating thread for process\n"); ZwClose(hSection);
Status = RtlCreateUserThread( return STATUS_SUCCESS;
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);
} }
/* EOF */ /* EOF */

View file

@ -3,113 +3,349 @@
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* PURPOSE: Rtl user thread functions * PURPOSE: Rtl user thread functions
* FILE: lib/ntdll/rtl/thread.c * FILE: lib/ntdll/rtl/thread.c
* PROGRAMER: Eric Kohl * PROGRAMERS:
* REVISION HISTORY: * Alex Ionescu (alex@relsoft.net)
* 09/07/99: Created * Eric Kohl
* 09/10/99: Cleanup and full stack support. * KJK::Hyperion
* 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
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
#include "rtl.h" #include "rtl.h"
#include <rosrtl/thread.h>
#define NDEBUG #define NDEBUG
#include <debug.h> #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 ***************************************************************/ /* FUNCTIONS ***************************************************************/
/* /*
@implemented @implemented
*/ */
NTSTATUS STDCALL RtlCreateUserThread NTSTATUS
( STDCALL
HANDLE ProcessHandle, RtlCreateUserThread(HANDLE ProcessHandle,
PSECURITY_DESCRIPTOR SecurityDescriptor, PSECURITY_DESCRIPTOR SecurityDescriptor,
BOOLEAN CreateSuspended, BOOLEAN CreateSuspended,
LONG StackZeroBits, LONG StackZeroBits,
ULONG StackReserve, ULONG StackReserve,
ULONG StackCommit, ULONG StackCommit,
PTHREAD_START_ROUTINE StartAddress, PTHREAD_START_ROUTINE StartAddress,
PVOID Parameter, PVOID Parameter,
PHANDLE ThreadHandle, PHANDLE ThreadHandle,
PCLIENT_ID ClientId 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 /*
( * FIXME: Should go in /i386
&oaThreadAttribs, @implemented
NULL, */
0, VOID
NULL, STDCALL
SecurityDescriptor 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 /*
( * Set the Initial Registers
ProcessHandle, * This is based on NT's default values -- crazy apps might expect this...
&oaThreadAttribs, */
CreateSuspended, ThreadContext->Ebp = 0;
StackZeroBits, ThreadContext->Eax = 0;
&StackReserve, ThreadContext->Ebx = 1;
&StackCommit, ThreadContext->Ecx = 2;
StartAddress, ThreadContext->Edx = 3;
ThreadHandle, ThreadContext->Esi = 4;
ClientId, ThreadContext->Edi = 5;
1,
(ULONG_PTR *)&Parameter /* 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 @implemented
*/ */
VOID STDCALL VOID
RtlInitializeContext( STDCALL
IN HANDLE ProcessHandle, RtlFreeUserThreadStack(HANDLE ProcessHandle,
OUT PCONTEXT ThreadContext, HANDLE ThreadHandle)
IN PVOID ThreadStartParam OPTIONAL,
IN PTHREAD_START_ROUTINE ThreadStartAddress,
IN PINITIAL_TEB InitialTeb)
{ {
RtlRosInitializeContext NTSTATUS Status;
( THREAD_BASIC_INFORMATION ThreadBasicInfo;
ProcessHandle, ULONG Dummy, Size = 0;
ThreadContext, PVOID StackLocation;
ThreadStartAddress,
InitialTeb, /* Query the Basic Info */
1, Status = NtQueryInformationThread(ThreadHandle,
(ULONG_PTR *)&ThreadStartParam ThreadBasicInformation,
); &ThreadBasicInfo,
} sizeof(THREAD_BASIC_INFORMATION),
NULL);
/* if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress)
@implemented {
*/ DPRINT1("Could not query info, or TEB is NULL\n");
NTSTATUS STDCALL RtlFreeUserThreadStack return;
( }
HANDLE ProcessHandle,
HANDLE ThreadHandle /* Get the deallocation stack */
) Status = NtReadVirtualMemory(ProcessHandle,
{ &((PTEB)ThreadBasicInfo.TebBaseAddress)->
return RtlRosFreeUserThreadStack(ProcessHandle, ThreadHandle); DeallocationStack,
} &StackLocation,
sizeof(PVOID),
/* &Dummy);
@implemented if (!NT_SUCCESS(Status) || !StackLocation)
*/ {
VOID STDCALL RtlExitUserThread(NTSTATUS Status) DPRINT1("Could not read Deallocation Base\n");
{ return;
RtlRosExitUserThread(Status); }
/* Free it */
NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);
} }
/* EOF */ /* EOF */

View file

@ -483,7 +483,10 @@ l_ReadHeaderFromFile:
ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint)); ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, 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)); ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));