개발/WIN32-MFC

COM HOOK #3 예제 DETOURS + DXGI

-=HaeJuK=- 2024. 9. 12. 13:39
Detours를 이용한 Present 함수 후킹

Detours를 이용한 Present 함수 후킹

이 문서에서는 Microsoft Detours 라이브러리를 사용하여 Direct3D 11IDXGISwapChain::Present 함수를 후킹하는 방법을 설명합니다. Detours는 함수 호출을 가로채고 수정할 수 있는 강력한 라이브러리입니다.

Detours 개념

Detours는 원래의 함수 호출을 가로채고, 후킹된 함수를 먼저 호출하게 만듭니다. 후킹된 함수는 필요에 따라 원래 함수 호출을 수정하거나, 전후 작업을 수행한 후 원래 함수로 돌아갈 수 있습니다. 이 예제에서는 Present 함수가 호출될 때마다 이를 가로채 화면 캡처와 같은 작업을 할 수 있습니다.

IDXGISwapChain::Present 후킹 코드 예제

다음은 C++로 Detours를 사용해 Present 함수를 후킹하는 코드 예제입니다:


// C++ 코드 예제
#include <d3d11.h>
#include <dxgi.h>
#include <iostream>
#include <detours.h>
#include <Windows.h>

// 원래의 Present 함수 정의
typedef HRESULT(__stdcall* PresentType)(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);
PresentType OriginalPresent = nullptr;  // 원래의 Present 함수 포인터

// 후킹된 Present 함수
HRESULT __stdcall HookedPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
{
    // 여기에서 화면 캡처 등의 작업을 할 수 있음
    std::cout << "Present 함수가 호출되었습니다!" << std::endl;

    // 원래의 Present 함수 호출
    return OriginalPresent(pSwapChain, SyncInterval, Flags);
}

// 후킹을 설치하는 함수
void HookPresent()
{
    // D3D11 장치 및 SwapChain을 임시로 생성하여 Present 함수 주소를 얻음
    DXGI_SWAP_CHAIN_DESC sd = {};
    sd.BufferCount = 1;
    sd.BufferDesc.Width = 800;
    sd.BufferDesc.Height = 600;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = GetConsoleWindow();
    sd.SampleDesc.Count = 1;
    sd.Windowed = TRUE;

    ID3D11Device* pDevice = nullptr;
    ID3D11DeviceContext* pContext = nullptr;
    IDXGISwapChain* pSwapChain = nullptr;

    D3D_FEATURE_LEVEL featureLevel;
    HRESULT hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0,
                                               D3D11_SDK_VERSION, &sd, &pSwapChain, &pDevice, &featureLevel, &pContext);
    if (FAILED(hr))
    {
        std::cerr << "D3D11 장치 생성 실패!" << std::endl;
        return;
    }

    // IDXGISwapChain의 Present 함수 주소 가져오기
    void** vTable = *(void***)pSwapChain;
    OriginalPresent = (PresentType)vTable[8];  // vTable의 8번째 슬롯에 Present 함수가 있음

    // Detours를 사용하여 Present 함수를 후킹
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)OriginalPresent, HookedPresent);
    DetourTransactionCommit();

    // 자원 해제
    pSwapChain->Release();
    pDevice->Release();
    pContext->Release();
}

void UnhookPresent()
{
    // Detours를 사용하여 후킹 해제
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach(&(PVOID&)OriginalPresent, HookedPresent);
    DetourTransactionCommit();
}

int main()
{
    // Detours 후킹 설치
    HookPresent();

    // 메시지 루프 대기
    std::cout << "화면 캡처 중..." << std::endl;
    Sleep(10000);  // 예시로 10초 대기

    // Detours 후킹 해제
    UnhookPresent();

    return 0;
    

코드 설명

  • Present 함수 후킹: IDXGISwapChain::Present는 Direct3D에서 화면을 갱신할 때 호출되는 함수입니다. 이를 후킹하여 매 프레임 갱신 시 화면 캡처 작업을 할 수 있습니다.
  • Detours 후킹: Detours 라이브러리를 사용해 원래 Present 함수 대신 HookedPresent 함수를 호출하도록 만듭니다.
  • 후킹된 함수: HookedPresent는 매번 Present가 호출될 때 실행됩니다. 그 후 원래의 Present를 호출하여 정상적인 화면 갱신이 이루어집니다.

주의 사항

  • Detours 라이브러리 설치: Detours는 Microsoft의 후킹 라이브러리로, 상업적 사용 시 라이선스 문제가 있을 수 있으므로 라이선스를 확인하십시오.
  • DirectX SDK: Direct3D 및 DXGI를 사용하려면 DirectX SDK가 프로젝트에 링크되어 있어야 합니다.
  • 성능 주의: 후킹된 함수에서 무거운 작업을 수행하면 성능에 영향을 줄 수 있으므로 주의해야 합니다.
반응형