Search

'후킹'에 해당되는 글 1건

  1. 2011.06.16 Detours Hooking Framework - 1. hooking function (13)

Detours Hooking Framework - 1. hooking function

프로그래밍 2011.06.16 00:37 Posted by 아일레프

최근 Hooking을 해야 할 일이 생겼다. 그런데 이 Hooking할 함수가 dll의 일반 export함수도 아니고, 클래스 멤버의 함수도 아니고, COM객체의 virtual 함수라 이리저리 많은 삽질을 해야했다. 그러다 Detours란 Hooking Framework를 만나게 되었는데 와, 이거 정말 훌륭하더라. 물론 Virtual 함수를 Hooking하는 것은 이리저리 많은 삽질을 거쳐야 했지만, 프로그래밍이란게 한번 알고 나면 너무 간단해 허무한 것이다. 고로 지금 허무하다.

 

설치.

Detours Hooking Framework 이 사이트에서 Detours Express 2.1을 다운로드 받고 설치하자. default 경로는 C:\Program Files (x86)\Microsoft Research\Detours Express 2.1 이다. 해당 폴더에 Command Prompt로 이동해 nmake all 명령을 실행하자. 본인은 nmake all 명령이 실패했는데 나의 문제는 Visual Studio의 Command Prompt를 이용하고 set DETOURS_TARGET_PROCESSOR =x86 을 설정함으로써 해결할 수 있었다.

 

Function Hooking

이제 Detours를 사용해보자. Visual Studio에 DetoursTest를 만들고 C/C++, Linker 환경을 설정하자. C/C++의 Additional Include Directories에 Detours Express의 Include 디렉토리를 추가하고, Linker의 Additional Library Directories에 Detours Express의 lib 디렉토리를 추가한다. 그리고 Linker의 Additional Dependencies에 detoured.lib, detours.lib를 추가한다. 그후 main.cpp란 파일을 추가 한 후 다음 코드를 넣자.


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

void TestFunction(){
    printf("TestFunction Called\n");
}

void HookingFunction(){
    printf("before - TestFunction call");
    TestFunction();
    printf("after - TestFunction call");
}

int main(int, char**){
    TestFunction();
    getchar();
}

main에서 TestFunction을 call했으므로 당연히 CMD 창에 "TestFunction Called" 문장이 나타날 것이다. 이제 TestFunction을 Hooking해 TestFunction()을 호출하면 HookingFunction()이 호출되게 할 것이다. 그리고 이 일은 굉장히 간단하다. 프로그램을 다음과 같이 바꿔보자.


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

void TestFunction(){
    printf("TestFunction Called\n");
}
void (*pfTrueTestFunction)() = TestFunction;
void HookingFunction(){
    printf("before - TestFunction call\n");
    TestFunction();
    //pfTrueTestFunction();
    printf("after - TestFunction call\n");
}

int main(int, char**){
    DWORD error;
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach((PVOID*)&pfTrueTestFunction, HookingFunction);
    error = DetourTransactionCommit();

    if (error == NO_ERROR) {
        printf("\n");
    }
    else{
        printf("fail to attach\n");
    }
    TestFunction();
    getchar();
}

프로그램을 실행하면 어떤 일이 벌어질까? before - TestFunction Call 문장이 반복되어 출력될 것이다. 원하는 동작을 원한다면 HookingFunction의 TestFunction()을 주석처리하고 pfTrueTestFunction function pointer로 기존 메소드를 출력하면 된다.

어떻게 이 일이 가능하게 되었을까? DetourAttach 함수 콜에 Breakpoint를 설정하고 TestFunction과 pfTrueTestFunction의 값을 확인해보자.

TestFunction 주소 값과 pfTrueTestFunction 값이 다르지만 pfTrueTestFunction 주소 값의 Assembly 명령어를 확인하면 Jmp 명령어로 TestFunction으로 점프하는 코드가 있음을 확인 할 수 있다. 그리고 그 명령어 위에 'TestFunction:'이 있는데 이것이 함수 symbol값이다. 

이제 DetourAttach명령과 DetourTransactionCommit()까지 프로그램을 진행시켜보자. Watch창으로 TestFunction과 pfTrueTestFunction을 다시 확인해보자. 재미있게도 pfTrueTestFunction의 주소 값이 바뀌었다.

pfTrueTestFunction의 값이 변경되었음을 알 수 있다. 0x010c0060메모리 주소를 보면 TestFunction의 메모리로 점프하는 코드가 있다.

 

더 재미있는 것은 0x010e12bc의 메모리주소의 값이 변경되었다는 사실에 있다.

TestFunction: 심볼 값에 Jmp TestFunction 명령이 있었는데 Jmp HookingFunction으로 변경되었다. 이것이 DetourAttach명령과 DetourTransactionCommit이 하는 일이다. 이것으로 후킹이 완료되었다. 

 

마치며

Detours로 특정 함수 심볼 값을 변경해 후킹을 해보았다. 이런 방식으로 기존의 exe파일이나 dll파일을 후킹할 수도 있다. detours의 bin 폴더 내에는 setdll이란 명령어가 있는데 이를 이용하면 된다. 이 setdll명령은 기존의 exe파일이나 dll파일에 외부의 dll을 로드하게하는 명령어이다. 예를 들어
setdll /d:dllInject.dll notepad.exe
명령을 실행시키면 이후에 notepad.exe를 실행했을 때 프로그램 내부에서 dllInject.dll이 로드되게 된다. 즉 LoadLibrary("dllInject.dll")이 실행되게 되는 것이다. 이 dll이 로드되면 dll내부의 DllMain함수가 실행되게 되고, 만약 DllMain함수 내에서 DetourAttach 등으로 Hooking동작을 하는 코드가 있다면 notepad.exe내에서 호출하는 함수, API들을 Hooking할 수 있다.
 

 2로 계속됩니다.

** 2001. 07. 01 수정.
setdll /d:dllInject.dll executable.exe를 실행시키면 dllInject.dll이 executable.exe에 Inject된다고 위에 설명했었다. 이것은 사실이다. 그런데 난 멋도 모르고 어떻게 추측했었냐면, .text의 EntryPoint에 LoadLibrary("dllInject.dll") 코드를 명시적으로 실행시켜 dllInject.dll의 DllMain 함수가 실행되게 할 줄 알았다. 하지만 사실은 이와 달라 정정한다. Dll Loading의 방식에는 2가지가 있는데 그 중 하나는 명시적 로딩, 즉 코드 내에서 LoadLibrary("dllInject.dll")이라고 명시적으로 코딩을 하는 방법이고, 또 하나는 암시적 로딩으로써 프로그램이 시작하는 순간에 같이 로딩되는 방법이 있다. 암시적 로딩을 위해 PE 파일은 어떤 DLL파일을 로드 해야 하는지 명시해 PE Loader에게 알려야 한다. Detours 는 PE파일의 이 부분을 변경한다. 즉, dllInject.dll이 필요하다고 PE Loader에게 알리는 것이다. 자세한 부분은 www.reversecore.com/23에 잘 설명되어 있다. 

신고


 

티스토리 툴바