[+] Aurora::Process::GetBinaryClassPath

[+] Aurora::Process::SetBinaryClassPath
[+] Aurora::Process::AddBinaryClassPath
[+] Aurora::Process::LoadModuleEx
[+] Aurora::Process::GetProcHandle
[+] Aurora::Process::GetProcAddressEx
[+] Aurora::ProcessConfig
[*] Cleanup a bit
This commit is contained in:
Reece Wilson 2023-10-11 00:21:32 +01:00
parent bee9b8b07b
commit 33f77cf011
5 changed files with 310 additions and 51 deletions

View File

@ -29,6 +29,7 @@ namespace Aurora::Process
eModulePathSystemDir, /// /usr/lib/, windir/system32 eModulePathSystemDir, /// /usr/lib/, windir/system32
eModulePathUserDir, /// /usr/local/lib eModulePathUserDir, /// /usr/local/lib
eProcessDirectory, /// eProcessDirectory, ///
eClassPath,
//eOSSpecified, /// LD_LIBRARY_PATH + /etc/ld.so.conf, AddDllDirectory //eOSSpecified, /// LD_LIBRARY_PATH + /etc/ld.so.conf, AddDllDirectory
eSpecified eSpecified
)); ));
@ -40,18 +41,19 @@ namespace Aurora::Process
// Ubuntu 2018 (mandatory 2021+): https://lists.ubuntu.com/archives/ubuntu-devel-announce/2018-November/001253.html https://wiki.debian.org/UsrMerge // Ubuntu 2018 (mandatory 2021+): https://lists.ubuntu.com/archives/ubuntu-devel-announce/2018-November/001253.html https://wiki.debian.org/UsrMerge
// Fedora (2011?): https://fedoraproject.org/wiki/Features/UsrMove // Fedora (2011?): https://fedoraproject.org/wiki/Features/UsrMove
static AuList<EModulePath> kUserOverloadableSearchPath = {EModulePath::eSpecified, EModulePath::eModulePathCWD, EModulePath::eProcessDirectory, EModulePath::eModulePathUserDir, EModulePath::eModulePathSystemDir}; static AuList<EModulePath> kUserOverloadableSearchPath = { EModulePath::eSpecified, EModulePath::eModulePathCWD, EModulePath::eClassPath, EModulePath::eProcessDirectory, EModulePath::eModulePathUserDir, EModulePath::eModulePathSystemDir };
static AuList<EModulePath> kAdminOverloadableSearchPath = {EModulePath::eSpecified, EModulePath::eModulePathSystemDir, EModulePath::eProcessDirectory, EModulePath::eModulePathCWD, EModulePath::eModulePathUserDir}; static AuList<EModulePath> kAdminOverloadableSearchPath = { EModulePath::eSpecified, EModulePath::eModulePathSystemDir, EModulePath::eProcessDirectory, EModulePath::eClassPath, EModulePath::eModulePathCWD, EModulePath::eModulePathUserDir };
static AuList<EModulePath> kSpecifiedPath = {EModulePath::eSpecified}; static AuList<EModulePath> kSpecifiedPath = { EModulePath::eSpecified, EModulePath::eClassPath };
static AuList<EModulePath> kCWDPath = {EModulePath::eModulePathCWD}; static AuList<EModulePath> kSpecifiedPathStrict = { EModulePath::eSpecified };
static AuList<EModulePath> kProcPath = {EModulePath::eProcessDirectory}; static AuList<EModulePath> kCWDPath = { EModulePath::eModulePathCWD };
static AuList<EModulePath> kProcPath = { EModulePath::eProcessDirectory };
struct ModuleLoadRequest struct ModuleLoadRequest
{ {
inline ModuleLoadRequest(const AuList<AuString> &directories, const AuString &mod) : mod(mod), specifiedSearchPaths(&directories), searchPath(&kSpecifiedPath) inline ModuleLoadRequest(const AuList<AuString> &directories, const AuString &mod) : mod(mod), specifiedSearchPaths(&directories), searchPath(&kSpecifiedPathStrict)
{} {}
inline ModuleLoadRequest(const AuList<AuString> &directories, const AuString &mod, const AuString &version) : mod(mod), version(version), specifiedSearchPaths(&directories), searchPath(&kSpecifiedPath) inline ModuleLoadRequest(const AuList<AuString> &directories, const AuString &mod, const AuString &version) : mod(mod), version(version), specifiedSearchPaths(&directories), searchPath(&kSpecifiedPathStrict)
{} {}
inline ModuleLoadRequest(const AuString &mod) : mod(mod), searchPath(&kAdminOverloadableSearchPath) inline ModuleLoadRequest(const AuString &mod) : mod(mod), searchPath(&kAdminOverloadableSearchPath)
@ -79,6 +81,17 @@ namespace Aurora::Process
*/ */
AUKN_SYM bool LoadModule(const ModuleLoadRequest &request); AUKN_SYM bool LoadModule(const ModuleLoadRequest &request);
AUKN_SYM void *LoadModuleEx(const ModuleLoadRequest &request);
AUKN_SYM AuMach GetProcAddress(AuString mod, AuString symbol); AUKN_SYM void *GetProcHandle(const AuString &name);
AUKN_SYM AuMach GetProcAddress(const AuString &mod, const AuString &symbol);
AUKN_SYM AuMach GetProcAddressEx(void *pHandle, const AuString &symbol);
AUKN_SYM AuList<AuString> GetBinaryClassPath();
AUKN_SYM bool SetBinaryClassPath(const AuList<AuString> &list, bool preloadAll = false);
AUKN_SYM bool AddBinaryClassPath(const AuString &dir, bool preloadAll = false);
} }

