From 727b6509de4e62850fe243ed8bbd5a912556ff53 Mon Sep 17 00:00:00 2001 From: Modin Modin Date: Mon, 6 Apr 2026 12:54:21 -0400 Subject: [PATCH] Sample 1 --- injector.cpp | 712 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 712 insertions(+) create mode 100644 injector.cpp diff --git a/injector.cpp b/injector.cpp new file mode 100644 index 0000000..4847ffa --- /dev/null +++ b/injector.cpp @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2021 Mykhailo Mamedov. All rights reserved. + * + * RESEARCH PREVIEW / REFERENCE ONLY: + * This source code is provided solely for the purpose of reviewing + * the author's research methods and implementation. + * + * NO LICENSE GRANTED: + * This code is NOT for distribution, modification, or use in any + * project (commercial or otherwise). Unauthorized copying or + * use of this code is strictly prohibited. + * + * For inquiries regarding use or licensing, contact: ua.modin@gmail.com + * + * + * Description: + * + * This is an old injector designed to help legacy processes + * play nice with modern filesystem features. Some older services + * get tripped up by reparse points when running out of the system root, + * so this steps in to patch the PEB. + * + */ +#include "main_defs.h" + +#pragma comment(lib,"ntdll.lib") +EXTERN_C NTSTATUS NTAPI NtSuspendProcess(IN HANDLE ProcessHandle); +EXTERN_C NTSTATUS NTAPI NtResumeProcess(IN HANDLE ProcessHandle); + +LPCTSTR PARENT_PIPE = TEXT("\\\\.\\pipe\\Aura"); + +#if _WIN64 +_PPEB pebPtr = NULL; +#else +PPEB32 pebPtr = NULL; +#endif + +_CreateProcessInternalW TrueCreateProcessInternalW = +(_CreateProcessInternalW)GetProcAddress(GetModuleHandle(L"KernelBase"), "CreateProcessInternalW"); + + +inline static BOOL InArray(const std::string& value, const std::vector& array) { + return std::find(array.begin(), array.end(), value) != array.end(); +} + +static void CheckProcImage(DEBUG_EVENT debugEvent) { + // Getting executable image name from handle provided. + const size_t size = _MAX_PATH + 4; + char* resolvedPath = (char*)malloc(size); + DWORD ret = GetFinalPathNameByHandleA(debugEvent.u.CreateProcessInfo.hFile, resolvedPath, size, 0); + simpleLogger(std::format("Module path: {}", resolvedPath)); + fs::path image_path(resolvedPath); + free(resolvedPath); +} + +static void CheckProcImageDLL(DEBUG_EVENT debugEvent) { + // Getting dll image name from handle provided. Can be merged with above. + const size_t size = _MAX_PATH + 4; + char* resolvedPath = (char*)malloc(size); + DWORD ret = GetFinalPathNameByHandleA(debugEvent.u.LoadDll.hFile, resolvedPath, size, 0); + simpleLogger(std::format("Module DLL path: {}", resolvedPath)); + free(resolvedPath); +} + +void CheckProcThreads(DWORD processID) { + // Print threads of the process specified (expensive). + // Currently not in use. + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) { + simpleLogger(std::format("Error in getting thread snapshot")); + return; + } + + te32.dwSize = sizeof(THREADENTRY32); + if (!Thread32First(hThreadSnap, &te32)) { + simpleLogger(std::format("Error in getting first thread")); + CloseHandle(hThreadSnap); + return; + } + + int threadCount = 0; + do { + if (te32.th32OwnerProcessID == processID) { + ++threadCount; + simpleLogger(std::format("THREAD ID: {}", te32.th32ThreadID)); + } + } while (Thread32Next(hThreadSnap, &te32)); + + simpleLogger(std::format("THREAD COUNT: {}", threadCount)); + CloseHandle(hThreadSnap); +} + + +HANDLE ConnectNamedPipe(LPCTSTR pipe_name) { + HANDLE hPipe = 0; + DWORD dwError; + while (TRUE) { + hPipe = ::CreateFile(pipe_name, + GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + if (hPipe != INVALID_HANDLE_VALUE) + break; + // If any error except the ERROR_PIPE_BUSY has occurred, + // we should return FALSE. + dwError = GetLastError(); + if (dwError != ERROR_PIPE_BUSY) { + simpleLogger(std::format("Pipe connect failed {}", dwError)); + return FALSE; + } + simpleLogger(std::format("Pipe is busy, waiting..")); + if (!WaitNamedPipe(pipe_name, 2000)) { + simpleLogger(std::format("Pipe wait failed {}", GetLastError())); + return FALSE; + } + } + return hPipe; +} + +DWORD RequestPatchProc(DWORD pid, fs::path file, DWORD thread_id, DWORD parent_pid, BOOL keepSuspended) { + std::string msg; + HANDLE hPipe = 0; + DWORD dwWritten = 0; + DWORD dwRead; + BOOL pipe_res = FALSE; + char _buffer[1024]{}; + hPipe = ConnectNamedPipe(PARENT_PIPE); + if (hPipe != INVALID_HANDLE_VALUE) { + + msg = std::format("patch_process_peb=[{0}][{1}][{2}]", + pid, file.filename().generic_string().c_str(), parent_pid); + + pipe_res = WriteFile(hPipe, + msg.c_str(), + msg.length(), + &dwWritten, + NULL); + if (!pipe_res || dwWritten != msg.length()) { + simpleLogger(std::format("Pipe failed to write(PEB): {}", pipe_res)); + } + + if (ReadFile(hPipe, _buffer, sizeof(_buffer) - 1, &dwRead, NULL) != FALSE) { + _buffer[dwRead] = '\0'; + simpleLogger(std::format("Got back from pipe(PEB): {}", _buffer)); + } + + msg = std::format("patch_inject=[{0}][{1}][{2}][{3}][{4}]", + pid, file.filename().generic_string().c_str(), thread_id, parent_pid, keepSuspended); + + pipe_res = WriteFile(hPipe, + msg.c_str(), + msg.length(), + &dwWritten, + NULL); + if (!pipe_res || dwWritten != msg.length()) { + simpleLogger(std::format("Pipe failed to write(PATCH): {}", pipe_res)); + } + + // Either response or broken connection. We shell wait. + if (ReadFile(hPipe, _buffer, sizeof(_buffer) - 1, &dwRead, NULL) != FALSE) { + _buffer[dwRead] = '\0'; + simpleLogger(std::format("Got back from pipe(PATCH): {}", _buffer)); + } + + CloseHandle(hPipe); + simpleLogger(std::format("Pipe done")); + + } + else { + simpleLogger(std::format("Named pipe is not available, service might be down.")); + } + return pipe_res; +} + +fs::path GetFileNameProc(HANDLE proc) { + TCHAR filename[MAX_PATH]; + fs::path out; + if (GetModuleFileNameEx(proc, NULL, filename, MAX_PATH) != 0) { + out = fs::path(filename); + } + return out; +} + +void CheckDbgString(DEBUG_EVENT event, DWORD pid) { + BOOL dropSub = FALSE; + DWORD dropPid = event.dwProcessId; + BOOL dropForced = FALSE; + + if (!event.u.DebugString.nDebugStringLength) + return; + + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + + if (event.u.DebugString.fUnicode) + { + std::wstring debugStringExtracted; + debugStringExtracted.resize(event.u.DebugString.nDebugStringLength + 1); + ReadProcessMemory(hProcess, event.u.DebugString.lpDebugStringData, &debugStringExtracted[0], + event.u.DebugString.nDebugStringLength * 2 + 2, nullptr); + std::string dbg_str(w_wo_a((LPWSTR)debugStringExtracted.c_str())); + simpleLogger(std::format("DBG_STR(W) {}", dbg_str)); + if (dbg_str.starts_with(hookSet)) { + dropSub = TRUE; + } + } + else + { + std::string debugStringExtracted; + debugStringExtracted.resize(event.u.DebugString.nDebugStringLength + 1); + ReadProcessMemory(hProcess, event.u.DebugString.lpDebugStringData, &debugStringExtracted[0], + event.u.DebugString.nDebugStringLength + 1, nullptr); + std::string dbg_str(debugStringExtracted.c_str()); + simpleLogger(std::format("DBG_STR(A) {}", dbg_str)); + if (dbg_str.starts_with(hookSet)) { + dropSub = TRUE; + } + else if (dbg_str.starts_with(libDrop)) { + std::string pid_s(dbg_str.substr(libDrop.length(), std::string::npos)); + if (pid_s.length()) { + dropPid = atoi(pid_s.c_str()); + simpleLogger(std::format("DBG_STR(AU_lib_drop A) {}", dropPid)); + dropSub = TRUE; + dropForced = TRUE; + } + } + } + CloseHandle(hProcess); + + if (dropSub) { + if (releaseAttachedDebuggee || dropForced) { + simpleLogger(std::format("Dropping {}", dropPid)); + if (!DebugActiveProcessStop(dropPid)) { + simpleLogger(std::format("Failed to detach")); + } + else { + simpleLogger(std::format("Detached")); + } + } + } + +} + +std::string flattenEnvBlock(LPVOID env) { + std::string out; + UINT offset = 0; + char* env_c = static_cast(env); + while (1) { + if (std::memcmp(env_c + offset, "\0\0", 2) == 0) { + break; + } + else { + offset++; + } + } + if (offset) { + char* env_copy = (char*)malloc(offset); + std::memcpy(env_copy, env_c, offset); + + for (UINT i = 0; i < offset; i++) { + if (std::memcmp(env_copy + i, "\0", 1) == 0) + std::memcpy(env_copy + i, " ", 1); + } + simpleLogger(std::format("Env len, {}.", offset)); + out = std::string(env_copy); + free(env_copy); + } + return out; +} + +int ProcessWrapperT(HANDLE hToken, // __in + LPCWSTR AppName, // __in_opt + LPWSTR CmdLine, // __inout_opt + LPSECURITY_ATTRIBUTES ProcessAttr, + LPSECURITY_ATTRIBUTES ThreadAttr, + BOOL bIH, + DWORD flags, + LPVOID env, + LPCWSTR CurrDir, + LPSTARTUPINFOW si, + LPPROCESS_INFORMATION pi, + PHANDLE NewToken, + PBOOL ret, + PDWORD lastErr, + BOOL* procLaunched +) { + simpleLogger(std::format("{} Start", __func__)); + + *ret = TrueCreateProcessInternalW( + hToken, AppName, CmdLine, ProcessAttr, ThreadAttr, bIH, + flags, env, CurrDir, si, pi, NewToken); + + // Preserve original error returned from API call. + *lastErr = GetLastError(); + + if (!*ret && *lastErr == ERROR_NOT_SUPPORTED) { // 32bit with 64bit child proc case. + // Try one more time. + flags = flags & ~DEBUG_PROCESS; + *ret = TrueCreateProcessInternalW( + hToken, AppName, CmdLine, ProcessAttr, ThreadAttr, bIH, + flags, env, CurrDir, si, pi, NewToken); + if (ret) { + simpleLogger(std::format("Launched detached (32>64bit case)")); + *procLaunched = 1; + return 0; + } + else { + *lastErr = GetLastError(); + simpleLogger(std::format("Abort launch E:{:x}.", (DWORD)&lastErr)); + *procLaunched = 1; + return 1; + } + } + + simpleLogger(std::format("Launched?, E:{:x}.", (DWORD)&lastErr)); + + // Notify parent thread that process is started + // and returned shared pointers can be checked. + *procLaunched = 1; + + // Children process continue running if this process terminated (very unlikely). + DebugSetProcessKillOnExit(FALSE); + + BOOL toContinue = TRUE; + DWORD waitMax = INFINITE; + if (flags & CREATE_SUSPENDED) { + // Some processes could be created suspended and wait for parent to resume + // But parent can break and left children hanging, therefore putting a timeout + // after which process is released. + waitMax = 30000; + } + HANDLE Handle; + fs::path pModule; + simpleLogger(std::format("Waiting for events.")); + while (toContinue) { + DWORD continueStatus = DBG_CONTINUE; + DWORD th_id = 0; + DEBUG_EVENT debugEvent = { 0 }; + BOOL keep = FALSE; + BOOL keepSuspended = FALSE; + fs::path tempPath; + if (!::WaitForDebugEvent(&debugEvent, waitMax)) { + simpleLogger(std::format("DBG stop.")); + break; + } + else { + simpleLogger(std::format("DBG event: {} {}", debugEvent.dwDebugEventCode, debugEvent.dwProcessId)); + switch (debugEvent.dwDebugEventCode) { + case EXCEPTION_DEBUG_EVENT: + // Non of exceptions expected. + simpleLogger(std::format("DBG Exception: {}", + debugEvent.u.Exception.ExceptionRecord.ExceptionCode)); + continueStatus = DBG_EXCEPTION_NOT_HANDLED; + switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + simpleLogger(std::format("EXCEPTION _ACCESS_VIOLATION")); + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + simpleLogger(std::format("EXCEPTION _DATATYPE_MISALIGNMENT")); + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + simpleLogger(std::format("EXCEPTION _ARRAY_BOUNDS_EXCEEDED")); + break; + case EXCEPTION_PRIV_INSTRUCTION: + simpleLogger(std::format("EXCEPTION _PRIV_INSTRUCTION")); + break; + case EXCEPTION_IN_PAGE_ERROR: + simpleLogger(std::format("EXCEPTION _IN_PAGE_ERROR")); + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + simpleLogger(std::format("EXCEPTION _ILLEGAL_INSTRUCTION")); + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + simpleLogger(std::format("EXCEPTION _NONCONTINUABLE_EXCEPTION")); + break; + case EXCEPTION_STACK_OVERFLOW: + simpleLogger(std::format("EXCEPTION _STACK_OVERFLOW")); + break; + case EXCEPTION_INVALID_DISPOSITION: + break; + case EXCEPTION_INVALID_HANDLE: + simpleLogger(std::format("EXCEPTION_INVALID_HANDLE")); + break; + default: + ; + } + break; + + case EXIT_PROCESS_DEBUG_EVENT: // last + simpleLogger(std::format("EXIT_PROCESS_DEBUG_EVENT")); + break; + case CREATE_THREAD_DEBUG_EVENT: // + simpleLogger(std::format("CREATE_THREAD_DEBUG_EVENT")); + break; + case CREATE_PROCESS_DEBUG_EVENT: // first + simpleLogger(std::format("CREATE_PROCESS_DEBUG_EVENT")); + tempPath = GetFileNameProc(debugEvent.u.CreateProcessInfo.hProcess); + simpleLogger(std::format("Started proc: {} {}", debugEvent.dwProcessId, tempPath.generic_string())); + th_id = 0; + if (debugEvent.u.CreateProcessInfo.hThread) { + th_id = GetThreadId(debugEvent.u.CreateProcessInfo.hThread); + keepSuspended = TRUE; + } + RequestPatchProc( + debugEvent.dwProcessId, + tempPath, + th_id, + pi->dwProcessId, + keepSuspended + ); + CheckProcImage(debugEvent); + break; + case EXIT_THREAD_DEBUG_EVENT: + simpleLogger(std::format("EXIT_THREAD_DEBUG_EVENT")); + break; + case LOAD_DLL_DEBUG_EVENT: // + simpleLogger(std::format("LOAD_DLL_DEBUG_EVENT")); + if (debugMode) + CheckProcImageDLL(debugEvent); + break; + case UNLOAD_DLL_DEBUG_EVENT: + simpleLogger(std::format("UNLOAD_DLL_DEBUG_EVENT")); + break; + case OUTPUT_DEBUG_STRING_EVENT: + simpleLogger(std::format("OUTPUT_DEBUG_STRING_EVENT")); + CheckDbgString(debugEvent, debugEvent.dwProcessId); + break; + default: + ; + } + ::ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, continueStatus); + } + } + if (!DebugActiveProcessStop(pi->dwProcessId)) { + simpleLogger(std::format("Failed to detach (top)")); + } + else { + simpleLogger(std::format("DBG Detached (top)")); + } + + return 0; +} + +void send_debug_string(std::string dbg_str) { + UCHAR orig_dbg_value = pebPtr->BeingDebugged; + BOOL changed = FALSE; + if (!orig_dbg_value) { + changed = TRUE; + // Required to be flipped back-forth to submit the notification. + // Original must be preserved afterwards. + pebPtr->BeingDebugged = 1; + } + OutputDebugStringA(dbg_str.c_str()); + if (changed) + pebPtr->BeingDebugged = orig_dbg_value; +} + + +BOOL WINAPI HookCreateProcessInternalW( + HANDLE hToken, // __in + LPCWSTR AppName, // __in_opt + LPWSTR CmdLine, // __inout_opt + LPSECURITY_ATTRIBUTES ProcessAttr, // __in_opt + LPSECURITY_ATTRIBUTES ThreadAttr, // __in_opt + BOOL bIH, // __in + DWORD flags, // __in + LPVOID env, // __in_opt + LPCWSTR CurrDir, // __in_opt + LPSTARTUPINFOW si, // __in + LPPROCESS_INFORMATION pi, // __out + PHANDLE NewToken // __in +) { + + std::wstring w_AppName(L"NOPE"); + std::wstring w_CmdLine(L"NOPE"); + if (AppName) + w_AppName = std::wstring(AppName); + if (CmdLine) + w_CmdLine = std::wstring(CmdLine); + + simpleLogger(std::format("{} Create proc: AppName: `{}` CmdLine: `{}` flags: `{:x}`", + __func__, w_wo_a(w_AppName), w_wo_a(w_CmdLine), flags)); + + // Patch the flags. + DWORD newFlags = flags; + DWORD current_pid = GetCurrentProcessId(); + simpleLogger(std::format("{} Original flags: `{:x}`", __func__, flags)); + BOOL cacheOverrideSet = FALSE; + if (env) { + std::string flattenedEnv(flattenEnvBlock(env)); + if (flattenedEnv.find(" __AU_ROOT") != std::string::npos) { + cacheOverrideSet = TRUE; + simpleLogger(std::format("Override is set.")); + } + } + + BOOL wrapIt = TRUE; + if (legacyRoot || cacheOverrideSet) + wrapIt = FALSE; + if (wrapIt) { + if (!(DEBUG_PROCESS & flags)) { + simpleLogger(std::format("Adding DEBUG_PROCESS flag")); + newFlags |= DEBUG_PROCESS; + } + } + BOOL keepSuspended = FALSE; + if (flags & CREATE_SUSPENDED) { + simpleLogger(std::format("{} sub-proc requested suspended flag: `{:x}`", __func__, flags)); + keepSuspended = TRUE; + } + else { + if (legacyRoot && !cacheOverrideSet) { + newFlags = flags | CREATE_SUSPENDED; + } + } + + simpleLogger(std::format("{} final flags: `{:x}`", __func__, newFlags)); + + BOOL res = 0; + DWORD lastError = 0; + + if (!wrapIt) { + // Same thread launch (when we don't need to track hierarchy. + res = TrueCreateProcessInternalW( + hToken, AppName, CmdLine, ProcessAttr, ThreadAttr, bIH, + newFlags, env, CurrDir, si, pi, NewToken); + lastError = GetLastError(); + } + else { + BOOL trigger = 0; + std::thread(ProcessWrapperT, hToken, AppName, CmdLine, ProcessAttr, ThreadAttr, bIH, + newFlags, env, CurrDir, si, pi, NewToken, &res, &lastError, &trigger).detach(); + + UINT counter = 0; + while (1) { + // Not an elegant replacement for mutex, since 32bit threads having issues with it. + if (trigger) + break; + if (counter > 200) { + simpleLogger(std::format("Launch timeout reached. (unexpected)")); + break; + } + counter++; + Sleep(5); + } + simpleLogger(std::format("Wrapper launched.")); + } + + DWORD ec = 0; + DWORD thread_res = 0; + DWORD event_pid = 0; + BOOL arm_lib = FALSE; + DWORD sz_r = 0; + + if (res && !wrapIt) { + // Legacy handling + fs::path _temp_path = GetFileNameProc(pi->hProcess); + simpleLogger(std::format("{} sub-proc(below) started: {} {}", + __func__, pi->dwProcessId, _temp_path.generic_string())); + if (!cacheOverrideSet) { + // Patch PEB and create remote thread. + DWORD th_id = 0; + if (legacyRoot && pi->hThread) + th_id = GetThreadId(pi->hThread); + if (isInSRoot(_temp_path.native())) { + RequestPatchProc( + pi->dwProcessId, + _temp_path, + th_id, + current_pid, + keepSuspended + ); + } + else { + if (!keepSuspended) { + if (ResumeThread(pi->hThread) == -1) { + simpleLogger(std::format("{} Failed to resume: {}", __func__, pi->dwProcessId)); + } + } + } + } + } + else if (res) { + // Process created. + simpleLogger(std::format("{} sub-proc started: {}", __func__, pi->dwProcessId)); + } + else { + simpleLogger(std::format("{} didn't start Err: {}", __func__, lastError)); + } + + if (cacheOverrideSet) { + std::string msg("AU_lib_drop"); + msg.append(std::to_string(pi->dwProcessId)); + send_debug_string(msg); + } + + simpleLogger(std::format("Releasing process..")); + SetLastError(lastError); + return res; +} + + +LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) { + + simpleLogger(std::format("Exception: 0x{:x}", pExceptionInfo->ExceptionRecord->ExceptionCode)); + + return EXCEPTION_CONTINUE_SEARCH; +} + + +BOOLEAN WINAPI DllMain(IN HINSTANCE hDllHandle, + IN DWORD nReason, + IN LPVOID Reserved) +{ + BOOLEAN bSuccess = TRUE; + BOOL unhook_res = FALSE; + CHAR szFileName[MAX_PATH * 3]; + const wchar_t* env_p = NULL; + PTEB tebPtr = NULL; + UCHAR orig_dbg_value; + BOOL changed; + std::string msg_d("AU_lib_drop"); + + switch (nReason) { + case DLL_PROCESS_ATTACH: + +#if _WIN64 + tebPtr = reinterpret_cast( + __readgsqword(reinterpret_cast(&static_cast(nullptr)->Self))); + pebPtr = (_PPEB)tebPtr->ProcessEnvironmentBlock; + +#else + tebPtr = reinterpret_cast( + __readfsdword(reinterpret_cast(&static_cast(nullptr)->Self))); + pebPtr = (PPEB32)tebPtr->ProcessEnvironmentBlock; +#endif + + + GetModuleFileNameA(NULL, szFileName, MAX_PATH * 3); + pathCurrentModule = fs::path(szFileName); + exeName = std::string(pathCurrentModule.filename().generic_string()); + env_p = _wgetenv(L"AU_API_HOOK_DEBUG"); + if (env_p) { + debugMode = TRUE; + } + env_p = _wgetenv(L"AU_API_HOOK_WRITE_STD_ERR"); + if (env_p) { + writeStdErr = _wtoi(env_p); + } + env_p = _wgetenv(L"AU_API_HOOK_LOG_PATH"); + if (env_p) { + logPathPrefix = std::wstring(env_p); + } + env_p = _wgetenv(L"AU_API_HOOK_EX_HANDLER"); + if (env_p) { + AddVectoredExceptionHandler(1, VectoredExceptionHandler); + } + env_p = _wgetenv(L"AU_API_HOOK_RELEASE_CHILD"); + if (env_p) { + // Keep child process attached for debugging purposes. + releaseAttachedDebuggee = TRUE; + } + env_p = _wgetenv(L"__AU_PACKAGE_REP_ROOT"); + if (env_p) { + msg_d.append(std::to_string(GetCurrentProcessId())); + send_debug_string(msg_d); + simpleLogger(std::format("Abort hook.")); + break; + } + + resolveSystemRoot(); + + if (isSRootLegacy() != G_LOCATION::is_not_in_systemroot) { + // Consider no response as legacy as well to keep going. + legacyRoot = TRUE; + } + + simpleLogger(std::format("AU platform api lib({}-{}) attached: {} PID: {} legacy: {} dbg: {}\nfull path: {}", + __DATE__, __TIME__, pathCurrentModule.filename().generic_string(), + GetCurrentProcessId(), legacyRoot, + IsDebuggerPresent(), pathCurrentModule.generic_string())); + + if (legacyRoot) { + pebPtr->PlaceholderCompatibilityMode = PHCM_DISGUISE_PLACEHOLDER; + } + + // Beware PEB patch removed from within library, + + // Set hook to tweak sub-procs. + if (!hookCreateProcW) + hookCreateProcW = Mhook_SetHook((PVOID*)&TrueCreateProcessInternalW, HookCreateProcessInternalW); + simpleLogger(std::format("Hook state: {}", hookCreateProcW)); + + send_debug_string(hookSet); // Notify parent that DLL initialized and hook is set. + + break; + + case DLL_PROCESS_DETACH: + simpleLogger("AU platform api lib DLL_PROCESS_DETACH"); + if (hookCreateProcW) + unhook_res = Mhook_Unhook((PVOID*)&TrueCreateProcessInternalW); + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + } + return bSuccess; +}