2012-02-17 3 views
11

후킹에 관심이있어서 몇 가지 기능을 연결할 수 있는지 알아보기로했습니다. 우회로와 같은 도서관을 사용하는 것에 관심이 없었습니다. 왜냐하면 저는 혼자서 그것을하는 경험이 있기를 원하기 때문입니다. 인터넷에서 찾은 일부 소스를 통해 아래 코드를 만들 수있었습니다. 그것은 기본이지만 괜찮습니다. 그러나 여러 스레드에서 호출하는 함수를 후크하는 경우 매우 불안정합니다. 거의 동시에 두 번의 전화가 걸리면 전화가 끊깁니다. 몇 가지 연구를 한 후에 트램펄린 기능을 만들어야한다고 생각합니다. 시간을 모두 찾은 후에 나는 트램펄린이 무엇인지에 대한 일반적인 설명과 다른 것을 찾을 수 없었습니다. 나는 트램펄린 기능을 쓰는 방법이나 그들이 실제로 어떻게 작동했는지 구체적으로 알 수 없었다. 어떤 사람이 글을 쓰거나, 글을 올리거나, 적어도 몇몇 기사, 사이트, 책 등을 추천함으로써 올바른 방향으로 나를 가리킬 수 있다면 큰 도움이 될 것입니다.후크 용 트램펄린 기능을 만드는 방법

다음은 작성한 코드입니다. 그것은 정말로 기본적인 것이지만 다른 사람들이 그것으로부터 배울 수 있기를 바랍니다.

Test.cpp에

#include "stdafx.h" 

Hook hook; 

typedef int (WINAPI *tMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); 

DWORD hMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) 
{ 
    hook.removeHook(); 
    tMessageBox oMessageBox = (tMessageBox)hook.funcPtr; 
    int ret =oMessageBox(hWnd, lpText, "Hooked!", uType); 
    hook.applyHook(&hMessageBox); 

    return ret; 
} 

void hookMessageBox() 
{ 
    printf("Hooking MessageBox...\n"); 
    if(hook.findFunc("User32.dll", "MessageBoxA")) 
    { 
     if(hook.applyHook(&hMessageBox)) 
     { 
      printf("hook applied! \n\n"); 
     } else printf("hook could not be applied\n"); 
    } 
} 

hook.cpp 여러 스레드에서 호출 할 때 후크가 안전하려면

#include "stdafx.h" 

bool Hook::findFunc(char* libName, char* funcName) 
{ 
    Hook::funcPtr = (void*)GetProcAddress(GetModuleHandleA(libName), funcName); 
    return (Hook::funcPtr != NULL); 
} 

bool Hook::removeHook() 
{ 
    DWORD dwProtect; 
    if(VirtualProtect(Hook::funcPtr, 6, PAGE_EXECUTE_READWRITE, &dwProtect)) 
     { 
     WriteProcessMemory(GetCurrentProcess(), (LPVOID)Hook::funcPtr, Hook::origData, 6, 0); 
     VirtualProtect(Hook::funcPtr, 6, dwProtect, NULL); 
     return true; 
    } else return false; 
} 

bool Hook::reapplyHook() 
{ 
    DWORD dwProtect; 
    if(VirtualProtect(funcPtr, 6, PAGE_EXECUTE_READWRITE, &dwProtect)) 
     { 
     WriteProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, Hook::hookData, 6, 0); 
     VirtualProtect(funcPtr, 6, dwProtect, NULL); 
     return true; 
    } else return false; 
} 

bool Hook::applyHook(void* hook) 
{ 
    return setHookAtAddress(Hook::funcPtr, hook); 
} 