View File

@ -409,6 +409,13 @@ namespace Aurora
AuUInt8 uSignalGAIOWorkerThreadDone { 28 }; AuUInt8 uSignalGAIOWorkerThreadDone { 28 };
}; };
struct ProcessConfig
{
bool bAlwaysPreloadEntireClassPath { false };
bool bForcePreload { false };
bool bEnablePreload { true };
};
struct RuntimeStartInfo struct RuntimeStartInfo
{ {
ConsoleConfig console; ConsoleConfig console;
@ -419,6 +426,7 @@ namespace Aurora
AuAlignTo<64, DebugConfig> debug; AuAlignTo<64, DebugConfig> debug;
AuAlignTo<32, ThreadingConfig> threadingConfig; AuAlignTo<32, ThreadingConfig> threadingConfig;
AuAlignTo<32, LinuxConfig> linuxConfig; AuAlignTo<32, LinuxConfig> linuxConfig;
AuAlignTo<32, ProcessConfig> processConfig;
AuAlignTo<32, DummyConfig> padding; AuAlignTo<32, DummyConfig> padding;
}; };

View File

@ -137,7 +137,9 @@ namespace Aurora
ADD_GET_PROC(Kernel32, VerSetConditionMask) ADD_GET_PROC(Kernel32, VerSetConditionMask)
ADD_GET_PROC(Kernel32, QueryPerformanceCounter) ADD_GET_PROC(Kernel32, QueryPerformanceCounter)
ADD_GET_PROC(Kernel32, QueryPerformanceFrequency) ADD_GET_PROC(Kernel32, QueryPerformanceFrequency)
ADD_GET_PROC(Kernel32, RemoveDllDirectory)
ADD_GET_PROC(Kernel32, AddDllDirectory)
ADD_GET_PROC_BI2(Kernel32, PSAPILegacy, K32GetProcessMemoryInfo, GetProcessMemoryInfo) ADD_GET_PROC_BI2(Kernel32, PSAPILegacy, K32GetProcessMemoryInfo, GetProcessMemoryInfo)
ADD_GET_PROC(Sync, WaitOnAddress) ADD_GET_PROC(Sync, WaitOnAddress)

View File

@ -239,6 +239,14 @@ namespace Aurora
); );
#endif #endif
inline BOOL(__stdcall *pRemoveDllDirectory)(
PVOID Cookie
);
inline PVOID(__stdcall *pAddDllDirectory)(
PCWSTR NewDirectory
);
inline INT(__stdcall *pGetAddrInfoExCancel)( inline INT(__stdcall *pGetAddrInfoExCancel)(
LPHANDLE lpHandle LPHANDLE lpHandle
); );

View File

