- Final ROSRTL removal patch. The next patch will remove the actual library and code.

- Changes:
    - CreateProcess
        * Cleanup creation of the initial thread using new utility functions and remove rosrtl
        * Almost entirely rewrote the function to support features such as:
            - SxS (locally only, patch will follow),
            - SFP (SAFER) (locally only, patch will follow),
            - DllPaths (locally only, patch will follow), 
            - Proper process environment/paramter block creation
            - Proper console handle management (needs more work in kernel32/csr),
            - Tokens/CreateProcessAsUser (locally only, patch will follow), 
            - Simpler code for path lookup, and more robust.
            - Support for "auto-correction" (see Raymond Chen's blog)
            - 16-bit/NE detection
            - A variety of creation flags are now properly supported
            - Added support for an undocumented-yet-known (see comment) shell flag
            - Alert for flags we don't support yet
            - Catch invalid flag combinations and other caller errors
            - Improve and correct path searcing to use documented behaviours
            - Created a multitude of helper functions to make the code easier to read
              and allow them to be used for other apis as time goes on.
    
    - BaseProcessStartup
        * Call NtSetThreadInformation to let the Kernel know of the Thread's Start Address.
        * Correct prototype of Thread Startup function for this case.

This fixes MANY things, some of which may not be evident, and possibly creates regressions which I have not yet seen but will try to correct. Some of these may be caused by the fact that I've seen code send CreateProcessW incorrect flags. Some things of note: DO NOT send partial names as "lpApplicationName". It's not supposed to work unless you're in the same current directory. Also, do NOT send CREATE_UNICODE_ENVIRONMENT if you don't have a unicode environement, and vice-versa. I've seen lots of code doing mistakes related to this. I hope you appreciate this patch and won't all jump on me for possbile regressions :(.

svn path=/trunk/; revision=16730
This commit is contained in:
Alex Ionescu 2005-07-26 04:14:10 +00:00
parent 286cccb1de
commit 1e8c8e3fe6
4 changed files with 2083 additions and 2079 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,32 +1,32 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
* FILE: lib/kernel32/thread/i386/thread.S * FILE: lib/kernel32/thread/i386/thread.S
* PURPOSE: Thread Start Thunks * PURPOSE: Thread Start Thunks
* PROGRAMMER: Alex Ionescu (alex@relsoft.net) * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
*/ */
.globl _BaseThreadStartupThunk@0 .globl _BaseThreadStartupThunk@0
.globl _BaseProcessStartThunk@0 .globl _BaseProcessStartThunk@0
.intel_syntax noprefix .intel_syntax noprefix
_BaseThreadStartupThunk@0: _BaseThreadStartupThunk@0:
/* Start out fresh */ /* Start out fresh */
xor ebp, ebp xor ebp, ebp
push ebx /* lpParameter */ push ebx /* lpParameter */
push eax /* lpStartAddress */ push eax /* lpStartAddress */
push 0 /* Return EIP */ push 0 /* Return EIP */
//jmp _BaseThreadStartup@8 jmp _BaseThreadStartup@8
_BaseProcessStartThunk@0: _BaseProcessStartThunk@0:
/* Start out fresh */ /* Start out fresh */
xor ebp, ebp xor ebp, ebp
push eax /* lpStartAddress */ push eax /* lpStartAddress */
push 0 /* Return EIP */ push 0 /* Return EIP */
//jmp _BaseProcessStartup@4 jmp _BaseProcessStartup@4
/* EOF */ /* EOF */

View file

@ -1,13 +1,10 @@
/* $Id$ /*
*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
* FILE: lib/kernel32/thread/thread.c * FILE: lib/kernel32/thread/thread.c
* PURPOSE: Thread functions * PURPOSE: Thread functions
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl) * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Tls functions are modified from WINE * Ariadne ( ariadne@xs4all.nl)
* UPDATE HISTORY:
* Created 01/11/98
* *
*/ */
@ -15,13 +12,9 @@
#include <k32.h> #include <k32.h>
/* FIXME */
#include <rosrtl/thread.h>
#define NDEBUG #define NDEBUG
#include "../include/debug.h" #include "../include/debug.h"
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
_SEH_FILTER(BaseThreadExceptionFilter) _SEH_FILTER(BaseThreadExceptionFilter)
{ {
@ -68,199 +61,196 @@ BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
ExitThread(uExitCode); ExitThread(uExitCode);
} }
/*
* @implemented
*/
HANDLE
STDCALL
CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId)
{
/* Act as if we're going to create a remote thread in ourselves */
return CreateRemoteThread(NtCurrentProcess(),
lpThreadAttributes,
dwStackSize,
lpStartAddress,
lpParameter,
dwCreationFlags,
lpThreadId);
}
/* /*
* @implemented * @implemented
*/ */
HANDLE STDCALL HANDLE
CreateThread STDCALL
( CreateRemoteThread(HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, LPVOID lpParameter,
DWORD dwCreationFlags, DWORD dwCreationFlags,
LPDWORD lpThreadId LPDWORD lpThreadId)
)
{ {
return CreateRemoteThread NTSTATUS Status;
( INITIAL_TEB InitialTeb;
NtCurrentProcess(), CONTEXT Context;
lpThreadAttributes, CLIENT_ID ClientId;
dwStackSize, OBJECT_ATTRIBUTES LocalObjectAttributes;
lpStartAddress, POBJECT_ATTRIBUTES ObjectAttributes;
lpParameter, HANDLE hThread;
dwCreationFlags, ULONG Dummy;
lpThreadId
); DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
} ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess,
dwStackSize, lpStartAddress, lpParameter, dwCreationFlags);
/* Clear the Context */
RtlZeroMemory(&Context, sizeof(CONTEXT));
/* Write PID */
ClientId.UniqueProcess = hProcess;
/* Create the Stack */
Status = BasepCreateStack(hProcess,
dwStackSize,
dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
dwStackSize : 0,
&InitialTeb);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return NULL;
}
/* Create Initial Context */
BasepInitializeContext(&Context,
lpParameter,
lpStartAddress,
InitialTeb.StackBase,
1);
/* initialize the attributes for the thread object */
ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
lpThreadAttributes,
NULL);
/* Create the Kernel Thread Object */
Status = NtCreateThread(&hThread,
THREAD_ALL_ACCESS,
ObjectAttributes,
hProcess,
&ClientId,
&Context,
&InitialTeb,
TRUE);
if(!NT_SUCCESS(Status))
{
BasepFreeStack(hProcess, &InitialTeb);
SetLastErrorByStatus(Status);
return NULL;
}
#ifdef SXS_SUPPORT_ENABLED
/* Are we in the same process? */
if (Process = NtCurrentProcess())
{
PTEB Teb;
PVOID ActivationContextStack;
PTHREAD_BASIC_INFORMATION ThreadBasicInfo;
PACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo;
ULONG_PTR Cookie;
/* Get the TEB */
Status = NtQueryInformationThread(hThread,
ThreadBasicIformation,
&ThreadBasicInfo,
sizeof(ThreadBasicInfo),
NULL);
/* Allocate the Activation Context Stack */
Status = RtlAllocateActivationContextStack(&ActivationContextStack);
Teb = ThreadBasicInfo.TebBaseAddress;
/* Save it */
Teb->ActivationContextStackPointer = ActivationContextStack;
/* Query the Context */
Status = RtlQueryInformationActivationContext(1,
0,
NULL,
ActivationContextBasicInformation,
&ActivationCtxInfo,
sizeof(ActivationCtxInfo),
NULL);
/* Does it need to be activated? */
if (!ActivationCtxInfo.hActCtx)
{
/* Activate it */
Status = RtlActivateActivationContextEx(1,
Teb,
ActivationCtxInfo.hActCtx,
&Cookie);
}
}
#endif
/* FIXME: Notify CSR */
/* Success */
if(lpThreadId) *lpThreadId = (DWORD)ClientId.UniqueThread;
/* Resume it if asked */
if (!(dwCreationFlags & CREATE_SUSPENDED))
{
NtResumeThread(hThread, &Dummy);
}
/* Return handle to thread */
return hThread;
}
/* /*
* @implemented * @implemented
*/ */
HANDLE STDCALL VOID
CreateRemoteThread STDCALL
( ExitThread(DWORD uExitCode)
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
)
{ {
HANDLE hThread; NTSTATUS Status;
CLIENT_ID cidClientId; BOOLEAN LastThread;
NTSTATUS nErrCode;
ULONG_PTR nStackReserve; /*
ULONG_PTR nStackCommit; * Terminate process if this is the last thread
OBJECT_ATTRIBUTES oaThreadAttribs; * of the current process
PIMAGE_NT_HEADERS pinhHeader = */
RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); Status = NtQueryInformationThread(NtCurrentThread(),
ThreadAmILastThread,
&LastThread,
sizeof(BOOLEAN),
NULL);
if (NT_SUCCESS(Status) && LastThread)
{
/* Exit the Process */
ExitProcess(uExitCode);
}
DPRINT /* Notify DLLs and TLS Callbacks of termination */
( LdrShutdownThread();
"hProcess %08X\n"
"lpThreadAttributes %08X\n" /* Tell the Kernel to free the Stack */
"dwStackSize %08X\n" NtCurrentTeb()->FreeStackOnTermination = TRUE;
"lpStartAddress %08X\n" NtTerminateThread(NULL, uExitCode);
"lpParameter %08X\n"
"dwCreationFlags %08X\n" /* We will never reach this place. This silences the compiler */
"lpThreadId %08X\n", ExitThread(uExitCode);
hProcess,
lpThreadAttributes,
dwStackSize,
lpStartAddress,
lpParameter,
dwCreationFlags,
lpThreadId
);
/* FIXME: do more checks - e.g. the image may not have an optional header */
if(pinhHeader == NULL)
{
nStackReserve = 0x100000;
nStackCommit = PAGE_SIZE;
}
else
{
nStackReserve = pinhHeader->OptionalHeader.SizeOfStackReserve;
nStackCommit = pinhHeader->OptionalHeader.SizeOfStackCommit;
}
/* FIXME: this should be defined in winbase.h */
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
#endif
/* use defaults */
if(dwStackSize == 0);
/* dwStackSize specifies the size to reserve */
else if(dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION)
nStackReserve = dwStackSize;
/* dwStackSize specifies the size to commit */
else
nStackCommit = dwStackSize;
/* fix the stack reserve size */
if(nStackCommit > nStackReserve)
nStackReserve = ROUNDUP(nStackCommit, 0x100000);
/* initialize the attributes for the thread object */
InitializeObjectAttributes
(
&oaThreadAttribs,
NULL,
0,
NULL,
NULL
);
if(lpThreadAttributes)
{
/* make the handle inheritable */
if(lpThreadAttributes->bInheritHandle)
oaThreadAttribs.Attributes |= OBJ_INHERIT;
/* user-defined security descriptor */
oaThreadAttribs.SecurityDescriptor = lpThreadAttributes->lpSecurityDescriptor;
}
DPRINT
(
"RtlRosCreateUserThreadVa\n"
"(\n"
" ProcessHandle %p,\n"
" ObjectAttributes %p,\n"
" CreateSuspended %d,\n"
" StackZeroBits %d,\n"
" StackReserve %lu,\n"
" StackCommit %lu,\n"
" StartAddress %p,\n"
" ThreadHandle %p,\n"
" ClientId %p,\n"
" ParameterCount %u,\n"
" Parameters[0] %p,\n"
" Parameters[1] %p\n"
")\n",
hProcess,
&oaThreadAttribs,
dwCreationFlags & CREATE_SUSPENDED,
0,
nStackReserve,
nStackCommit,
BaseThreadStartup,
&hThread,
&cidClientId,
2,
lpStartAddress,
lpParameter
);
/* create the thread */
nErrCode = RtlRosCreateUserThreadVa
(
hProcess,
&oaThreadAttribs,
dwCreationFlags & CREATE_SUSPENDED,
0,
&nStackReserve,
&nStackCommit,
(PTHREAD_START_ROUTINE)BaseThreadStartup,
&hThread,
&cidClientId,
2,
lpStartAddress,
lpParameter
);
/* failure */
if(!NT_SUCCESS(nErrCode))
{
SetLastErrorByStatus(nErrCode);
return NULL;
}
DPRINT
(
"StackReserve %p\n"
"StackCommit %p\n"
"ThreadHandle %p\n"
"ClientId.UniqueThread %p\n",
nStackReserve,
nStackCommit,
hThread,
cidClientId.UniqueThread
);
/* success */
if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
return hThread;
} }
/* /*
* @implemented * @implemented
*/ */
@ -330,37 +320,6 @@ GetCurrentThreadId(VOID)
return((DWORD)(NtCurrentTeb()->Cid).UniqueThread); return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
} }
/*
* @implemented
*/
VOID STDCALL
ExitThread(DWORD uExitCode)
{
NTSTATUS Status;
BOOLEAN LastThread;
/*
* Terminate process if this is the last thread
* of the current process
*/
Status = NtQueryInformationThread(NtCurrentThread(),
ThreadAmILastThread,
&LastThread,
sizeof(BOOLEAN),
NULL);
if (NT_SUCCESS(Status) && LastThread == TRUE)
{
ExitProcess(uExitCode);
}
/* FIXME: notify csrss of thread termination */
LdrShutdownThread();
RtlRosExitUserThread(uExitCode);
}
/* /*
* @implemented * @implemented
*/ */

