This commit is contained in:
mik
2026-04-06 12:54:21 -04:00
commit 727b6509de

712
injector.cpp Normal file
View File

@@ -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<std::string>& 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<char*>(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<PTEB>(
__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
pebPtr = (_PPEB)tebPtr->ProcessEnvironmentBlock;
#else
tebPtr = reinterpret_cast<PTEB>(
__readfsdword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(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;
}