Search

'멤버 함수 후킹'에 해당되는 글 1건

  1. 2011.07.29 Detours Hooking Framework - 3-2. Hooking class member function (6)

이전 글

Detours Hooking Framework 1 - Hooking Function

Detours Hooking Framework 2 - Hooking API

Detours Hooking Framework 3-1 Hooking class member function

 

잠시 복습

지난 글에서 class member function을 호출했을 때 컴파일 된 assembly에 대해 살펴보았다. 나머지는 전부 제쳐두고 다음을 기억하면 됐다.


    int result1 = a.TestFunction(10);
008E1612  push        0Ah  
008E1614  lea         ecx,[a]  
008E1617  call        TestClass::TestFunction (8E111Dh)  

class의 instance의 주소를 ecx에 넣고 해당 함수를 콜 한다는 규칙이었다. 자, 이것을 기억해두고 class member function을 후킹해보자.

 

 

Hooking class member function


#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <detours.h>

class TestClass{
private :
    int mInt;

public :
    TestClass() : mInt(0){}
    TestClass(int initValue) : mInt(initValue){}
    int TestFunction(int iValue);
};

int TestClass::TestFunction(int iValue){
    return mInt + iValue;
}

int HookingFunction(int value){
    std::cout<<"Hooked" <<std::endl;
    //여기서­ 진짜 멤버 함수를 호출해야한다.
    return 0;
}
int main(int argc, char** argv){
    TestClass a(10),b(20);

    int result1 = a.TestFunction(10);

    return 0;
}


위 코드에서 TestClass의 TestFunction함수를 후킹해보자. Detours를 사용하기 위해 TestClass::TestFunction과 HookingFunction의 address를 넘겨야 한다. 이때 main()함수의 코드는 다음과 같게 된다.


int HookingFunction(int value){
    std::cout<<"Hooked" <<std::endl;
    //여기서 진짜 멤버 함수를 호출해야 한다.
    return 0;
}

PVOID functionAddress ;

int main(int argc, char** argv){
    TestClass a(10),b(20);
    functionAddress = (PVOID)(&(PVOID&)TestClass::TestFunction);

    DWORD error;
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach((PVOID*)&functionAddress, HookingFunction);
    
    error = DetourTransactionCommit();

    int result1 = a.TestFunction(10);

    return 0;
}

위 작업으로 a.TestFunction(10)을 실행했을 때 HookingFunction이 호출되게 된다. 기존 TestClass::TestFunction이 존재하던 Address에 jmp HookingFunction이란 코드가 대치되었기 때문이다. 그런데 HookingFunction코드 내에서 어떻게 TestClass::TestFunction을 실행할 수 있을까?

 

TestClass::TestFunction 을 실행하기 위한 조건은 다음과 같았다. 먼저 TestClass의 instance, a의 주소를 ecx에 넘겨 주어야 하고 TestClass::TestFunction의 address를 call해야 한다. 그런데 문제가 있다. a의 주소를 HookingFunction 내에서 알아낼 방법이 없다는 것이다. a의 주소는 ecx로 넘어 오기 때문에 알 수 있지 않냐고 생각할 수 있겠지만 ecx를 일반함수 HookingFunction에서 보존한다는 보장이 없기 때문이다. 만약 ecx값을 보존한다면 다음과 같이 코딩하면 되겠지만 이는 실패한다.


int HookingFunction(int value){
    std::cout<<"Hooked" <<std::endl;
    int result;
    __asm push value;
    __asm call [functionAddress];
    __asm mov [result], eax;
    return result;
}


그럼 어떻게 해야할까? 답은 의외로 간단하다. 일반 함수로 Hooking하는 것이 아니라 클래스의 멤버함수로 Hooking하면 된다. 다음과 같이 말이다.


class HookingClass{
public:
    int HookingFunction(int value){
        std::cout<<"Hooked" <<std::endl;
        int result;
        __asm push value;
        __asm mov ecx, [this];
        __asm call [functionAddress];
        __asm mov [result], eax;
        return result;
    }
};


int main(int argc, char** argv){
    TestClass a(10),b(20);
    functionAddress = (PVOID)(&(PVOID&)TestClass::TestFunction);

    DWORD error;
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach((PVOID*)&functionAddress, (PVOID)(&(PVOID&)HookingClass::HookingFunction));
    
    error = DetourTransactionCommit();

    int result1 = a.TestFunction(10);

    return 0;
}


위 코드를 실행시키면 HookingClass::HookingFunction(int value)내에서 TestClass::TestFunction을 실행할 수 있음을 알 수 있다. __asm mov ecx, [this];  에서 [this]가 곧 instance a의 주소이다. 이때 __asm으로 어셈블리 코드를 직접 사용하는 것이 싫으면 다음과 같이 하면 된다.


#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <detours.h>

class TestClass{
private :
    int mInt;

public :
    TestClass() : mInt(0){}
    TestClass(int initValue) : mInt(initValue){}
    int TestFunction(int iValue);
};

int TestClass::TestFunction(int iValue){
    return mInt + iValue;
}

class HookingClass{
public:
    int HookingFunction(int value);
    static int (HookingClass::*Real_Target)(int);
};

int HookingClass::HookingFunction(int value)
{
    std::cout<<"Hooked" <<std::endl;
    return (this->*Real_Target)(value);
}
int (HookingClass::* HookingClass::Real_Target)(int) = (int (HookingClass::*)(int))&TestClass::TestFunction;

int main(int argc, char** argv){
    TestClass a(10),b(20);

    DWORD error;
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)HookingClass::Real_Target, (PVOID)(&(PVOID&)HookingClass::HookingFunction));
    
    error = DetourTransactionCommit();

    int result1 = a.TestFunction(10);

    return 0;
}


굉장히 아름다운 이 방법은 detours의 sample에 포함된 소스코드를 참조한 것이다. 붉은 색으로 된 코드를 보고 그 안에 담긴 의미를 음미해보라. 다음 마지막이 될 다음 포스트에는 virtual function을 후킹하는 법에 대하 알아보도록 한다.

 

신고


 

티스토리 툴바