bool Hook::setHookAtAddress(void* funcPtr, void* hook) 
{ 
    Hook::funcPtr = funcPtr; 
    BYTE jmp[6] = { 0xE9, //jmp 
        0x00, 0x00, 0x00, 0x00, //address 
        0xC3 //retn 
       }; 

    DWORD dwProtect; 

    if(VirtualProtect(funcPtr, 6, PAGE_EXECUTE_READWRITE, &dwProtect)) // make memory writable 
    { 

     ReadProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, Hook::origData, 6, 0); // save old data 
     DWORD offset = ((DWORD)hook - (DWORD)funcPtr - 5); //((to)-(from)-5) 
     memcpy(&jmp[1], &offset, 4); // write address into jmp 
     memcpy(Hook::hookData, jmp, 6); // save hook data 
     WriteProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, jmp, 6, 0); // write jmp 
     VirtualProtect(funcPtr, 6, dwProtect, NULL); // reprotect 

     return true; 
    } else return false; 
} 
+0

나는 GD에 대한 링크를 게시하려고했으나 그곳에 회원이 있다는 것을 눈치 챘다. 검색 기능을 사용해 보셨습니까? 그것은 많은 예제를 제공합니다. –

+0

EasyHook의 코드를 확인할 수 있습니다. 오픈 소스라고 생각합니다. 주위에 다른 예제도 많이 있습니다. 이것을 배포 된 응용 프로그램에서 사용할 계획이라면 후크/트램펄린, 스레딩 및 재미있는 것들에 대한 재귀를 이미 처리 할 수있는 라이브러리 (예 : EasyHook)를 사용하는 것이 좋습니다. – ssube

+0

@Tom Knapen 게시하기 전에 GD, MPGH 및 기타 다른 사이트를 검색했습니다. GD에서 '트램펄린'을 검색하면 약간의 관련 게시물이 반환되지만 내가 원하는 것은 아닙니다. – Stratus

답변

7

, 당신은 지속적으로 unhooking과 rehooking되고 싶지 않아 원래 API.

트램펄린은 원래 API의 처음 몇 바이트 (점프로 덮어 쓴)의 기능을 복제 한 코드 중 하나이며, 덮어 쓴 바이트 뒤에 API로 점프합니다.

API를 푸는 것보다 API를 호출하고 다시 호출하면 trampoline을 호출하기 만하면됩니다.

이것은 명령 경계를 찾기 위해 (최소한의) 디스어셈블러가 필요하기 때문에 x86에서 다소 복잡합니다. 또한 trampoline으로 복사 한 코드가 명령어 포인터 (jmp, branch 또는 call과 같은)와 관련이 없는지 확인해야합니다.

이것은 쓰레드 안전을위한 호출을하기에 충분하지만, 다중 쓰레드가 API를 사용하고 있다면 훅을 생성 할 수 없습니다. 이를 위해서는 2 바이트 단위의 점프 (원자 적으로 작성할 수 있음)로 함수를 연결해야합니다. Windows API는이 점프 점프를위한 목표를 제공하기 위해 자주 몇 번의 NOP (먼 점프로 덮어 쓸 수 있음)로 시작합니다.

x64에서이 작업을 수행하는 경우 이 더 복잡합니다. 64 비트 원거리 점프로 함수를 간단히 패치 할 수는 없습니다 (하나가 없기 때문에 멀리 시뮬레이션하는 지침이 너무 길어집니다). 그리고 트램펄린이하는 일에 따라 OS의 스택 해제 정보에 추가해야 할 수도 있습니다.

너무 일반적인 것이 아니기를 바랍니다.

+0

고마워요. 그러나 이것은 제가 이미 발견 한 것이기 때문에 제가 글을 쓰는 데 도움이되지 않습니다. – Stratus

+0

@Stratus : 무엇을 놓치셨습니까? 일부 실행 메모리를 할당하십시오. 함수 프롤로그에서 할당 된 메모리로 n 바이트를 복사하고 prolog + n 함수로 점프하여 그 뒤에옵니다. n은 함수 프롤로그에서 적어도 5 바이트를 비우기 위해 복사해야하는 명령어의 크기입니다. 그건 트램펄린이야. 다른 주름 (IP를 수정하는 지침을 복사하지 않는 것과 같은)이 있지만 그것이 기본입니다. – arx

관련 문제