개발/WIN32-MFC

COM HOOK #1 개념

-=HaeJuK=- 2024. 9. 12. 13:24

 

COM 인터페이스 vtable 후킹

COM(컴포넌트 객체 모델) 인터페이스 후킹은 특정 COM 객체의 메서드 호출을 가로채고 이를 수정하거나 모니터링하는 기법입니다. 이 문서에서는 vtable 후킹을 사용하여 COM 인터페이스의 메서드를 후킹하는 방법을 설명합니다.

vtable 후킹 개념

COM 인터페이스는 C++의 가상 함수 테이블(vtable)을 통해 메서드 호출을 관리합니다. vtable 후킹은 이 가상 함수 테이블을 수정하여 원래 메서드 대신 사용자가 정의한 함수로 대체하는 방식입니다.

COM vtable 후킹 코드 예제

다음은 C++로 COM 인터페이스의 QueryInterface 메서드를 후킹하는 예제입니다.


// C++ 코드 예제
#include <Windows.h>
#include <iostream>
#include <objbase.h>

typedef HRESULT(STDMETHODCALLTYPE* QueryInterfaceType)(IUnknown* pThis, REFIID riid, void** ppvObject);

// 원본 QueryInterface 함수 포인터를 저장할 변수
QueryInterfaceType OriginalQueryInterface = nullptr;

// 후킹된 QueryInterface 함수
HRESULT STDMETHODCALLTYPE HookedQueryInterface(IUnknown* pThis, REFIID riid, void** ppvObject)
{
    std::cout << "QueryInterface가 호출되었습니다!" << std::endl;

    // 원래의 QueryInterface 함수 호출
    return OriginalQueryInterface(pThis, riid, ppvObject);
}

void HookCOMMethod(IUnknown* pInterface)
{
    // COM 객체의 vtable 가져오기
    void** vtable = *(void***)pInterface;

    // QueryInterface의 원본 함수 포인터 저장
    OriginalQueryInterface = (QueryInterfaceType)vtable[0]; // QueryInterface는 vtable의 첫 번째 항목

    // 메모리 보호 속성을 변경하여 vtable 수정 가능하도록 설정
    DWORD oldProtect;
    VirtualProtect(&vtable[0], sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProtect);

    // QueryInterface를 후킹 함수로 대체
    vtable[0] = (void*)HookedQueryInterface;

    // 메모리 보호 속성을 원래대로 복원
    VirtualProtect(&vtable[0], sizeof(void*), oldProtect, &oldProtect);
}

int main()
{
    // COM 라이브러리 초기화
    CoInitialize(nullptr);

    // COM 객체 생성 (여기서는 샘플로 IUnknown 객체 생성)
    IUnknown* pUnknown = nullptr;
    HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, nullptr, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);

    if (SUCCEEDED(hr) && pUnknown)
    {
        // QueryInterface를 후킹
        HookCOMMethod(pUnknown);

        // QueryInterface 호출 테스트 (후킹된 함수가 실행됨)
        IUnknown* pTest = nullptr;
        pUnknown->QueryInterface(IID_IUnknown, (void**)&pTest);

        if (pTest)
        {
            pTest->Release();
        }

        pUnknown->Release();
    }

    // COM 라이브러리 종료
    CoUninitialize();

    return 0;
}
    

설명

  • QueryInterfaceType: QueryInterface 메서드의 함수 포인터 타입을 정의합니다.
  • OriginalQueryInterface: 원본 QueryInterface 함수 포인터를 저장하기 위한 변수입니다.
  • HookedQueryInterface: 후킹된 QueryInterface 함수로, 후킹 동작을 정의하고 원래 메서드를 호출할 수 있습니다.
  • HookCOMMethod: COM 객체의 vtable을 후킹하는 함수입니다.

주의 사항

  • 메모리 보호: vtable은 읽기 전용 메모리에 저장되므로 수정할 때는 메모리 보호 속성을 변경해야 합니다.
  • 참조 카운트: COM 객체는 참조 카운트를 사용해 메모리를 관리하므로, AddRefRelease 호출을 신중하게 관리해야 합니다.
반응형