@ -40,6 +40,7 @@
namespace Aurora::Process namespace Aurora::Process
{ {
static AuFutexMutex gSpinLock; static AuFutexMutex gSpinLock;
static AuList<AuString> gClassPath;
static AuHashMap<AuString, void *> gModuleHandles; static AuHashMap<AuString, void *> gModuleHandles;
static const bool kIsMainSigned = false; static const bool kIsMainSigned = false;
@ -273,12 +274,12 @@ namespace Aurora::Process
} }
#endif #endif
static bool LoadModule(const AuString &name, const AuString &path) static void *LoadModule(const AuString &name, const AuString &path)
{ {
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
if (!pLoadLibraryW) if (!pLoadLibraryW)
{ {
return false; return {};
} }
auto handle = pLoadLibraryW(Locale::ConvertFromUTF8(path).c_str()); auto handle = pLoadLibraryW(Locale::ConvertFromUTF8(path).c_str());
@ -296,11 +297,12 @@ namespace Aurora::Process
} }
#endif #endif
gModuleHandles.insert(AuMakePair(name, (void *)handle)); auto pRet = (void *)handle;
return true; gModuleHandles.insert(AuMakePair(name, pRet));
return pRet;
} }
static bool TryLoadModule(const AuString &path, static void *TryLoadModule(const AuString &path,
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
const AuString &abs, const AuString &abs,
#endif #endif
@ -320,7 +322,7 @@ namespace Aurora::Process
{ {
SysPushErrorNested("Couldn't open existing file. Race exploit?"); SysPushErrorNested("Couldn't open existing file. Race exploit?");
fail = true; fail = true;
return false; return {};
} }
auto absPath = AuIOFS::NormalizePathRet(abs); auto absPath = AuIOFS::NormalizePathRet(abs);
@ -334,7 +336,7 @@ namespace Aurora::Process
SysPushErrorNested("Couldn't verify file {}", path); SysPushErrorNested("Couldn't verify file {}", path);
fail = true; fail = true;
AuWin32CloseHandle(mitigateTimeOfUse); AuWin32CloseHandle(mitigateTimeOfUse);
return false; return {};
} }
#else #else
AuLogWarn("Can't verify {} on this platform", path); AuLogWarn("Can't verify {} on this platform", path);
@ -350,13 +352,13 @@ namespace Aurora::Process
{ {
SysPushErrorNested("Couldn't open existing file. Race exploit?"); SysPushErrorNested("Couldn't open existing file. Race exploit?");
fail = true; fail = true;
return false; return {};
} }
if ((sb.st_mode & S_IXUSR) == 0) if ((sb.st_mode & S_IXUSR) == 0)
{ {
fail = true; fail = true;
return false; return {};
} }
} }
#endif #endif
@ -377,7 +379,7 @@ namespace Aurora::Process
return returnValue; return returnValue;
} }
static bool TryLoadModule(const AuString &path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request, bool &fail) static void *TryLoadModule(const AuString &path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request, bool &fail)
{ {
AuString a = path + "/" + auDll; AuString a = path + "/" + auDll;
AuString b = path + "/" + genericDll; AuString b = path + "/" + genericDll;
@ -412,34 +414,61 @@ namespace Aurora::Process
return {}; return {};
} }
static bool TryLoadModule(EModulePath path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request) static void *TryLoadModule(EModulePath path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request)
{ {
AuString pathA, pathB; AuString pathA, pathB;
AuList<AuString> arrayPaths;
switch (path) switch (path)
{ {
case EModulePath::eClassPath:
{
AU_LOCK_GUARD(gSpinLock);
arrayPaths = gClassPath;
break;
}
case EModulePath::eModulePathCWD: case EModulePath::eModulePathCWD:
if (!Process::GetWorkingDirectory(pathA)) return false; {
if (!Process::GetWorkingDirectory(pathA))
{
return {};
}
break; break;
}
case EModulePath::eProcessDirectory: case EModulePath::eProcessDirectory:
if (!Process::GetProcDirectory(pathA)) return false; {
if (!Process::GetProcDirectory(pathA))
{
return {};
}
break; break;
}
case EModulePath::eModulePathSystemDir: case EModulePath::eModulePathSystemDir:
{
pathA = AuIOFS::GetSystemLibPath().value_or(AuString {}); pathA = AuIOFS::GetSystemLibPath().value_or(AuString {});
pathB = AuIOFS::GetSystemLibPath2().value_or(AuString {}); pathB = AuIOFS::GetSystemLibPath2().value_or(AuString {});
if (pathA.empty()) return false; if (pathA.empty())
{
return {};
}
break; break;
}
case EModulePath::eModulePathUserDir: case EModulePath::eModulePathUserDir:
{
pathA = AuIOFS::GetUserLibPath().value_or(AuString {}); pathA = AuIOFS::GetUserLibPath().value_or(AuString {});
pathB = AuIOFS::GetUserLibPath2().value_or(AuString {}); pathB = AuIOFS::GetUserLibPath2().value_or(AuString {});
if (pathA.empty()) return false; if (pathA.empty())
{
return {};
}
break; break;
}
//case EModulePath::eOSSpecified: //case EModulePath::eOSSpecified:
// //
// break; // break;
@ -452,27 +481,40 @@ namespace Aurora::Process
if (pathA.size()) if (pathA.size())
{ {
if (TryLoadModule(pathA, auDll, genericDll, request, fail)) if (auto pRet = TryLoadModule(pathA, auDll, genericDll, request, fail))
{ {
return true; return pRet;
} }
if (fail) if (fail)
{ {
return false; return {};
} }
} }
if (pathB.size()) if (pathB.size())
{ {
if (TryLoadModule(pathB, auDll, genericDll, request, fail)) if (auto pRet = TryLoadModule(pathB, auDll, genericDll, request, fail))
{ {
return true; return pRet;
} }
if (fail) if (fail)
{ {
return false; return {};
}
}
for (const auto &dir : arrayPaths)
{
if (auto pRet = TryLoadModule(dir, auDll, genericDll, request, fail))
{
return pRet;
}
if (fail)
{
return {};
} }
} }
@ -480,14 +522,14 @@ namespace Aurora::Process
{ {
for (const auto &val : *request.specifiedSearchPaths) for (const auto &val : *request.specifiedSearchPaths)
{ {
if (TryLoadModule(val, auDll, genericDll, request, fail)) if (auto pRet = TryLoadModule(val, auDll, genericDll, request, fail))
{ {
return true; return pRet;
} }
if (fail) if (fail)
{ {
return false; return {};
} }
} }
} }
@ -496,13 +538,18 @@ namespace Aurora::Process
} }
AUKN_SYM bool LoadModule(const ModuleLoadRequest &request) AUKN_SYM bool LoadModule(const ModuleLoadRequest &request)
{
return bool(LoadModuleEx(request));
}
AUKN_SYM void *LoadModuleEx(const ModuleLoadRequest &request)
{ {
AU_LOCK_GUARD(gSpinLock); AU_LOCK_GUARD(gSpinLock);
auto h = gModuleHandles.find(request.mod); auto h = gModuleHandles.find(request.mod);
if (h != gModuleHandles.end()) if (h != gModuleHandles.end())
{ {
return true; return h->second;
} }
auto au = request.mod + ConstructAuDllSuffix(); auto au = request.mod + ConstructAuDllSuffix();
@ -528,37 +575,47 @@ namespace Aurora::Process
auto searchPath = request.searchPath ? request.searchPath : &kUserOverloadableSearchPath; auto searchPath = request.searchPath ? request.searchPath : &kUserOverloadableSearchPath;
for (EModulePath path : *searchPath) for (EModulePath path : *searchPath)
{ {
if (TryLoadModule(path, au, base, request)) if (auto pRet = TryLoadModule(path, au, base, request))
{ {
return true; return pRet;
} }
} }
return false; return {};
} }
AUKN_SYM AuMach GetProcAddress(AuString mod, AuString symbol) AUKN_SYM AuMach GetProcAddressEx(void *pHandle, const AuString &symbol)
{ {
AU_LOCK_GUARD(gSpinLock);
auto h = gModuleHandles.find(mod);
if (h == gModuleHandles.end())
{
SysPushErrorGen("Module {} is not loaded", mod);
return {};
}
auto handle = h->second;
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
if (!pGetProcAddress) if (!pGetProcAddress)
{ {
return {}; return {};
} }
auto ret = reinterpret_cast<AuMach>(pGetProcAddress(reinterpret_cast<HMODULE>(handle), symbol.c_str())); auto ret = reinterpret_cast<AuMach>(pGetProcAddress(reinterpret_cast<HMODULE>(pHandle), symbol.c_str()));
#else #else
auto ret = reinterpret_cast<AuMach>(dlsym(handle, symbol.c_str())); auto ret = reinterpret_cast<AuMach>(dlsym(hapHandlendle, symbol.c_str()));
#endif #endif
return ret;
}
AUKN_SYM void *GetProcHandle(const AuString &name)
{
AU_LOCK_GUARD(gSpinLock);
auto h = gModuleHandles.find(name);
if (h == gModuleHandles.end())
{
SysPushErrorGen("Module {} is not loaded", name);
return {};
}
return h->second;
}
AUKN_SYM AuMach GetProcAddress(const AuString &mod, const AuString &symbol)
{
auto ret = GetProcAddressEx(GetProcHandle(mod), symbol);
if (!ret) if (!ret)
{ {
@ -590,6 +647,177 @@ namespace Aurora::Process
#endif #endif
} }
static void PreloadDLLsDoOnce(const AuList<AuString> &dirs)
{
AU_DEBUG_MEMCRUNCH;
AuList<void *> cookieList;
#if defined(AURORA_PLATFORM_WIN32)
for (const auto dir : dirs)
{
void *pCookie {};
if (pRemoveDllDirectory)
{
if (pAddDllDirectory)
{
pCookie = pAddDllDirectory(AuLocale::ConvertFromUTF8(dir).c_str());
}
}
cookieList.push_back(pCookie);
}
#endif
for (const auto dir : dirs)
{
AuList<AuString> files;
AuList<AuString> sharedObjects;
if (!AuFS::FilesInDirectory(dir, files))
{
SysPushErrorIO("Couldn't readdir: {}", dir);
continue;
}
auto endingPattern = ConstructAuDllSuffix();
auto endingAlt = GetPlatformExt(Build::kCurrentPlatform);
for (const auto &file : files)
{
if (!(file.ends_with(endingPattern.c_str()) ||
file.ends_with(endingAlt)))
{
continue;
}
sharedObjects.push_back(file);
}
{
AuUInt uSuccess {};
do
{
uSuccess = 0;
for (auto itr = sharedObjects.begin();
itr != sharedObjects.end(); )
{
auto &sharedDLL = *itr;
AuLogDbg("[attempt] Loading shared object: {}", sharedDLL);
AuString a = dir + "/" + sharedDLL;
#if defined(AURORA_IS_MODERNNT_DERIVED)
AuString aAbs = dir + "/" + sharedDLL + ".";
#endif
bool fail {};
ModuleLoadRequest request { AuList<AuString>{ dir }, sharedDLL };
if (TryLoadModule(a,
#if defined(AURORA_IS_MODERNNT_DERIVED)
aAbs,
#endif
request,
fail
))
{
if (!fail)
{
AuLogDbg("[attempt] Loaded shared object: {}!", sharedDLL);
uSuccess++;
itr = sharedObjects.erase(itr);
}
else
{
itr++;
}
}
else
{
itr++;
}
}
}
while (uSuccess);
}
}
#if defined(AURORA_PLATFORM_WIN32)
for (const auto pCookie : AuExchange(cookieList, {}))
{
if (pRemoveDllDirectory)
{
if (pCookie)
{
pRemoveDllDirectory(pCookie);
}
}
}
#endif
}
static void PreloadDLLs(const AuString &dir)
{
AU_DEBUG_MEMCRUNCH;
if (gRuntimeConfig.processConfig.bAlwaysPreloadEntireClassPath)
{
PreloadDLLsDoOnce(gClassPath);
}
else
{
PreloadDLLsDoOnce({ dir });
}
}
AUKN_SYM bool SetBinaryClassPath(const AuList<AuString> &list, bool preloadAll)
{
AU_DEBUG_MEMCRUNCH;
AU_LOCK_GUARD(gSpinLock);
AuExchange(gClassPath, list);
if (((preloadAll && gRuntimeConfig.processConfig.bEnablePreload)) ||
(gRuntimeConfig.processConfig.bForcePreload))
{
if (gRuntimeConfig.processConfig.bAlwaysPreloadEntireClassPath)
{
PreloadDLLsDoOnce(gClassPath);
}
else
{
PreloadDLLsDoOnce(list);
}
}
return true;
}
AUKN_SYM bool AddBinaryClassPath(const AuString &dir, bool preloadAll)
{
AU_LOCK_GUARD(gSpinLock);
if (!AuTryInsert(gClassPath, dir))
{
return false;
}
if (((preloadAll && gRuntimeConfig.processConfig.bEnablePreload)) ||
(gRuntimeConfig.processConfig.bForcePreload))
{
PreloadDLLs(dir);
}
return true;
}
AUKN_SYM AuList<AuString> GetBinaryClassPath()
{
AU_LOCK_GUARD(gSpinLock);
return gClassPath;
}
void InitProcess() void InitProcess()
{ {