test crashing
This commit is contained in:
@@ -44,6 +44,9 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
static BOOL g_HooksInitialized = FALSE;
|
static BOOL g_HooksInitialized = FALSE;
|
||||||
static HANDLE g_LogFile = INVALID_HANDLE_VALUE;
|
static HANDLE g_LogFile = INVALID_HANDLE_VALUE;
|
||||||
static HANDLE g_CrashLog = INVALID_HANDLE_VALUE;
|
static HANDLE g_CrashLog = INVALID_HANDLE_VALUE;
|
||||||
|
static volatile LONG g_CrashStageSeq = 0;
|
||||||
|
static char g_CrashStage[192] = "not started";
|
||||||
|
static LPTOP_LEVEL_EXCEPTION_FILTER g_PreviousUnhandledFilter = NULL;
|
||||||
|
|
||||||
// %TEMP%\crashlogovd.log
|
// %TEMP%\crashlogovd.log
|
||||||
// Both CrashLog (narrow) and CrashLogW (wide) write UTF-16LE so the file
|
// Both CrashLog (narrow) and CrashLogW (wide) write UTF-16LE so the file
|
||||||
@@ -81,6 +84,75 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetCrashStage(const char* stage) {
|
||||||
|
if (!stage) return;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < sizeof(g_CrashStage) - 1 && stage[i] != '\0'; i++) {
|
||||||
|
g_CrashStage[i] = stage[i];
|
||||||
|
}
|
||||||
|
g_CrashStage[i] = '\0';
|
||||||
|
|
||||||
|
LONG seq = InterlockedIncrement(&g_CrashStageSeq);
|
||||||
|
char msg[256];
|
||||||
|
sprintf_s(msg, 256, "[STAGE %ld] %s", seq, g_CrashStage);
|
||||||
|
CrashLog(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CrashLogModuleForAddress(PVOID address) {
|
||||||
|
HMODULE module = NULL;
|
||||||
|
WCHAR modulePath[1024] = { 0 };
|
||||||
|
|
||||||
|
if (GetModuleHandleExW(
|
||||||
|
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
|
(LPCWSTR)address,
|
||||||
|
&module) &&
|
||||||
|
module &&
|
||||||
|
GetModuleFileNameW(module, modulePath, 1024) > 0) {
|
||||||
|
CrashLog("[CRASH] Module for exception address:");
|
||||||
|
CrashLogW(modulePath);
|
||||||
|
} else {
|
||||||
|
CrashLog("[CRASH] Module for exception address: <unknown>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LONG WINAPI HvncUnhandledExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) {
|
||||||
|
CrashLog("=== Unhandled exception observed ===");
|
||||||
|
|
||||||
|
if (exceptionInfo && exceptionInfo->ExceptionRecord) {
|
||||||
|
EXCEPTION_RECORD* rec = exceptionInfo->ExceptionRecord;
|
||||||
|
char msg[512];
|
||||||
|
sprintf_s(msg, 512,
|
||||||
|
"[CRASH] code=0x%08lX flags=0x%08lX address=%p lastStage=%ld:%s",
|
||||||
|
rec->ExceptionCode,
|
||||||
|
rec->ExceptionFlags,
|
||||||
|
rec->ExceptionAddress,
|
||||||
|
g_CrashStageSeq,
|
||||||
|
g_CrashStage);
|
||||||
|
CrashLog(msg);
|
||||||
|
|
||||||
|
if (rec->NumberParameters > 0) {
|
||||||
|
char params[512];
|
||||||
|
sprintf_s(params, 512,
|
||||||
|
"[CRASH] params count=%lu p0=0x%p p1=0x%p p2=0x%p",
|
||||||
|
rec->NumberParameters,
|
||||||
|
rec->NumberParameters > 0 ? (PVOID)rec->ExceptionInformation[0] : NULL,
|
||||||
|
rec->NumberParameters > 1 ? (PVOID)rec->ExceptionInformation[1] : NULL,
|
||||||
|
rec->NumberParameters > 2 ? (PVOID)rec->ExceptionInformation[2] : NULL);
|
||||||
|
CrashLog(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashLogModuleForAddress(rec->ExceptionAddress);
|
||||||
|
} else {
|
||||||
|
CrashLog("[CRASH] exceptionInfo was NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_PreviousUnhandledFilter && g_PreviousUnhandledFilter != HvncUnhandledExceptionFilter) {
|
||||||
|
return g_PreviousUnhandledFilter(exceptionInfo);
|
||||||
|
}
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to log debug info (verbose, compile-time gated)
|
// Helper function to log debug info (verbose, compile-time gated)
|
||||||
void LogDebug(const WCHAR* message) {
|
void LogDebug(const WCHAR* message) {
|
||||||
#if ENABLE_DEBUG_LOGGING
|
#if ENABLE_DEBUG_LOGGING
|
||||||
@@ -1006,6 +1078,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
}
|
}
|
||||||
|
|
||||||
static BOOL ReflectiveInjectIntoChild(HANDLE hProcess, const BYTE* dllBytes, DWORD dllSize) {
|
static BOOL ReflectiveInjectIntoChild(HANDLE hProcess, const BYTE* dllBytes, DWORD dllSize) {
|
||||||
|
SetCrashStage("ChildInject: locating ReflectiveLoader");
|
||||||
DWORD loaderOffset = FindReflectiveLoaderFileOffset(dllBytes, dllSize);
|
DWORD loaderOffset = FindReflectiveLoaderFileOffset(dllBytes, dllSize);
|
||||||
if (loaderOffset == 0) {
|
if (loaderOffset == 0) {
|
||||||
CrashLog("[ChildInject] FAIL: ReflectiveLoader export not found in DLL");
|
CrashLog("[ChildInject] FAIL: ReflectiveLoader export not found in DLL");
|
||||||
@@ -1013,6 +1086,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCrashStage("ChildInject: VirtualAllocEx");
|
||||||
LPVOID remoteMem = VirtualAllocEx(hProcess, NULL, dllSize,
|
LPVOID remoteMem = VirtualAllocEx(hProcess, NULL, dllSize,
|
||||||
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||||
if (!remoteMem) {
|
if (!remoteMem) {
|
||||||
@@ -1021,6 +1095,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCrashStage("ChildInject: WriteProcessMemory");
|
||||||
SIZE_T written;
|
SIZE_T written;
|
||||||
if (!WriteProcessMemory(hProcess, remoteMem, dllBytes, dllSize, &written)) {
|
if (!WriteProcessMemory(hProcess, remoteMem, dllBytes, dllSize, &written)) {
|
||||||
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
|
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
|
||||||
@@ -1028,10 +1103,16 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
LogDebug(L"[ChildInject] WriteProcessMemory failed");
|
LogDebug(L"[ChildInject] WriteProcessMemory failed");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
char msg[160];
|
||||||
|
sprintf_s(msg, 160, "[ChildInject] WriteProcessMemory wrote %llu/%lu bytes", (unsigned long long)written, dllSize);
|
||||||
|
CrashLog(msg);
|
||||||
|
}
|
||||||
|
|
||||||
LPTHREAD_START_ROUTINE remoteLoader =
|
LPTHREAD_START_ROUTINE remoteLoader =
|
||||||
(LPTHREAD_START_ROUTINE)((BYTE*)remoteMem + loaderOffset);
|
(LPTHREAD_START_ROUTINE)((BYTE*)remoteMem + loaderOffset);
|
||||||
|
|
||||||
|
SetCrashStage("ChildInject: CreateRemoteThread");
|
||||||
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 1024 * 1024,
|
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 1024 * 1024,
|
||||||
remoteLoader, NULL, 0, NULL);
|
remoteLoader, NULL, 0, NULL);
|
||||||
if (!hThread) {
|
if (!hThread) {
|
||||||
@@ -1040,10 +1121,19 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCrashStage("ChildInject: waiting for loader thread");
|
||||||
DWORD waitResult = WaitForSingleObject(hThread, 30000);
|
DWORD waitResult = WaitForSingleObject(hThread, 30000);
|
||||||
|
DWORD loaderExitCode = 0;
|
||||||
|
GetExitCodeThread(hThread, &loaderExitCode);
|
||||||
|
{
|
||||||
|
char msg[160];
|
||||||
|
sprintf_s(msg, 160, "[ChildInject] loader wait=0x%lX exit=0x%lX", waitResult, loaderExitCode);
|
||||||
|
CrashLog(msg);
|
||||||
|
}
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
|
|
||||||
if (waitResult == WAIT_OBJECT_0) {
|
if (waitResult == WAIT_OBJECT_0) {
|
||||||
|
SetCrashStage("ChildInject: loader thread completed");
|
||||||
CrashLog("[ChildInject] OK: child injection completed");
|
CrashLog("[ChildInject] OK: child injection completed");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else if (waitResult == WAIT_TIMEOUT) {
|
} else if (waitResult == WAIT_TIMEOUT) {
|
||||||
@@ -1076,6 +1166,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
LPPROCESS_INFORMATION lpProcessInformation
|
LPPROCESS_INFORMATION lpProcessInformation
|
||||||
) {
|
) {
|
||||||
if (!OriginalCreateProcessW) return FALSE;
|
if (!OriginalCreateProcessW) return FALSE;
|
||||||
|
SetCrashStage("HookedCreateProcessW: entered");
|
||||||
|
|
||||||
// Snapshot g_DllRawBytes / g_DllRawSize into locals *before* any check.
|
// Snapshot g_DllRawBytes / g_DllRawSize into locals *before* any check.
|
||||||
// RemoveNtApiHooks() can race here: it calls UnmapViewOfFile(g_DllRawBytes)
|
// RemoveNtApiHooks() can race here: it calls UnmapViewOfFile(g_DllRawBytes)
|
||||||
@@ -1086,6 +1177,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
DWORD localDllSize = g_DllRawSize;
|
DWORD localDllSize = g_DllRawSize;
|
||||||
|
|
||||||
if (!g_HooksInitialized || !localDllBytes || localDllSize == 0) {
|
if (!g_HooksInitialized || !localDllBytes || localDllSize == 0) {
|
||||||
|
SetCrashStage("HookedCreateProcessW: bypassing child injection");
|
||||||
return OriginalCreateProcessW(
|
return OriginalCreateProcessW(
|
||||||
lpApplicationName, lpCommandLine,
|
lpApplicationName, lpCommandLine,
|
||||||
lpProcessAttributes, lpThreadAttributes,
|
lpProcessAttributes, lpThreadAttributes,
|
||||||
@@ -1098,6 +1190,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
BOOL wasSuspended = (dwCreationFlags & CREATE_SUSPENDED) != 0;
|
BOOL wasSuspended = (dwCreationFlags & CREATE_SUSPENDED) != 0;
|
||||||
DWORD modifiedFlags = dwCreationFlags | CREATE_SUSPENDED;
|
DWORD modifiedFlags = dwCreationFlags | CREATE_SUSPENDED;
|
||||||
|
|
||||||
|
SetCrashStage("HookedCreateProcessW: calling original CreateProcessW");
|
||||||
BOOL result = OriginalCreateProcessW(
|
BOOL result = OriginalCreateProcessW(
|
||||||
lpApplicationName, lpCommandLine,
|
lpApplicationName, lpCommandLine,
|
||||||
lpProcessAttributes, lpThreadAttributes,
|
lpProcessAttributes, lpThreadAttributes,
|
||||||
@@ -1107,6 +1200,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (result && lpProcessInformation) {
|
if (result && lpProcessInformation) {
|
||||||
|
SetCrashStage("HookedCreateProcessW: child created, injecting");
|
||||||
CrashLog("[CreateProcessW] Injecting DLL into child process...");
|
CrashLog("[CreateProcessW] Injecting DLL into child process...");
|
||||||
LogDebug(L"[CreateProcessW] Reflective-injecting DLL into child process");
|
LogDebug(L"[CreateProcessW] Reflective-injecting DLL into child process");
|
||||||
BOOL injected = ReflectiveInjectIntoChild(lpProcessInformation->hProcess,
|
BOOL injected = ReflectiveInjectIntoChild(lpProcessInformation->hProcess,
|
||||||
@@ -1123,10 +1217,12 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
// Even if injection failed we resume; the child runs without hooks rather than
|
// Even if injection failed we resume; the child runs without hooks rather than
|
||||||
// hanging forever (fail-open policy).
|
// hanging forever (fail-open policy).
|
||||||
if (!wasSuspended) {
|
if (!wasSuspended) {
|
||||||
|
SetCrashStage("HookedCreateProcessW: resuming child thread");
|
||||||
ResumeThread(lpProcessInformation->hThread);
|
ResumeThread(lpProcessInformation->hThread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCrashStage("HookedCreateProcessW: returning");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1150,6 +1246,8 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
g_CrashLog = INVALID_HANDLE_VALUE;
|
g_CrashLog = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_PreviousUnhandledFilter = SetUnhandledExceptionFilter(HvncUnhandledExceptionFilter);
|
||||||
|
SetCrashStage("InstallNtApiHooks: crash log opened");
|
||||||
CrashLog("=== Overlord HVNC DLL Loaded ===");
|
CrashLog("=== Overlord HVNC DLL Loaded ===");
|
||||||
|
|
||||||
#if ENABLE_DEBUG_LOGGING
|
#if ENABLE_DEBUG_LOGGING
|
||||||
@@ -1184,6 +1282,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
g_DllRawSize = 0;
|
g_DllRawSize = 0;
|
||||||
|
|
||||||
// Try to get configuration from environment variables
|
// Try to get configuration from environment variables
|
||||||
|
SetCrashStage("InstallNtApiHooks: reading environment");
|
||||||
__try {
|
__try {
|
||||||
// Use the same capacity as the global g_SearchString / g_ReplacementString
|
// Use the same capacity as the global g_SearchString / g_ReplacementString
|
||||||
// buffers (2048 WCHARs) so that very long paths are never silently truncated.
|
// buffers (2048 WCHARs) so that very long paths are never silently truncated.
|
||||||
@@ -1194,6 +1293,11 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
|
|
||||||
DWORD searchLen = GetEnvironmentVariableW(L"RDI_SEARCH_PATH", envSearchString, 2048);
|
DWORD searchLen = GetEnvironmentVariableW(L"RDI_SEARCH_PATH", envSearchString, 2048);
|
||||||
DWORD replaceLen = GetEnvironmentVariableW(L"RDI_REPLACE_PATH", envReplaceString, 2048);
|
DWORD replaceLen = GetEnvironmentVariableW(L"RDI_REPLACE_PATH", envReplaceString, 2048);
|
||||||
|
{
|
||||||
|
char msg[160];
|
||||||
|
sprintf_s(msg, 160, "[ENV] RDI path lengths search=%lu replace=%lu", searchLen, replaceLen);
|
||||||
|
CrashLog(msg);
|
||||||
|
}
|
||||||
|
|
||||||
// A return value >= buffer capacity means the value was truncated.
|
// A return value >= buffer capacity means the value was truncated.
|
||||||
if (searchLen >= 2048) {
|
if (searchLen >= 2048) {
|
||||||
@@ -1242,6 +1346,11 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
WCHAR envDllSize[32] = { 0 };
|
WCHAR envDllSize[32] = { 0 };
|
||||||
DWORD sectionNameLen = GetEnvironmentVariableW(L"RDI_DLL_SECTION", envSectionName, 512);
|
DWORD sectionNameLen = GetEnvironmentVariableW(L"RDI_DLL_SECTION", envSectionName, 512);
|
||||||
DWORD dllSizeLen = GetEnvironmentVariableW(L"RDI_DLL_SIZE", envDllSize, 32);
|
DWORD dllSizeLen = GetEnvironmentVariableW(L"RDI_DLL_SIZE", envDllSize, 32);
|
||||||
|
{
|
||||||
|
char msg[160];
|
||||||
|
sprintf_s(msg, 160, "[ENV] RDI dll metadata lengths section=%lu size=%lu", sectionNameLen, dllSizeLen);
|
||||||
|
CrashLog(msg);
|
||||||
|
}
|
||||||
|
|
||||||
if (sectionNameLen >= 512) {
|
if (sectionNameLen >= 512) {
|
||||||
CrashLog("[ENV] WARN: RDI_DLL_SECTION is >= 512 chars and was truncated — child injection disabled");
|
CrashLog("[ENV] WARN: RDI_DLL_SECTION is >= 512 chars and was truncated — child injection disabled");
|
||||||
@@ -1276,6 +1385,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
}
|
}
|
||||||
g_DllSectionHandle = OpenFileMappingW(FILE_MAP_READ, FALSE, envSectionName);
|
g_DllSectionHandle = OpenFileMappingW(FILE_MAP_READ, FALSE, envSectionName);
|
||||||
if (g_DllSectionHandle) {
|
if (g_DllSectionHandle) {
|
||||||
|
SetCrashStage("InstallNtApiHooks: mapping DLL section");
|
||||||
g_DllRawBytes = MapViewOfFile(g_DllSectionHandle, FILE_MAP_READ, 0, 0, g_DllRawSize);
|
g_DllRawBytes = MapViewOfFile(g_DllSectionHandle, FILE_MAP_READ, 0, 0, g_DllRawSize);
|
||||||
if (g_DllRawBytes) {
|
if (g_DllRawBytes) {
|
||||||
char msg[256];
|
char msg[256];
|
||||||
@@ -1312,6 +1422,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize MinHook (this must succeed)
|
// Initialize MinHook (this must succeed)
|
||||||
|
SetCrashStage("InstallNtApiHooks: initializing MinHook");
|
||||||
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
||||||
LogDebugA("Initializing MinHook...");
|
LogDebugA("Initializing MinHook...");
|
||||||
}
|
}
|
||||||
@@ -1329,6 +1440,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
LogDebugA("MinHook initialized successfully");
|
LogDebugA("MinHook initialized successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCrashStage("InstallNtApiHooks: resolving ntdll");
|
||||||
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
|
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
|
||||||
if (!ntdll) {
|
if (!ntdll) {
|
||||||
CrashLog("FATAL: GetModuleHandleW(ntdll.dll) returned NULL");
|
CrashLog("FATAL: GetModuleHandleW(ntdll.dll) returned NULL");
|
||||||
@@ -1343,6 +1455,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
LogDebugA("Got ntdll.dll handle");
|
LogDebugA("Got ntdll.dll handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCrashStage("InstallNtApiHooks: creating hooks");
|
||||||
#define SAFE_HOOK(target, detour, ppOriginal, label) do { \
|
#define SAFE_HOOK(target, detour, ppOriginal, label) do { \
|
||||||
MH_STATUS _cr = MH_CreateHook((LPVOID)(target), (LPVOID)(detour), (LPVOID*)(ppOriginal)); \
|
MH_STATUS _cr = MH_CreateHook((LPVOID)(target), (LPVOID)(detour), (LPVOID*)(ppOriginal)); \
|
||||||
if (_cr == MH_OK) { \
|
if (_cr == MH_OK) { \
|
||||||
@@ -1415,12 +1528,14 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
#undef SAFE_HOOK
|
#undef SAFE_HOOK
|
||||||
|
|
||||||
if (OriginalNtCreateFile && OriginalNtOpenFile) {
|
if (OriginalNtCreateFile && OriginalNtOpenFile) {
|
||||||
|
SetCrashStage("InstallNtApiHooks: hooks initialized");
|
||||||
g_HooksInitialized = TRUE;
|
g_HooksInitialized = TRUE;
|
||||||
CrashLog("=== All hooks installed successfully ===");
|
CrashLog("=== All hooks installed successfully ===");
|
||||||
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
||||||
LogDebugA("=== All hooks installed successfully ===");
|
LogDebugA("=== All hooks installed successfully ===");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
SetCrashStage("InstallNtApiHooks: critical hook failure cleanup");
|
||||||
CrashLog("FATAL: Critical hooks (NtCreateFile/NtOpenFile) failed — tearing down all hooks");
|
CrashLog("FATAL: Critical hooks (NtCreateFile/NtOpenFile) failed — tearing down all hooks");
|
||||||
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
||||||
LogDebugA("ERROR: Critical hooks (NtCreateFile/NtOpenFile) failed. Removing all hooks.");
|
LogDebugA("ERROR: Critical hooks (NtCreateFile/NtOpenFile) failed. Removing all hooks.");
|
||||||
@@ -1452,11 +1567,13 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
|
|
||||||
void RemoveNtApiHooks() {
|
void RemoveNtApiHooks() {
|
||||||
__try {
|
__try {
|
||||||
|
SetCrashStage("RemoveNtApiHooks: begin");
|
||||||
CrashLog("=== Removing hooks ===");
|
CrashLog("=== Removing hooks ===");
|
||||||
LogDebugA("=== Removing hooks ===");
|
LogDebugA("=== Removing hooks ===");
|
||||||
g_HooksInitialized = FALSE;
|
g_HooksInitialized = FALSE;
|
||||||
|
|
||||||
// Disable JMP patches in all target functions.
|
// Disable JMP patches in all target functions.
|
||||||
|
SetCrashStage("RemoveNtApiHooks: disabling hooks");
|
||||||
MH_DisableHook(MH_ALL_HOOKS);
|
MH_DisableHook(MH_ALL_HOOKS);
|
||||||
|
|
||||||
// Give any thread that passed the g_HooksInitialized guard but has not yet
|
// Give any thread that passed the g_HooksInitialized guard but has not yet
|
||||||
@@ -1468,6 +1585,7 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
// dangling. NULL them immediately so any racing thread that calls through
|
// dangling. NULL them immediately so any racing thread that calls through
|
||||||
// them gets a clean NULL-dereference AV (caught by the hook's __try/__except)
|
// them gets a clean NULL-dereference AV (caught by the hook's __try/__except)
|
||||||
// rather than a use-after-free at an arbitrary freed address.
|
// rather than a use-after-free at an arbitrary freed address.
|
||||||
|
SetCrashStage("RemoveNtApiHooks: uninitializing MinHook");
|
||||||
MH_Uninitialize();
|
MH_Uninitialize();
|
||||||
|
|
||||||
OriginalNtCreateFile = NULL;
|
OriginalNtCreateFile = NULL;
|
||||||
@@ -1481,15 +1599,18 @@ static inline void _hvnc_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *
|
|||||||
OriginalCreateProcessW = NULL;
|
OriginalCreateProcessW = NULL;
|
||||||
|
|
||||||
if (g_DllRawBytes) {
|
if (g_DllRawBytes) {
|
||||||
|
SetCrashStage("RemoveNtApiHooks: unmapping DLL section");
|
||||||
UnmapViewOfFile(g_DllRawBytes);
|
UnmapViewOfFile(g_DllRawBytes);
|
||||||
g_DllRawBytes = NULL;
|
g_DllRawBytes = NULL;
|
||||||
}
|
}
|
||||||
g_DllRawSize = 0;
|
g_DllRawSize = 0;
|
||||||
if (g_DllSectionHandle) {
|
if (g_DllSectionHandle) {
|
||||||
|
SetCrashStage("RemoveNtApiHooks: closing DLL section");
|
||||||
CloseHandle(g_DllSectionHandle);
|
CloseHandle(g_DllSectionHandle);
|
||||||
g_DllSectionHandle = NULL;
|
g_DllSectionHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCrashStage("RemoveNtApiHooks: cleanup complete");
|
||||||
CrashLog("=== Cleanup complete ===");
|
CrashLog("=== Cleanup complete ===");
|
||||||
|
|
||||||
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ var (
|
|||||||
procWaitForSingleObject = kernel32.NewProc("WaitForSingleObject")
|
procWaitForSingleObject = kernel32.NewProc("WaitForSingleObject")
|
||||||
procCloseHandle = kernel32.NewProc("CloseHandle")
|
procCloseHandle = kernel32.NewProc("CloseHandle")
|
||||||
procResumeThread = kernel32.NewProc("ResumeThread")
|
procResumeThread = kernel32.NewProc("ResumeThread")
|
||||||
|
procGetExitCodeThread = kernel32.NewProc("GetExitCodeThread")
|
||||||
procOpenProcessToken = advapi32.NewProc("OpenProcessToken")
|
procOpenProcessToken = advapi32.NewProc("OpenProcessToken")
|
||||||
procLookupPrivilegeValueW = advapi32.NewProc("LookupPrivilegeValueW")
|
procLookupPrivilegeValueW = advapi32.NewProc("LookupPrivilegeValueW")
|
||||||
procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges")
|
procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges")
|
||||||
@@ -1223,7 +1224,14 @@ func buildEnvironmentBlock(searchPath, replacePath, shmName string, dllSize int)
|
|||||||
extra = append(extra, fmt.Sprintf("RDI_DLL_SIZE=%d", dllSize))
|
extra = append(extra, fmt.Sprintf("RDI_DLL_SIZE=%d", dllSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
return appendEnvironmentOverrides(rawSlice[:blockLen], extra)
|
block, err := appendEnvironmentOverrides(rawSlice[:blockLen], extra)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("hvnc inject env: nativeChars=%d finalChars=%d searchRunes=%d replaceRunes=%d hasDllSection=%v dllSize=%d",
|
||||||
|
blockLen, len(block), len([]rune(searchPath)), len([]rune(replacePath)), shmName != "", dllSize)
|
||||||
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendEnvironmentOverrides(rawBlock []uint16, extra []string) ([]uint16, error) {
|
func appendEnvironmentOverrides(rawBlock []uint16, extra []string) ([]uint16, error) {
|
||||||
@@ -1345,9 +1353,22 @@ func reflectiveInject(hProcess uintptr, dllBytes []byte) error {
|
|||||||
return fmt.Errorf("CreateRemoteThread failed")
|
return fmt.Errorf("CreateRemoteThread failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
procWaitForSingleObject.Call(hThread, INFINITE_WAIT)
|
waitRet, _, waitErr := procWaitForSingleObject.Call(hThread, INFINITE_WAIT)
|
||||||
|
var exitCode uint32
|
||||||
|
if ret, _, callErr := procGetExitCodeThread.Call(hThread, uintptr(unsafe.Pointer(&exitCode))); ret != 0 {
|
||||||
|
log.Printf("hvnc inject: remote loader thread finished wait=0x%x exit=%s", waitRet, describeExitCode(exitCode))
|
||||||
|
} else {
|
||||||
|
log.Printf("hvnc inject: GetExitCodeThread failed after wait=0x%x: %v", waitRet, callErr)
|
||||||
|
}
|
||||||
procCloseHandle.Call(hThread)
|
procCloseHandle.Call(hThread)
|
||||||
|
|
||||||
|
if waitRet == 0xFFFFFFFF {
|
||||||
|
return fmt.Errorf("remote loader thread wait failed: %v", waitErr)
|
||||||
|
}
|
||||||
|
if exitCode >= 0xC0000000 {
|
||||||
|
return fmt.Errorf("remote loader thread failed: %s", describeExitCode(exitCode))
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user