mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 02:13:29 +00:00
![Hermès Bélusca-Maïto](/assets/img/avatar_default.png)
- kernel32!BaseCreateStack() is compatible with ntdll!RtlpCreateUserStack().
- When checking whether a stack guard page can be added, its size has to
be accounted for in the checking logic.
- We have to satisfy the PEB::MinimumStackCommit constraint.
- We cannot use PEB::GuaranteedStackBytes in BaseCreateStack() since it is
nowhere initialized (default is 0). It gets initialized to a non-zero
value when the user manually calls SetThreadStackGuarantee().
https://www.installsetupconfig.com/win32programming/windowsthreadsprocessapis7_6.html
- RtlpCreateUserStack(): Fix memory leak in failure case.
- RtlpFreeUserStack() doesn't need to return anything.
See also commit 1bc59379
(r59868).
CORE-11319
953 lines
26 KiB
C
953 lines
26 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: dll/win32/kernel32/client/utils.c
|
|
* PURPOSE: Utility and Support Functions
|
|
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
|
* Pierre Schweitzer (pierre.schweitzer@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <k32.h>
|
|
#ifdef _M_IX86
|
|
#include "i386/ketypes.h"
|
|
#elif defined _M_AMD64
|
|
#include "amd64/ketypes.h"
|
|
#endif
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
UNICODE_STRING Restricted = RTL_CONSTANT_STRING(L"Restricted");
|
|
BOOL bIsFileApiAnsi = TRUE; // set the file api to ansi or oem
|
|
PRTL_CONVERT_STRING Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
|
|
PRTL_CONVERT_STRINGA BasepUnicodeStringTo8BitString = RtlUnicodeStringToAnsiString;
|
|
PRTL_COUNT_STRING BasepUnicodeStringTo8BitSize = BasepUnicodeStringToAnsiSize;
|
|
PRTL_COUNT_STRINGA Basep8BitStringToUnicodeSize = BasepAnsiStringToUnicodeSize;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
ULONG
|
|
NTAPI
|
|
BasepUnicodeStringToOemSize(IN PUNICODE_STRING String)
|
|
{
|
|
return RtlUnicodeStringToOemSize(String);
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
BasepOemStringToUnicodeSize(IN PANSI_STRING String)
|
|
{
|
|
return RtlOemStringToUnicodeSize(String);
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
BasepUnicodeStringToAnsiSize(IN PUNICODE_STRING String)
|
|
{
|
|
return RtlUnicodeStringToAnsiSize(String);
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
BasepAnsiStringToUnicodeSize(IN PANSI_STRING String)
|
|
{
|
|
return RtlAnsiStringToUnicodeSize(String);
|
|
}
|
|
|
|
HANDLE
|
|
WINAPI
|
|
BaseGetNamedObjectDirectory(VOID)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS Status;
|
|
HANDLE DirHandle, BnoHandle, Token, NewToken;
|
|
|
|
if (BaseNamedObjectDirectory) return BaseNamedObjectDirectory;
|
|
|
|
if (NtCurrentTeb()->IsImpersonating)
|
|
{
|
|
Status = NtOpenThreadToken(NtCurrentThread(),
|
|
TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&Token);
|
|
if (!NT_SUCCESS(Status)) return BaseNamedObjectDirectory;
|
|
|
|
NewToken = NULL;
|
|
Status = NtSetInformationThread(NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
&NewToken,
|
|
sizeof(HANDLE));
|
|
if (!NT_SUCCESS (Status))
|
|
{
|
|
NtClose(Token);
|
|
return BaseNamedObjectDirectory;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Token = NULL;
|
|
}
|
|
|
|
RtlAcquirePebLock();
|
|
if (BaseNamedObjectDirectory) goto Quickie;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&BaseStaticServerData->NamedObjectDirectory,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenDirectoryObject(&BnoHandle,
|
|
DIRECTORY_QUERY |
|
|
DIRECTORY_TRAVERSE |
|
|
DIRECTORY_CREATE_OBJECT |
|
|
DIRECTORY_CREATE_SUBDIRECTORY,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = NtOpenDirectoryObject(&DirHandle,
|
|
DIRECTORY_TRAVERSE,
|
|
&ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
(PUNICODE_STRING)&Restricted,
|
|
OBJ_CASE_INSENSITIVE,
|
|
DirHandle,
|
|
NULL);
|
|
|
|
Status = NtOpenDirectoryObject(&BnoHandle,
|
|
DIRECTORY_QUERY |
|
|
DIRECTORY_TRAVERSE |
|
|
DIRECTORY_CREATE_OBJECT |
|
|
DIRECTORY_CREATE_SUBDIRECTORY,
|
|
&ObjectAttributes);
|
|
NtClose(DirHandle);
|
|
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) BaseNamedObjectDirectory = BnoHandle;
|
|
|
|
Quickie:
|
|
|
|
RtlReleasePebLock();
|
|
|
|
if (Token)
|
|
{
|
|
NtSetInformationThread(NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
&Token,
|
|
sizeof(Token));
|
|
|
|
NtClose(Token);
|
|
}
|
|
|
|
return BaseNamedObjectDirectory;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry,
|
|
IN PVOID Context,
|
|
OUT BOOLEAN *StopEnumeration)
|
|
{
|
|
/* Make sure we get Entry, Context and valid StopEnumeration pointer */
|
|
ASSERT(Entry);
|
|
ASSERT(Context);
|
|
ASSERT(StopEnumeration);
|
|
|
|
/* If entry is already found - signal to stop */
|
|
if (BasepExeLdrEntry)
|
|
{
|
|
*StopEnumeration = TRUE;
|
|
return;
|
|
}
|
|
|
|
/* Otherwise keep enumerating until we find a match */
|
|
if (Entry->DllBase == Context)
|
|
{
|
|
/* It matches, so remember the ldr entry */
|
|
BasepExeLdrEntry = Entry;
|
|
|
|
/* And stop enumeration */
|
|
*StopEnumeration = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Converts an ANSI or OEM String to the TEB StaticUnicodeString
|
|
*/
|
|
PUNICODE_STRING
|
|
WINAPI
|
|
Basep8BitStringToStaticUnicodeString(IN LPCSTR String)
|
|
{
|
|
PUNICODE_STRING StaticString = &(NtCurrentTeb()->StaticUnicodeString);
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
/* Initialize an ANSI String */
|
|
Status = RtlInitAnsiStringEx(&AnsiString, String);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
/* Convert it */
|
|
Status = Basep8BitStringToUnicodeString(StaticString, &AnsiString, FALSE);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) return StaticString;
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
}
|
|
else
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Allocates space from the Heap and converts an Unicode String into it
|
|
*/
|
|
BOOLEAN
|
|
WINAPI
|
|
Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString,
|
|
IN LPCSTR String)
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
NTSTATUS Status;
|
|
|
|
/* Initialize an ANSI String */
|
|
Status = RtlInitAnsiStringEx(&AnsiString, String);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
/* Convert it */
|
|
Status = Basep8BitStringToUnicodeString(UnicodeString, &AnsiString, TRUE);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) return TRUE;
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
SetLastError(ERROR_FILENAME_EXCED_RANGE);
|
|
}
|
|
else
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Allocates space from the Heap and converts an Ansi String into it
|
|
*/
|
|
/*NOTE: API IS A HACK */
|
|
VOID
|
|
WINAPI
|
|
BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString,
|
|
OUT LPWSTR* UnicodeString)
|
|
{
|
|
ANSI_STRING AnsiTemp;
|
|
UNICODE_STRING UnicodeTemp;
|
|
|
|
DPRINT("BasepAnsiStringToHeapUnicodeString\n");
|
|
|
|
/* First create the ANSI_STRING */
|
|
RtlInitAnsiString(&AnsiTemp, AnsiString);
|
|
|
|
if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeTemp,
|
|
&AnsiTemp,
|
|
TRUE)))
|
|
{
|
|
*UnicodeString = UnicodeTemp.Buffer;
|
|
}
|
|
else
|
|
{
|
|
*UnicodeString = NULL;
|
|
}
|
|
}
|
|
|
|
PLARGE_INTEGER
|
|
WINAPI
|
|
BaseFormatTimeOut(OUT PLARGE_INTEGER Timeout,
|
|
IN DWORD dwMilliseconds)
|
|
{
|
|
/* Check if this is an infinite wait, which means no timeout argument */
|
|
if (dwMilliseconds == INFINITE) return NULL;
|
|
|
|
/* Otherwise, convert the time to NT Format */
|
|
Timeout->QuadPart = dwMilliseconds * -10000LL;
|
|
return Timeout;
|
|
}
|
|
|
|
/*
|
|
* Converts lpSecurityAttributes + Object Name into ObjectAttributes.
|
|
*/
|
|
POBJECT_ATTRIBUTES
|
|
WINAPI
|
|
BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL,
|
|
IN PUNICODE_STRING ObjectName)
|
|
{
|
|
ULONG Attributes;
|
|
HANDLE RootDirectory;
|
|
PVOID SecurityDescriptor;
|
|
DPRINT("BaseFormatObjectAttributes. Security: %p, Name: %p\n",
|
|
SecurityAttributes, ObjectName);
|
|
|
|
/* Get the attributes if present */
|
|
if (SecurityAttributes)
|
|
{
|
|
Attributes = SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0;
|
|
SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
|
|
}
|
|
else
|
|
{
|
|
if (!ObjectName) return NULL;
|
|
Attributes = 0;
|
|
SecurityDescriptor = NULL;
|
|
}
|
|
|
|
if (ObjectName)
|
|
{
|
|
Attributes |= OBJ_OPENIF;
|
|
RootDirectory = BaseGetNamedObjectDirectory();
|
|
}
|
|
else
|
|
{
|
|
RootDirectory = NULL;
|
|
}
|
|
|
|
/* Create the Object Attributes */
|
|
InitializeObjectAttributes(ObjectAttributes,
|
|
ObjectName,
|
|
Attributes,
|
|
RootDirectory,
|
|
SecurityDescriptor);
|
|
DPRINT("Attributes: %lx, RootDirectory: %p, SecurityDescriptor: %p\n",
|
|
Attributes, RootDirectory, SecurityDescriptor);
|
|
return ObjectAttributes;
|
|
}
|
|
|
|
/*
|
|
* Creates a stack for a thread or fiber.
|
|
* NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpCreateUserStack().
|
|
*/
|
|
NTSTATUS
|
|
WINAPI
|
|
BaseCreateStack(
|
|
_In_ HANDLE hProcess,
|
|
_In_opt_ SIZE_T StackCommit,
|
|
_In_opt_ SIZE_T StackReserve,
|
|
_Out_ PINITIAL_TEB InitialTeb)
|
|
{
|
|
NTSTATUS Status;
|
|
PIMAGE_NT_HEADERS Headers;
|
|
ULONG_PTR Stack;
|
|
BOOLEAN UseGuard;
|
|
ULONG PageSize, AllocationGranularity, Dummy;
|
|
SIZE_T MinimumStackCommit, GuardPageSize;
|
|
|
|
DPRINT("BaseCreateStack(hProcess: 0x%p, Max: 0x%lx, Current: 0x%lx)\n",
|
|
hProcess, StackReserve, StackCommit);
|
|
|
|
/* Read page size */
|
|
PageSize = BaseStaticServerData->SysInfo.PageSize;
|
|
AllocationGranularity = BaseStaticServerData->SysInfo.AllocationGranularity;
|
|
|
|
/* Get the Image Headers */
|
|
Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
|
|
if (!Headers) return STATUS_INVALID_IMAGE_FORMAT;
|
|
|
|
if (StackReserve == 0)
|
|
StackReserve = Headers->OptionalHeader.SizeOfStackReserve;
|
|
|
|
if (StackCommit == 0)
|
|
{
|
|
StackCommit = Headers->OptionalHeader.SizeOfStackCommit;
|
|
}
|
|
/* Check if the commit is higher than the reserve */
|
|
else if (StackCommit >= StackReserve)
|
|
{
|
|
/* Grow the reserve beyond the commit, up to 1MB alignment */
|
|
StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
|
|
}
|
|
|
|
/* Align everything to Page Size */
|
|
StackCommit = ROUND_UP(StackCommit, PageSize);
|
|
StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
|
|
|
|
MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit;
|
|
if ((MinimumStackCommit != 0) && (StackCommit < MinimumStackCommit))
|
|
{
|
|
StackCommit = MinimumStackCommit;
|
|
}
|
|
|
|
/* Check if the commit is higher than the reserve */
|
|
if (StackCommit >= StackReserve)
|
|
{
|
|
/* Grow the reserve beyond the commit, up to 1MB alignment */
|
|
StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
|
|
}
|
|
|
|
/* Align everything to Page Size */
|
|
StackCommit = ROUND_UP(StackCommit, PageSize);
|
|
StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
|
|
|
|
/* Reserve memory for the stack */
|
|
Stack = 0;
|
|
Status = NtAllocateVirtualMemory(hProcess,
|
|
(PVOID*)&Stack,
|
|
0,
|
|
&StackReserve,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failure to reserve stack: %lx\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Now set up some basic Initial TEB Parameters */
|
|
InitialTeb->AllocatedStackBase = (PVOID)Stack;
|
|
InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
|
|
InitialTeb->PreviousStackBase = NULL;
|
|
InitialTeb->PreviousStackLimit = NULL;
|
|
|
|
/* Update the stack position */
|
|
Stack += StackReserve - StackCommit;
|
|
|
|
/* Check if we can add a guard page */
|
|
if (StackReserve >= StackCommit + PageSize)
|
|
{
|
|
Stack -= PageSize;
|
|
StackCommit += PageSize;
|
|
UseGuard = TRUE;
|
|
}
|
|
else
|
|
{
|
|
UseGuard = FALSE;
|
|
}
|
|
|
|
/* Allocate memory for the stack */
|
|
Status = NtAllocateVirtualMemory(hProcess,
|
|
(PVOID*)&Stack,
|
|
0,
|
|
&StackCommit,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failure to allocate stack\n");
|
|
GuardPageSize = 0;
|
|
NtFreeVirtualMemory(hProcess, (PVOID*)&Stack, &GuardPageSize, MEM_RELEASE);
|
|
return Status;
|
|
}
|
|
|
|
/* Now set the current Stack Limit */
|
|
InitialTeb->StackLimit = (PVOID)Stack;
|
|
|
|
/* Create a guard page if needed */
|
|
if (UseGuard)
|
|
{
|
|
GuardPageSize = PageSize;
|
|
Status = NtProtectVirtualMemory(hProcess,
|
|
(PVOID*)&Stack,
|
|
&GuardPageSize,
|
|
PAGE_GUARD | PAGE_READWRITE,
|
|
&Dummy);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failure to set guard page\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Update the Stack Limit keeping in mind the Guard Page */
|
|
InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit +
|
|
GuardPageSize);
|
|
}
|
|
|
|
/* We are done! */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpFreeUserStack().
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
BaseFreeThreadStack(
|
|
_In_ HANDLE hProcess,
|
|
_In_ PINITIAL_TEB InitialTeb)
|
|
{
|
|
SIZE_T Dummy = 0;
|
|
|
|
/* Free the Stack */
|
|
NtFreeVirtualMemory(hProcess,
|
|
&InitialTeb->AllocatedStackBase,
|
|
&Dummy,
|
|
MEM_RELEASE);
|
|
}
|
|
|
|
/*
|
|
* Creates the Initial Context for a Thread or Fiber
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
BaseInitializeContext(IN PCONTEXT Context,
|
|
IN PVOID Parameter,
|
|
IN PVOID StartAddress,
|
|
IN PVOID StackAddress,
|
|
IN ULONG ContextType)
|
|
{
|
|
#ifdef _M_IX86
|
|
ULONG ContextFlags;
|
|
DPRINT("BaseInitializeContext: %p\n", Context);
|
|
|
|
/* Setup the Initial Win32 Thread Context */
|
|
Context->Eax = (ULONG)StartAddress;
|
|
Context->Ebx = (ULONG)Parameter;
|
|
Context->Esp = (ULONG)StackAddress;
|
|
/* The other registers are undefined */
|
|
|
|
/* Setup the Segments */
|
|
Context->SegFs = KGDT_R3_TEB;
|
|
Context->SegEs = KGDT_R3_DATA;
|
|
Context->SegDs = KGDT_R3_DATA;
|
|
Context->SegCs = KGDT_R3_CODE;
|
|
Context->SegSs = KGDT_R3_DATA;
|
|
Context->SegGs = 0;
|
|
|
|
/* Set the Context Flags */
|
|
ContextFlags = Context->ContextFlags;
|
|
Context->ContextFlags = CONTEXT_FULL;
|
|
|
|
/* Give it some room for the Parameter */
|
|
Context->Esp -= sizeof(PVOID);
|
|
|
|
/* Set the EFLAGS */
|
|
Context->EFlags = 0x3000; /* IOPL 3 */
|
|
|
|
/* What kind of context is being created? */
|
|
if (ContextType == 1)
|
|
{
|
|
/* For Threads */
|
|
Context->Eip = (ULONG)BaseThreadStartupThunk;
|
|
}
|
|
else if (ContextType == 2)
|
|
{
|
|
/* This is a fiber: make space for the return address */
|
|
Context->Esp -= sizeof(PVOID);
|
|
*((PVOID*)Context->Esp) = BaseFiberStartup;
|
|
|
|
/* Is FPU state required? */
|
|
Context->ContextFlags |= ContextFlags;
|
|
if ((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
|
|
{
|
|
/* Set an initial state */
|
|
Context->FloatSave.ControlWord = 0x27F;
|
|
Context->FloatSave.StatusWord = 0;
|
|
Context->FloatSave.TagWord = 0xFFFF;
|
|
Context->FloatSave.ErrorOffset = 0;
|
|
Context->FloatSave.ErrorSelector = 0;
|
|
Context->FloatSave.DataOffset = 0;
|
|
Context->FloatSave.DataSelector = 0;
|
|
if (SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE])
|
|
Context->Dr6 = 0x1F80;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* For first thread in a Process */
|
|
Context->Eip = (ULONG)BaseProcessStartThunk;
|
|
}
|
|
|
|
#elif defined(_M_AMD64)
|
|
DPRINT("BaseInitializeContext: %p\n", Context);
|
|
|
|
/* Setup the Initial Win32 Thread Context */
|
|
Context->Rax = (ULONG_PTR)StartAddress;
|
|
Context->Rbx = (ULONG_PTR)Parameter;
|
|
Context->Rsp = (ULONG_PTR)StackAddress;
|
|
/* The other registers are undefined */
|
|
|
|
/* Setup the Segments */
|
|
Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegCs = KGDT64_R3_CODE | RPL_MASK;
|
|
Context->SegSs = KGDT64_R3_DATA | RPL_MASK;
|
|
Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
|
|
|
|
/* Set the EFLAGS */
|
|
Context->EFlags = 0x3000; /* IOPL 3 */
|
|
|
|
if (ContextType == 1) /* For Threads */
|
|
{
|
|
Context->Rip = (ULONG_PTR)BaseThreadStartupThunk;
|
|
}
|
|
else if (ContextType == 2) /* For Fibers */
|
|
{
|
|
Context->Rip = (ULONG_PTR)BaseFiberStartup;
|
|
}
|
|
else /* For first thread in a Process */
|
|
{
|
|
Context->Rip = (ULONG_PTR)BaseProcessStartThunk;
|
|
}
|
|
|
|
/* Set the Context Flags */
|
|
Context->ContextFlags = CONTEXT_FULL;
|
|
|
|
/* Give it some room for the Parameter */
|
|
Context->Rsp -= sizeof(PVOID);
|
|
#elif defined(_M_ARM)
|
|
DPRINT("BaseInitializeContext: %p\n", Context);
|
|
|
|
// FIXME: check if this is correct!
|
|
/* Setup the Initial Win32 Thread Context */
|
|
Context->R0 = (ULONG_PTR)StartAddress;
|
|
Context->R1 = (ULONG_PTR)Parameter;
|
|
Context->Sp = (ULONG_PTR)StackAddress;
|
|
|
|
if (ContextType == 1) /* For Threads */
|
|
{
|
|
Context->Pc = (ULONG_PTR)BaseThreadStartupThunk;
|
|
}
|
|
else if (ContextType == 2) /* For Fibers */
|
|
{
|
|
Context->Pc = (ULONG_PTR)BaseFiberStartup;
|
|
}
|
|
else /* For first thread in a Process */
|
|
{
|
|
Context->Pc = (ULONG_PTR)BaseProcessStartThunk;
|
|
}
|
|
|
|
/* Set the Context Flags */
|
|
Context->ContextFlags = CONTEXT_FULL;
|
|
|
|
/* Give it some room for the Parameter */
|
|
Context->Sp -= sizeof(PVOID);
|
|
#else
|
|
#warning Unknown architecture
|
|
UNIMPLEMENTED;
|
|
DbgBreakPoint();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Checks if the privilege for Real-Time Priority is there
|
|
* Beware about this function behavior:
|
|
* - In case Keep is set to FALSE, then the function will only check
|
|
* whether real time is allowed and won't grant the privilege. In that case
|
|
* it will return TRUE if allowed, FALSE otherwise. Not a state!
|
|
* It means you don't have to release privilege when calling with FALSE.
|
|
*/
|
|
PVOID
|
|
WINAPI
|
|
BasepIsRealtimeAllowed(IN BOOLEAN Keep)
|
|
{
|
|
ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE;
|
|
PVOID State;
|
|
NTSTATUS Status;
|
|
|
|
Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
|
|
if (!NT_SUCCESS(Status)) return NULL;
|
|
|
|
if (!Keep)
|
|
{
|
|
RtlReleasePrivilege(State);
|
|
State = (PVOID)TRUE;
|
|
}
|
|
|
|
return State;
|
|
}
|
|
|
|
/*
|
|
* Maps an image file into a section
|
|
*/
|
|
NTSTATUS
|
|
WINAPI
|
|
BasepMapFile(IN LPCWSTR lpApplicationName,
|
|
OUT PHANDLE hSection,
|
|
IN PUNICODE_STRING ApplicationName)
|
|
{
|
|
RTL_RELATIVE_NAME_U RelativeName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS Status;
|
|
HANDLE hFile = NULL;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
DPRINT("BasepMapFile\n");
|
|
|
|
/* Zero out the Relative Directory */
|
|
RelativeName.ContainingDirectory = NULL;
|
|
|
|
/* Find the application name */
|
|
if (!RtlDosPathNameToNtPathName_U(lpApplicationName,
|
|
ApplicationName,
|
|
NULL,
|
|
&RelativeName))
|
|
{
|
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|
}
|
|
|
|
DPRINT("ApplicationName %wZ\n", ApplicationName);
|
|
DPRINT("RelativeName %wZ\n", &RelativeName.RelativeName);
|
|
|
|
/* Did we get a relative name? */
|
|
if (RelativeName.RelativeName.Length)
|
|
{
|
|
ApplicationName = &RelativeName.RelativeName;
|
|
}
|
|
|
|
/* Initialize the Object Attributes */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
ApplicationName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
RelativeName.ContainingDirectory,
|
|
NULL);
|
|
|
|
/* 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))
|
|
{
|
|
DPRINT1("Failed to open file\n");
|
|
BaseSetLastNTError(Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Create a section for this file */
|
|
Status = NtCreateSection(hSection,
|
|
SECTION_ALL_ACCESS,
|
|
NULL,
|
|
NULL,
|
|
PAGE_EXECUTE,
|
|
SEC_IMAGE,
|
|
hFile);
|
|
NtClose(hFile);
|
|
|
|
/* Return status */
|
|
DPRINT("Section: %p for file: %p\n", *hSection, hFile);
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
WINAPI
|
|
Wow64EnableWow64FsRedirection(IN BOOLEAN Wow64EnableWow64FsRedirection)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOL Result;
|
|
|
|
Status = RtlWow64EnableFsRedirection(Wow64EnableWow64FsRedirection);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
Result = FALSE;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
Wow64DisableWow64FsRedirection(IN PVOID *OldValue)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOL Result;
|
|
|
|
Status = RtlWow64EnableFsRedirectionEx((PVOID)TRUE, OldValue);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
Result = FALSE;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
Wow64RevertWow64FsRedirection(IN PVOID OldValue)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOL Result;
|
|
|
|
Status = RtlWow64EnableFsRedirectionEx(OldValue, &OldValue);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
BaseSetLastNTError(Status);
|
|
Result = FALSE;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
SetFileApisToOEM(VOID)
|
|
{
|
|
/* Set the correct Base Api */
|
|
Basep8BitStringToUnicodeString = (PRTL_CONVERT_STRING)RtlOemStringToUnicodeString;
|
|
BasepUnicodeStringTo8BitString = RtlUnicodeStringToOemString;
|
|
BasepUnicodeStringTo8BitSize = BasepUnicodeStringToOemSize;
|
|
Basep8BitStringToUnicodeSize = BasepOemStringToUnicodeSize;
|
|
|
|
/* FIXME: Old, deprecated way */
|
|
bIsFileApiAnsi = FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
SetFileApisToANSI(VOID)
|
|
{
|
|
/* Set the correct Base Api */
|
|
Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
|
|
BasepUnicodeStringTo8BitString = RtlUnicodeStringToAnsiString;
|
|
BasepUnicodeStringTo8BitSize = BasepUnicodeStringToAnsiSize;
|
|
Basep8BitStringToUnicodeSize = BasepAnsiStringToUnicodeSize;
|
|
|
|
/* FIXME: Old, deprecated way */
|
|
bIsFileApiAnsi = TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
AreFileApisANSI(VOID)
|
|
{
|
|
return Basep8BitStringToUnicodeString == RtlAnsiStringToUnicodeString;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
BaseMarkFileForDelete(IN HANDLE FileHandle,
|
|
IN ULONG FileAttributes)
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_BASIC_INFORMATION FileBasicInfo;
|
|
FILE_DISPOSITION_INFORMATION FileDispositionInfo;
|
|
|
|
/* If no attributes were given, get them */
|
|
if (!FileAttributes)
|
|
{
|
|
FileBasicInfo.FileAttributes = 0;
|
|
NtQueryInformationFile(FileHandle,
|
|
&IoStatusBlock,
|
|
&FileBasicInfo,
|
|
sizeof(FileBasicInfo),
|
|
FileBasicInformation);
|
|
FileAttributes = FileBasicInfo.FileAttributes;
|
|
}
|
|
|
|
/* If file is marked as RO, reset its attributes */
|
|
if (FileAttributes & FILE_ATTRIBUTE_READONLY)
|
|
{
|
|
RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
|
|
FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
NtSetInformationFile(FileHandle,
|
|
&IoStatusBlock,
|
|
&FileBasicInfo,
|
|
sizeof(FileBasicInfo),
|
|
FileBasicInformation);
|
|
}
|
|
|
|
/* Finally, mark the file for deletion */
|
|
FileDispositionInfo.DeleteFile = TRUE;
|
|
NtSetInformationFile(FileHandle,
|
|
&IoStatusBlock,
|
|
&FileDispositionInfo,
|
|
sizeof(FileDispositionInfo),
|
|
FileDispositionInformation);
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
WINAPI
|
|
BasepCheckWinSaferRestrictions(IN HANDLE UserToken,
|
|
IN LPWSTR ApplicationName,
|
|
IN HANDLE FileHandle,
|
|
OUT PBOOLEAN InJob,
|
|
OUT PHANDLE NewToken,
|
|
OUT PHANDLE JobHandle)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Validate that there's a name */
|
|
if ((ApplicationName) && *(ApplicationName))
|
|
{
|
|
/* Validate that the required output parameters are there */
|
|
if ((InJob) && (NewToken) && (JobHandle))
|
|
{
|
|
/* Do the work (one day...) */
|
|
DPRINT("BasepCheckWinSaferRestrictions is UNIMPLEMENTED\n");
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Act as if SEH hit this */
|
|
Status = STATUS_ACCESS_VIOLATION;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Input is invalid */
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Return the status */
|
|
return Status;
|
|
}
|