View file

@ -1,483 +1,472 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/process.c * FILE: ntoskrnl/mm/process.c
* PURPOSE: Memory functions related to Processes * PURPOSE: Memory functions related to Processes
* *
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
#include <ntoskrnl.h> #include <ntoskrnl.h>
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
extern ULONG NtMajorVersion; extern ULONG NtMajorVersion;
extern ULONG NtMinorVersion; extern ULONG NtMinorVersion;
extern ULONG NtOSCSDVersion; extern ULONG NtOSCSDVersion;
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
PVOID PVOID
STDCALL STDCALL
MiCreatePebOrTeb(PEPROCESS Process, MiCreatePebOrTeb(PEPROCESS Process,
PVOID BaseAddress) PVOID BaseAddress)
{ {
NTSTATUS Status; NTSTATUS Status;
PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
PMEMORY_AREA MemoryArea; PMEMORY_AREA MemoryArea;
PHYSICAL_ADDRESS BoundaryAddressMultiple; PHYSICAL_ADDRESS BoundaryAddressMultiple;
PVOID AllocatedBase = BaseAddress; PVOID AllocatedBase = BaseAddress;
BoundaryAddressMultiple.QuadPart = 0; BoundaryAddressMultiple.QuadPart = 0;
/* Acquire the Lock */ /* Acquire the Lock */
MmLockAddressSpace(ProcessAddressSpace); MmLockAddressSpace(ProcessAddressSpace);
/* /*
* Create a Peb or Teb. * Create a Peb or Teb.
* Loop until it works, decreasing by PAGE_SIZE each time. The logic here * Loop until it works, decreasing by PAGE_SIZE each time. The logic here
* is that a PEB allocation should never fail since the address is free, * is that a PEB allocation should never fail since the address is free,
* while TEB allocation can fail, and we should simply try the address * while TEB allocation can fail, and we should simply try the address
* below. Is there a nicer way of doing this automagically? (ie: findning) * below. Is there a nicer way of doing this automagically? (ie: findning)
* a gap region? -- Alex * a gap region? -- Alex
*/ */
do { do {
DPRINT("Trying to allocate: %x\n", AllocatedBase); DPRINT("Trying to allocate: %x\n", AllocatedBase);
Status = MmCreateMemoryArea(Process, Status = MmCreateMemoryArea(Process,
ProcessAddressSpace, ProcessAddressSpace,
MEMORY_AREA_PEB_OR_TEB, MEMORY_AREA_PEB_OR_TEB,
&AllocatedBase, &AllocatedBase,
PAGE_SIZE, PAGE_SIZE,
PAGE_READWRITE, PAGE_READWRITE,
&MemoryArea, &MemoryArea,
TRUE, TRUE,
FALSE, FALSE,
BoundaryAddressMultiple); BoundaryAddressMultiple);
AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE); AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);
} while (Status != STATUS_SUCCESS); } while (Status != STATUS_SUCCESS);
/* Initialize the Region */ /* Initialize the Region */
MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead, MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
PAGE_SIZE, PAGE_SIZE,
MEM_COMMIT, MEM_COMMIT,
PAGE_READWRITE); PAGE_READWRITE);
/* Reserve the pages */ /* Reserve the pages */
MmReserveSwapPages(PAGE_SIZE); MmReserveSwapPages(PAGE_SIZE);
/* Unlock Address Space */ /* Unlock Address Space */
DPRINT("Returning\n"); DPRINT("Returning\n");
MmUnlockAddressSpace(ProcessAddressSpace); MmUnlockAddressSpace(ProcessAddressSpace);
return RVA(AllocatedBase, PAGE_SIZE); return RVA(AllocatedBase, PAGE_SIZE);
} }
VOID VOID
MiFreeStackPage(PVOID Context, MiFreeStackPage(PVOID Context,
MEMORY_AREA* MemoryArea, MEMORY_AREA* MemoryArea,
PVOID Address, PVOID Address,
PFN_TYPE Page, PFN_TYPE Page,
SWAPENTRY SwapEntry, SWAPENTRY SwapEntry,
BOOLEAN Dirty) BOOLEAN Dirty)
{ {
ASSERT(SwapEntry == 0); ASSERT(SwapEntry == 0);
if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
} }
VOID VOID
STDCALL STDCALL
MmDeleteKernelStack(PVOID Stack, MmDeleteKernelStack(PVOID Stack,
BOOLEAN GuiStack) BOOLEAN GuiStack)
{ {
/* Lock the Address Space */ /* Lock the Address Space */
MmLockAddressSpace(MmGetKernelAddressSpace()); MmLockAddressSpace(MmGetKernelAddressSpace());
/* Delete the Stack */ /* Delete the Stack */
MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
Stack, Stack,
MiFreeStackPage, MiFreeStackPage,
NULL); NULL);
/* Unlock the Address Space */ /* Unlock the Address Space */
MmUnlockAddressSpace(MmGetKernelAddressSpace()); MmUnlockAddressSpace(MmGetKernelAddressSpace());
} }
VOID VOID
MiFreePebPage(PVOID Context, MiFreePebPage(PVOID Context,
MEMORY_AREA* MemoryArea, MEMORY_AREA* MemoryArea,
PVOID Address, PVOID Address,
PFN_TYPE Page, PFN_TYPE Page,
SWAPENTRY SwapEntry, SWAPENTRY SwapEntry,
BOOLEAN Dirty) BOOLEAN Dirty)
{ {
PEPROCESS Process = (PEPROCESS)Context; PEPROCESS Process = (PEPROCESS)Context;
if (Page != 0) if (Page != 0)
{ {
SWAPENTRY SavedSwapEntry; SWAPENTRY SavedSwapEntry;
SavedSwapEntry = MmGetSavedSwapEntryPage(Page); SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
if (SavedSwapEntry != 0) if (SavedSwapEntry != 0)
{ {
MmFreeSwapPage(SavedSwapEntry); MmFreeSwapPage(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0); MmSetSavedSwapEntryPage(Page, 0);
} }
MmDeleteRmap(Page, Process, Address); MmDeleteRmap(Page, Process, Address);
MmReleasePageMemoryConsumer(MC_USER, Page); MmReleasePageMemoryConsumer(MC_USER, Page);
} }
else if (SwapEntry != 0) else if (SwapEntry != 0)
{ {
MmFreeSwapPage(SwapEntry); MmFreeSwapPage(SwapEntry);
} }
} }
VOID VOID
STDCALL STDCALL
MmDeleteTeb(PEPROCESS Process, MmDeleteTeb(PEPROCESS Process,
PTEB Teb) PTEB Teb)
{ {
PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
/* Lock the Address Space */ /* Lock the Address Space */
MmLockAddressSpace(ProcessAddressSpace); MmLockAddressSpace(ProcessAddressSpace);
/* Delete the Stack */ /* Delete the Stack */
MmFreeMemoryAreaByPtr(ProcessAddressSpace, MmFreeMemoryAreaByPtr(ProcessAddressSpace,
Teb, Teb,
MiFreePebPage, MiFreePebPage,
Process); Process);
/* Unlock the Address Space */ /* Unlock the Address Space */
MmUnlockAddressSpace(ProcessAddressSpace); MmUnlockAddressSpace(ProcessAddressSpace);
} }
PVOID PVOID
STDCALL STDCALL
MmCreateKernelStack(BOOLEAN GuiStack) MmCreateKernelStack(BOOLEAN GuiStack)
{ {
PMEMORY_AREA StackArea; PMEMORY_AREA StackArea;
ULONG i; ULONG i;
PHYSICAL_ADDRESS BoundaryAddressMultiple; PHYSICAL_ADDRESS BoundaryAddressMultiple;
PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE]; PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
PVOID KernelStack = NULL; PVOID KernelStack = NULL;
NTSTATUS Status; NTSTATUS Status;
/* Initialize the Boundary Address */ /* Initialize the Boundary Address */
BoundaryAddressMultiple.QuadPart = 0; BoundaryAddressMultiple.QuadPart = 0;
/* Lock the Kernel Address Space */ /* Lock the Kernel Address Space */
MmLockAddressSpace(MmGetKernelAddressSpace()); MmLockAddressSpace(MmGetKernelAddressSpace());
/* Create a MAREA for the Kernel Stack */ /* Create a MAREA for the Kernel Stack */
Status = MmCreateMemoryArea(NULL, Status = MmCreateMemoryArea(NULL,
MmGetKernelAddressSpace(), MmGetKernelAddressSpace(),
MEMORY_AREA_KERNEL_STACK, MEMORY_AREA_KERNEL_STACK,
&KernelStack, &KernelStack,
MM_STACK_SIZE, MM_STACK_SIZE,
0, 0,
&StackArea, &StackArea,
FALSE, FALSE,
FALSE, FALSE,
BoundaryAddressMultiple); BoundaryAddressMultiple);
/* Unlock the Address Space */ /* Unlock the Address Space */
MmUnlockAddressSpace(MmGetKernelAddressSpace()); MmUnlockAddressSpace(MmGetKernelAddressSpace());
/* Check for Success */ /* Check for Success */
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to create thread stack\n"); DPRINT1("Failed to create thread stack\n");
KEBUGCHECK(0); KEBUGCHECK(0);
} }
/* Mark the Stack in use */ /* Mark the Stack in use */
for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
{ {
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
} }
/* Create a Virtual Mapping for it */ /* Create a Virtual Mapping for it */
Status = MmCreateVirtualMapping(NULL, Status = MmCreateVirtualMapping(NULL,
KernelStack, KernelStack,
PAGE_READWRITE, PAGE_READWRITE,
Page, Page,
MM_STACK_SIZE / PAGE_SIZE); MM_STACK_SIZE / PAGE_SIZE);
/* Check for success */ /* Check for success */
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Could not create Virtual Mapping for Kernel Stack\n"); DPRINT1("Could not create Virtual Mapping for Kernel Stack\n");
KEBUGCHECK(0); KEBUGCHECK(0);
} }
return KernelStack; return KernelStack;
} }
NTSTATUS NTSTATUS
STDCALL STDCALL
MmCreatePeb(PEPROCESS Process) MmCreatePeb(PEPROCESS Process)
{ {
PPEB Peb = NULL; PPEB Peb = NULL;
LARGE_INTEGER SectionOffset; LARGE_INTEGER SectionOffset;
ULONG ViewSize = 0; ULONG ViewSize = 0;
PVOID TableBase = NULL; PVOID TableBase = NULL;
NTSTATUS Status; NTSTATUS Status;
SectionOffset.QuadPart = (ULONGLONG)0; SectionOffset.QuadPart = (ULONGLONG)0;
DPRINT("MmCreatePeb\n"); DPRINT("MmCreatePeb\n");
/* Map NLS Tables */ /* Map NLS Tables */
DPRINT("Mapping NLS\n"); DPRINT("Mapping NLS\n");
Status = MmMapViewOfSection(NlsSectionObject, Status = MmMapViewOfSection(NlsSectionObject,
Process, Process,
&TableBase, &TableBase,
0, 0,
0, 0,
&SectionOffset, &SectionOffset,
&ViewSize, &ViewSize,
ViewShare, ViewShare,
MEM_TOP_DOWN, MEM_TOP_DOWN,
PAGE_READONLY); PAGE_READONLY);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status); DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
return(Status); return(Status);
} }
DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize); DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize);
/* Attach to Process */ /* Attach to Process */
KeAttachProcess(&Process->Pcb); KeAttachProcess(&Process->Pcb);
/* Allocate the PEB */ /* Allocate the PEB */
Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE); Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE);
/* Initialize the PEB */ /* Initialize the PEB */
DPRINT("Allocated: %x\n", Peb); DPRINT("Allocated: %x\n", Peb);
RtlZeroMemory(Peb, sizeof(PEB)); RtlZeroMemory(Peb, sizeof(PEB));
/* Set up data */ /* Set up data */
DPRINT("Setting up PEB\n"); DPRINT("Setting up PEB\n");
Peb->ImageBaseAddress = Process->SectionBaseAddress; Peb->ImageBaseAddress = Process->SectionBaseAddress;
Peb->OSMajorVersion = NtMajorVersion; Peb->OSMajorVersion = NtMajorVersion;
Peb->OSMinorVersion = NtMinorVersion; Peb->OSMinorVersion = NtMinorVersion;
Peb->OSBuildNumber = 2195; Peb->OSBuildNumber = 2195;
Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT; Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT;
Peb->OSCSDVersion = NtOSCSDVersion; Peb->OSCSDVersion = NtOSCSDVersion;
Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset; Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset;
Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset; Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset;
Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset; Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset;
Peb->NumberOfProcessors = KeNumberProcessors; Peb->NumberOfProcessors = KeNumberProcessors;
Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE); Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
Process->Peb = Peb; Process->Peb = Peb;
KeDetachProcess(); KeDetachProcess();
DPRINT("MmCreatePeb: Peb created at %p\n", Peb); DPRINT("MmCreatePeb: Peb created at %p\n", Peb);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
PTEB PTEB
STDCALL STDCALL
MmCreateTeb(PEPROCESS Process, MmCreateTeb(PEPROCESS Process,
PCLIENT_ID ClientId, PCLIENT_ID ClientId,
PINITIAL_TEB InitialTeb) PINITIAL_TEB InitialTeb)
{ {
PTEB Teb; PTEB Teb;
BOOLEAN Attached = FALSE; BOOLEAN Attached = FALSE;
/* Attach to the process */ /* Attach to the process */
DPRINT("MmCreateTeb\n"); DPRINT("MmCreateTeb\n");
if (Process != PsGetCurrentProcess()) if (Process != PsGetCurrentProcess())
{ {
/* Attach to Target */ /* Attach to Target */
KeAttachProcess(&Process->Pcb); KeAttachProcess(&Process->Pcb);
Attached = TRUE; Attached = TRUE;
} }
/* Allocate the TEB */ /* Allocate the TEB */
Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE); Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE);
/* Initialize the PEB */ /* Initialize the PEB */
RtlZeroMemory(Teb, sizeof(TEB)); RtlZeroMemory(Teb, sizeof(TEB));
/* Set TIB Data */ /* Set TIB Data */
Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF; Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF;
Teb->Tib.Version = 1; Teb->Tib.Version = 1;
Teb->Tib.Self = (PNT_TIB)Teb; Teb->Tib.Self = (PNT_TIB)Teb;
/* Set TEB Data */ /* Set TEB Data */
Teb->Cid = *ClientId; Teb->Cid = *ClientId;
Teb->RealClientId = *ClientId; Teb->RealClientId = *ClientId;
Teb->ProcessEnvironmentBlock = Process->Peb; Teb->ProcessEnvironmentBlock = Process->Peb;
Teb->CurrentLocale = PsDefaultThreadLocaleId; Teb->CurrentLocale = PsDefaultThreadLocaleId;
/* Store stack information from InitialTeb */ /* Store stack information from InitialTeb */
if(InitialTeb != NULL) if(InitialTeb != NULL)
{ {
/* fixed-size stack */ Teb->Tib.StackBase = InitialTeb->StackBase;
if(InitialTeb->PreviousStackBase && InitialTeb->PreviousStackLimit) Teb->Tib.StackLimit = InitialTeb->StackLimit;
{ Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
Teb->Tib.StackBase = InitialTeb->PreviousStackBase; }
Teb->Tib.StackLimit = InitialTeb->PreviousStackLimit;
Teb->DeallocationStack = InitialTeb->PreviousStackLimit; /* Return TEB Address */
} DPRINT("Allocated: %x\n", Teb);
/* expandable stack */ if (Attached) KeDetachProcess();
else return Teb;
{ }
Teb->Tib.StackBase = InitialTeb->StackBase;
Teb->Tib.StackLimit = InitialTeb->StackLimit; NTSTATUS
Teb->DeallocationStack = InitialTeb->AllocatedStackBase; STDCALL
} MmCreateProcessAddressSpace(IN PEPROCESS Process,
} IN PSECTION_OBJECT Section OPTIONAL)
{
/* Return TEB Address */ NTSTATUS Status;
DPRINT("Allocated: %x\n", Teb); PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace;
if (Attached) KeDetachProcess(); PVOID BaseAddress;
return Teb; PMEMORY_AREA MemoryArea;
} PHYSICAL_ADDRESS BoundaryAddressMultiple;
ULONG ViewSize = 0;
NTSTATUS PVOID ImageBase = 0;
STDCALL BoundaryAddressMultiple.QuadPart = 0;
MmCreateProcessAddressSpace(IN PEPROCESS Process,
IN PSECTION_OBJECT Section OPTIONAL) /* Initialize the Addresss Space */
{ MmInitializeAddressSpace(Process, ProcessAddressSpace);
NTSTATUS Status;
PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; /* Acquire the Lock */
PVOID BaseAddress; MmLockAddressSpace(ProcessAddressSpace);
PMEMORY_AREA MemoryArea;
PHYSICAL_ADDRESS BoundaryAddressMultiple; /* Protect the highest 64KB of the process address space */
ULONG ViewSize = 0; BaseAddress = (PVOID)MmUserProbeAddress;
PVOID ImageBase = 0; Status = MmCreateMemoryArea(Process,
BoundaryAddressMultiple.QuadPart = 0; ProcessAddressSpace,
MEMORY_AREA_NO_ACCESS,
/* Initialize the Addresss Space */ &BaseAddress,
MmInitializeAddressSpace(Process, ProcessAddressSpace); 0x10000,
PAGE_NOACCESS,
/* Acquire the Lock */ &MemoryArea,
MmLockAddressSpace(ProcessAddressSpace); FALSE,
FALSE,
/* Protect the highest 64KB of the process address space */ BoundaryAddressMultiple);
BaseAddress = (PVOID)MmUserProbeAddress; if (!NT_SUCCESS(Status))
Status = MmCreateMemoryArea(Process, {
ProcessAddressSpace, DPRINT1("Failed to protect last 64KB\n");
MEMORY_AREA_NO_ACCESS, goto exit;
&BaseAddress, }
0x10000,
PAGE_NOACCESS, /* Protect the 60KB above the shared user page */
&MemoryArea, BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE;
FALSE, Status = MmCreateMemoryArea(Process,
FALSE, ProcessAddressSpace,
BoundaryAddressMultiple); MEMORY_AREA_NO_ACCESS,
if (!NT_SUCCESS(Status)) &BaseAddress,
{ 0x10000 - PAGE_SIZE,
DPRINT1("Failed to protect last 64KB\n"); PAGE_NOACCESS,
goto exit; &MemoryArea,
} FALSE,
FALSE,
/* Protect the 60KB above the shared user page */ BoundaryAddressMultiple);
BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE; if (!NT_SUCCESS(Status))
Status = MmCreateMemoryArea(Process, {
ProcessAddressSpace, DPRINT1("Failed to protect the memory above the shared user page\n");
MEMORY_AREA_NO_ACCESS, goto exit;
&BaseAddress, }
0x10000 - PAGE_SIZE,
PAGE_NOACCESS, /* Create the shared data page */
&MemoryArea, BaseAddress = (PVOID)USER_SHARED_DATA;
FALSE, Status = MmCreateMemoryArea(Process,
FALSE, ProcessAddressSpace,
BoundaryAddressMultiple); MEMORY_AREA_SHARED_DATA,
if (!NT_SUCCESS(Status)) &BaseAddress,
{ PAGE_SIZE,
DPRINT1("Failed to protect the memory above the shared user page\n"); PAGE_READONLY,
goto exit; &MemoryArea,
} FALSE,
FALSE,
/* Create the shared data page */ BoundaryAddressMultiple);
BaseAddress = (PVOID)USER_SHARED_DATA; if (!NT_SUCCESS(Status))
Status = MmCreateMemoryArea(Process, {
ProcessAddressSpace, DPRINT1("Failed to create Shared User Data\n");
MEMORY_AREA_SHARED_DATA, goto exit;
&BaseAddress, }
PAGE_SIZE,
PAGE_READONLY, /* Check if there's a Section Object */
&MemoryArea, if (Section)
FALSE, {
FALSE, UNICODE_STRING FileName;
BoundaryAddressMultiple); PWCHAR szSrc;
if (!NT_SUCCESS(Status)) PCHAR szDest;
{ USHORT lnFName = 0;
DPRINT1("Failed to create Shared User Data\n");
goto exit; /* Unlock the Address Space */
} DPRINT("Unlocking\n");
MmUnlockAddressSpace(ProcessAddressSpace);
/* Check if there's a Section Object */
if (Section) DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n",
{ Section, Process, &ImageBase);
UNICODE_STRING FileName; Status = MmMapViewOfSection(Section,
PWCHAR szSrc; Process,
PCHAR szDest; (PVOID*)&ImageBase,
USHORT lnFName = 0; 0,
0,
/* Unlock the Address Space */ NULL,
DPRINT("Unlocking\n"); &ViewSize,
MmUnlockAddressSpace(ProcessAddressSpace); 0,
MEM_COMMIT,
DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n", PAGE_READWRITE);
Section, Process, &ImageBase); if (!NT_SUCCESS(Status))
Status = MmMapViewOfSection(Section, {
Process, DPRINT1("Failed to map process Image\n");
(PVOID*)&ImageBase, ObDereferenceObject(Section);
0, goto exit;
0, }
NULL, ObDereferenceObject(Section);
&ViewSize,
0, /* Save the pointer */
MEM_COMMIT, Process->SectionBaseAddress = ImageBase;
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) /* Determine the image file name and save it to EPROCESS */
{ DPRINT("Getting Image name\n");
DPRINT1("Failed to map process Image\n"); FileName = Section->FileObject->FileName;
ObDereferenceObject(Section); szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1);
goto exit;
} while(szSrc >= FileName.Buffer)
ObDereferenceObject(Section); {
if(*szSrc == L'\\')
/* Save the pointer */ {
Process->SectionBaseAddress = ImageBase; szSrc++;
break;
/* Determine the image file name and save it to EPROCESS */ }
DPRINT("Getting Image name\n"); else
FileName = Section->FileObject->FileName; {
szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1); szSrc--;
lnFName++;
while(szSrc >= FileName.Buffer) }
{ }
if(*szSrc == L'\\')
{ /* Copy the to the process and truncate it to 15 characters if necessary */
szSrc++; DPRINT("Copying and truncating\n");
break; szDest = Process->ImageFileName;
} lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
else while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++);
{
szSrc--; /* Return status to caller */
lnFName++; return Status;
} }
}
exit:
/* Copy the to the process and truncate it to 15 characters if necessary */ /* Unlock the Address Space */
DPRINT("Copying and truncating\n"); DPRINT("Unlocking\n");
szDest = Process->ImageFileName; MmUnlockAddressSpace(ProcessAddressSpace);
lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1);
while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++); /* Return status to caller */
return Status;
/* Return status to caller */ }
return Status;
}
exit:
/* Unlock the Address Space */
DPRINT("Unlocking\n");
MmUnlockAddressSpace(ProcessAddressSpace);
/* Return status to caller */
return Status;
}