Windows API Hooking
User-Mode Hooking
IAT(Import Address Table) Hooking
Inline Function Hooking (Detour Hooking)
사용할 API의 첫 5byte(x86)를 자신이 만든 가짜 함수로 JMP 하는 코드로 바꾸는 방식.
가짜 함수에서 여러 조작을 한 뒤 다시 API의 시작 위치로 돌려줄 수도 있고, 가짜 함수 내부적으로 원본 API를 호출한뒤 리턴하는 방법도 있다.
JMP 의 OPCode는 “E9"이며, 사용되는 주소는 상대주소이다. 코드의 주소는 명령어의 시작 위치이고 점프는 그 명령어 다음부터 세기때문에 E9 01000000 이라고 해도 명령어 크기(5byte)만큼은 일단 이동하기때문에 총 6byte를 움직이는걸 알 수 있다.
주소가 0x410000 이고, 0x420000으로 JMP 하는 코드인데, E9 FBFF0000 => FFFB(0x10000 - 0x5) 만큼만 점프하는것을 알 수 있다.
JMP 상대주소 = 0x420000 - 0x410000 - 5 임을 알 수 있다.
제자리로 점프하는 코드도 -5byte 점프해야하고, 만약 도착지가 더 낮은주소라도 계산방법은 같다.
typedef int (__stdcall *tFunction)(int, int, double, char*); // 함수포인터 별칭지정
tFunction oFunction = NULL;
int __stdcall hkFunction(int a, int b, double c, char *d)
{
int ret;
printf("before Execute Function\n");
ret = oFunction(a, b, c, d);
printf("after Execute Function\n");
return (ret);
}
void *SetHook(BYTE *src, const BYTE *dst)
{
BYTE *org_gadget = malloc(10);
DWORD dwBack;
VirtualProtect(src, 5, PAGE_EXECUTE_READWRITE, &dwBack);
memcpy(org_gadget, src, 5); // 기존 코드 저장
*src = 0xE9;
*(DWORD*)(src + 1) = dst - src - 5; // E9 __ __ __ __ 점프할 주소 값을 채워야한다. LittleEndian
// 후킹 이후 사용할 원본함수 가젯
*(DWORD*)(org_gadget + 5) = 0xE9;
*(DWORD*)(org_gadget + 6) = (src + 5) - (org_gadget + 5) - 5; // 현재위치에서 원본함수로 돌아가기
// src는 더이상 코드수정이 필요없으니 권한원복, 가젯은 원본호출전 실행해야되기 때문에 권한줌
VirtualProtect(src, 5, dwBack, &dwBack);
VirtualProtect(org_gadget, 10, PAGE_EXECUTE_READWRITE, &dwBack);
return (org_gadget);
}
oFunction = SetHook(src, hkFunction);
후킹을 위해 JMP코드를 원본 함수에 삽입했기때문에 그 코드는 손실되어버린다.
후킹함수에서 원하는 코드를 실행하고난 뒤 다시 원본함수를 호출해야하는데, 손실된 원본 코드와 원본함수 + 5 위치로 점프하는 코드를 같이 가젯에 담고 실행시켜주면 손실된 코드도 실행되며 원본 함수로 복구된다.
만약 후킹을 단 한번만 한다면 후킹함수에서 원본 코드를 복원하는 방법도 사용할 수 있을것이다.
Comments