438 lines
16 KiB
C++
438 lines
16 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuProcessSectionView.NT.cpp
|
|
Date: 2022-08-09
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuProcessSectionView.NT.hpp"
|
|
#include "Process.hpp"
|
|
#include <Source/IO/FS/FileStream.NT.hpp>
|
|
#include "AuProcessSectionFileMapView.NT.hpp"
|
|
#include <Source/IO/IPC/AuIPCHandle.hpp>
|
|
#include <Windows.h>
|
|
|
|
namespace Aurora::Process
|
|
{
|
|
AuUInt ProcessSectionView::GetStart()
|
|
{
|
|
return AuNumericLimits<AuUInt>::min();
|
|
}
|
|
|
|
AuUInt ProcessSectionView::GetEnd()
|
|
{
|
|
return AuNumericLimits<AuUInt>::max();
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::Allocate(AuUInt uLength)
|
|
{
|
|
PageTable table {};
|
|
table.NX = true;
|
|
table.readable = true;
|
|
table.writable = true;
|
|
return this->AllocateEx2(uLength, 0, table);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByPath(const AuString &str,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode,
|
|
AuFS::EFileAdvisoryLockLevel sectionLock)
|
|
{
|
|
auto file = AuFS::OpenShared(str, mode, AuFS::EFileAdvisoryLockLevel::eNoSafety);
|
|
return file ? this->MapFileByObject(file, uOffset, uLength, mode, sectionLock) : AuSPtr<IProcessSectionMapView> {};
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByObject(const AuSPtr<AuFS::IFileStream> &pStream,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode,
|
|
AuFS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
HANDLE hFileMap;
|
|
ULONG desiredAccess {}, pageAttributes {};
|
|
|
|
if (!pStream)
|
|
{
|
|
SysPushErrorArg();
|
|
return {};
|
|
}
|
|
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
auto pFileStream = AuStaticCast<AuFS::WinFileStream>(pStream);
|
|
if (processLockLevel != AuFS::EFileAdvisoryLockLevel::eNoSafety)
|
|
{
|
|
DWORD dwFlags {};
|
|
OVERLAPPED overlapped {};
|
|
|
|
if (processLockLevel == AuFS::EFileAdvisoryLockLevel::eBlockReadWrite)
|
|
{
|
|
dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
|
}
|
|
|
|
dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
|
|
|
|
overlapped.Offset = AuBitsToLower(uOffset);
|
|
overlapped.OffsetHigh = AuBitsToHigher(uOffset);
|
|
|
|
if (!::LockFileEx(pFileStream->GetHandle(),
|
|
dwFlags,
|
|
0,
|
|
AuBitsToLower(uLength),
|
|
AuBitsToHigher(uLength),
|
|
&overlapped))
|
|
{
|
|
SysPushErrorIO("No Lock");
|
|
return {};
|
|
}
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case AuFS::EFileOpenMode::eRead:
|
|
{
|
|
desiredAccess = SECTION_MAP_READ;
|
|
pageAttributes = PAGE_READONLY;
|
|
break;
|
|
}
|
|
case AuFS::EFileOpenMode::eWrite:
|
|
case AuFS::EFileOpenMode::eReadWrite:
|
|
{
|
|
desiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE;
|
|
pageAttributes = PAGE_READWRITE;
|
|
break;
|
|
}
|
|
default:
|
|
SysPushErrorGeneric();
|
|
return {};
|
|
};
|
|
|
|
hFileMap = ::CreateFileMappingA(pFileStream->GetHandle(),
|
|
nullptr,
|
|
pageAttributes,
|
|
#if defined(AURORA_IS_64BIT)
|
|
AuBitsToHigher(uLength),
|
|
AuBitsToLower(uLength),
|
|
#else
|
|
0,
|
|
uLength,
|
|
#endif
|
|
nullptr);
|
|
if ((hFileMap == INVALID_HANDLE_VALUE) ||
|
|
(!hFileMap))
|
|
{
|
|
SysPushErrorIO("Couldn't create file map. Is the requeted access mode too high for the given object?");
|
|
return {};
|
|
}
|
|
|
|
auto map = ::MapViewOfFile(hFileMap,
|
|
desiredAccess,
|
|
AuBitsToHigher(uOffset),
|
|
AuBitsToLower(uOffset),
|
|
uLength);
|
|
if (!map)
|
|
{
|
|
SysPushErrorIO("Couldn't create map of section");
|
|
AuWin32CloseHandle(hFileMap);
|
|
return {};
|
|
}
|
|
|
|
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
|
|
if (!pNewObject)
|
|
{
|
|
SysPushErrorMem();
|
|
AuWin32CloseHandle(hFileMap);
|
|
::UnmapViewOfFile(map);
|
|
return {};
|
|
}
|
|
|
|
pNewObject->pProcessGlobalHint = this;
|
|
pNewObject->uLength = uLength;
|
|
|
|
return pNewObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapIPCMemory(const AuString &handleString,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode)
|
|
{
|
|
AuIPC::IPCHandle handle;
|
|
HANDLE hFileMap;
|
|
ULONG desiredAccess {}, pageAttributes {};
|
|
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
if (!handle.FromString(handleString))
|
|
{
|
|
SysPushErrorParseError("{}", handleString);
|
|
return {};
|
|
}
|
|
|
|
auto token = handle.GetToken(AuIPC::EIPCHandleType::eIPCMemory, 0);
|
|
if (!token)
|
|
{
|
|
SysPushErrorParseError();
|
|
return {};
|
|
}
|
|
|
|
auto actualLength = token->token.word;
|
|
auto path = token->token.ToNTPath();
|
|
|
|
if (actualLength < uOffset + uLength)
|
|
{
|
|
SysPushErrorIO("Out of range");
|
|
return {};
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case AuFS::EFileOpenMode::eRead:
|
|
{
|
|
desiredAccess = SECTION_MAP_READ;
|
|
pageAttributes = PAGE_READONLY;
|
|
break;
|
|
}
|
|
case AuFS::EFileOpenMode::eWrite:
|
|
case AuFS::EFileOpenMode::eReadWrite:
|
|
{
|
|
desiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE;
|
|
pageAttributes = PAGE_READWRITE;
|
|
break;
|
|
}
|
|
default:
|
|
SysPushErrorGeneric();
|
|
return {};
|
|
};
|
|
|
|
hFileMap = ::OpenFileMappingA(desiredAccess,
|
|
FALSE,
|
|
path.c_str());
|
|
if ((hFileMap == INVALID_HANDLE_VALUE) ||
|
|
(!hFileMap))
|
|
{
|
|
SysPushErrorIO("Couldn't create IPC map (handle: {})", handleString);
|
|
return {};
|
|
}
|
|
|
|
auto map = ::MapViewOfFile(hFileMap,
|
|
desiredAccess,
|
|
AuBitsToHigher(uOffset),
|
|
AuBitsToLower(uOffset),
|
|
uLength);
|
|
if (!map)
|
|
{
|
|
SysPushErrorIO("Couldn't create map of IPC section (handle: {})", handleString);
|
|
AuWin32CloseHandle(hFileMap);
|
|
return {};
|
|
}
|
|
|
|
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
|
|
if (!pNewObject)
|
|
{
|
|
SysPushErrorMem();
|
|
AuWin32CloseHandle(hFileMap);
|
|
::UnmapViewOfFile(map);
|
|
return {};
|
|
}
|
|
|
|
pNewObject->pProcessGlobalHint = this;
|
|
pNewObject->uLength = uLength;
|
|
|
|
return pNewObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::AllocateEx(AuUInt uLength,
|
|
AuUInt uOffset)
|
|
{
|
|
SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. "
|
|
"Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows."
|
|
"We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset.");
|
|
return this->Allocate(uLength);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::AllocateEx2(AuUInt uLength,
|
|
AuUInt uOffset,
|
|
PageTable permissions)
|
|
{
|
|
SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. "
|
|
"Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows."
|
|
"We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset.");
|
|
|
|
HANDLE hFileMap;
|
|
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
DWORD uPageFlags {};
|
|
if (permissions.writable && permissions.NX)
|
|
{
|
|
uPageFlags = PAGE_READWRITE;
|
|
}
|
|
else if (permissions.readable && permissions.NX)
|
|
{
|
|
uPageFlags = PAGE_READONLY;
|
|
}
|
|
else if (permissions.writable)
|
|
{
|
|
uPageFlags = PAGE_EXECUTE_READWRITE;
|
|
}
|
|
else if (permissions.readable)
|
|
{
|
|
uPageFlags = PAGE_EXECUTE_READ;
|
|
}
|
|
|
|
hFileMap = ::CreateFileMappingA(INVALID_HANDLE_VALUE,
|
|
nullptr,
|
|
uPageFlags,
|
|
#if defined(AURORA_IS_64BIT)
|
|
AuBitsToHigher(uLength),
|
|
AuBitsToLower(uLength),
|
|
#else
|
|
0,
|
|
uLength,
|
|
#endif
|
|
nullptr);
|
|
if ((hFileMap == INVALID_HANDLE_VALUE) ||
|
|
(!hFileMap))
|
|
{
|
|
SysPushErrorIO("Couldn't create file map");
|
|
return {};
|
|
}
|
|
|
|
DWORD sectionPermission {};
|
|
if (permissions.readable)
|
|
{
|
|
sectionPermission = SECTION_MAP_READ;
|
|
}
|
|
|
|
if (permissions.writable)
|
|
{
|
|
sectionPermission |= SECTION_MAP_WRITE;
|
|
}
|
|
|
|
if (!permissions.NX)
|
|
{
|
|
sectionPermission |= SECTION_MAP_EXECUTE;
|
|
}
|
|
|
|
auto map = ::MapViewOfFile(hFileMap,
|
|
sectionPermission,
|
|
0,
|
|
0,
|
|
uLength);
|
|
if (!map)
|
|
{
|
|
SysPushErrorIO("Couldn't create allocation of section");
|
|
AuWin32CloseHandle(hFileMap);
|
|
return {};
|
|
}
|
|
|
|
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
|
|
if (!pNewObject)
|
|
{
|
|
SysPushErrorMem();
|
|
AuWin32CloseHandle(hFileMap);
|
|
return {};
|
|
}
|
|
|
|
pNewObject->pProcessGlobalHint = this;
|
|
pNewObject->uLength = uLength;
|
|
|
|
return pNewObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByPathEx(AuUInt viewOffset,
|
|
const AuString &str,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode,
|
|
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. "
|
|
"Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows."
|
|
"We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset.");
|
|
return this->MapFileByPath(str, uOffset, uLength, mode, processLockLevel);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByObjectEx(AuUInt viewOffset,
|
|
const AuSPtr<Aurora::IO::FS::IFileStream> &pStream,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode,
|
|
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. "
|
|
"Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows."
|
|
"We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset.");
|
|
return this->MapFileByObject(pStream, uOffset, uLength, mode, processLockLevel);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapIPCMemoryEx(AuUInt viewOffset,
|
|
const AuString &handle,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode)
|
|
{
|
|
SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. "
|
|
"Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows."
|
|
"We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset.");
|
|
return this->MapIPCMemory(handle, uOffset, uLength, mode);
|
|
}
|
|
|
|
AuList<AuPair<AuUInt, AuUInt>> ProcessSectionView::GetAllocations()
|
|
{
|
|
AU_LOCK_GUARD(this->spinlock);
|
|
return this->allocations;
|
|
}
|
|
|
|
void ProcessSectionView::DoVanillaDriverlessExtesionWin7Test()
|
|
{
|
|
#if defined(AURORA_PLATFORM_WIN32)
|
|
|
|
#define WIN_7_WARN "WARNING: ADDRESS SPACE CANNOT BE RESERVED ON OLDER NT KERNELS. \r\n" \
|
|
"AuProcess::ReserveAddressSpace(AuUInt uOffset) is about to lie about reserving the address space, yield the entire address space, and leave a note to terminate the application if an explicit fixed-offset request is made."
|
|
|
|
SysPushErrorUnimplemented("Win7_ReserveAddressSpace_RS4_REQ");
|
|
|
|
AuUInt uEnvSize {};
|
|
::getenv_s(&uEnvSize, nullptr, 0, "AURORA_FORCE_RANDOM_ADDRESS_WITHOUT_VIRTALLOC2");
|
|
if (uEnvSize)
|
|
{
|
|
// bah
|
|
// enjoy return not respecting what was provided as the expected offset.
|
|
// this is not a workaround for missing functionality in the operating systems userland and kernel abstraction.
|
|
// this will just prevent us from panicing preemptively.
|
|
this->bPanicOnEx = true;
|
|
}
|
|
else
|
|
{
|
|
AuLogWarn(WIN_7_WARN);
|
|
this->bPanicOnEx = false;
|
|
}
|
|
#else
|
|
AuLogWarn("I don't know this platform - AuProcess");
|
|
this->bPanicOnEx = true;
|
|
#endif
|
|
}
|
|
|
|
AUKN_SYM AuSPtr<IProcessSectionView> GetGlobalProcessSpace()
|
|
{
|
|
static ProcessSectionView gSingleton;
|
|
gSingleton.DoVanillaDriverlessExtesionWin7Test();
|
|
return AuUnsafeRaiiToShared(&gSingleton);
|
|
}
|
|
} |