미친해커

[Reversing] Trampoline(Inline) Hooking x64 Step 2 본문

Reversing/Hooking

[Reversing] Trampoline(Inline) Hooking x64 Step 2

미친해커 2022. 5. 3. 13:02
반응형

How to patch the top 12 bytes of the API

이제 후킹하고 싶은 API의 상위 12 바이트를 패치하는 것만 남았다. 기본적으로 DLL의 함수들은 .text 섹션에 존재한다. 해당 섹션의 메모리 보호 옵션은 보통 ER---  쓰기 권한이 빠져있다. 그렇기 때문에 먼저 쓰기 권한을 부여해야만 한다. Windows API 중 특정 영역의 메모리 보호 옵션을 수정하는 함수 VirtualProtect 함수가 있다.

 

VirtualProtectEx function (memoryapi.h) - Win32 apps

Changes the protection on a region of committed pages in the virtual address space of a specified process.

docs.microsoft.com

#include <stdio.h>
#include <windows.h>

int main(int argc, char *argv[])
{
    // GetModuleHandleA 함수로 hModule을 구한다.
    HMODULE hModule = GetModuleHandleA("user32.dll");
    
    // 만약 GetModuleHandleA 함수로 구하지 못하였다면 LoadLibraryA 함수로 DLL을 로드한다.
    if (hModule == NULL)
        hModule = LoadLibraryA("user32.dll");
    
    // GetProcAddress 함수를 이용해 주소를 가져옴
    PVOID pMessageBoxA = (PVOID)GetProcAddress(hModule, "MessageBoxA");
    
    // 원본 메모리 보호 옵션을 저장할 변수
    DWORD OldProtect;
    
    /*
    VirtualProtect 함수를 사용해 MessageBoxA 주소로부터 12바이트 만큼의 메모리 보호 옵션을
    PAGE_EXECUTE_READWRITE(ERW--)로 변경한다.
    */
    if (VirtualProtect(pMessageBoxA, 12, PAGE_EXECUTE_READWRITE, &OldProtect) == FALSE)
    {
        printf("VirtualProtect Failed\n");
        return -1;
    }
    
    printf("Changed the top 12 bytes memory protection option in MessageBoxA to ERW--\n");
}
Changed the top 12 bytes memory protection option in MessageBoxA to ERW--

위 문자열이 출력되면 정상적으로 MessageBoxA 함수의 상위 12 바이트의 메모리 보호 옵션이 수정된 것이다. 수정된 이후에는 해당 영역의 데이터를 수정할 수 있게 된다. 이제 본격적으로 후킹을 시도해보자.

Let's try Trampoline Hooking!!

후킹 함수가 호출되었을 때 원본 함수를 호출하기 위해서는 꼭 다시 원본 코드로 복원 후 호출해야 하고 호출이 끝난 후에는 다시 후킹 코드로 패치해줘야 후킹이 유지될 수 있다.

#include <stdio.h>
#include <windows.h>

BYTE HookCode[12] = { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0 };
BYTE OriginCode[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

int __stdcall NewMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
    // 상위 5 바이트를 원본 코드로 패치
    memcpy(MessageBoxA, OriginCode, 12);
    // lpText 변수를 조작해 함수를 정상적으로 실행
    int ret = MessageBoxA(hWnd, "Hooked..!", lpCaption, uType);
    // 다시 후킹 코드로 패치
    memcpy(MessageBoxA, HookCode, 12);

    // 반환값 전달
    return ret;
}

int main(int argc, char *argv[])
{
    // GetModuleHandleA 함수로 hModule을 구한다.
    HMODULE hModule = GetModuleHandleA("user32.dll");
    
    // 만약 GetModuleHandleA 함수로 구하지 못하였다면 LoadLibraryA 함수로 DLL을 로드한다.
    if (hModule == NULL)
        hModule = LoadLibraryA("user32.dll");

    if (hModule == NULL)
    {
        printf("[-] user32.dll not found\n");
        return -1;
    }

    printf("[+] user32.dll found!\n");

    // GetProcAddress 함수를 이용해 주소를 가져옴
    PVOID pMessageBoxA = (PVOID)GetProcAddress(hModule, "MessageBoxA");
    
    if (pMessageBoxA == NULL)
    {
        printf("[-] MessageBoxA not found\n");
        return -1;
    }

    printf("[+] MessageBoxA found!\n");

    // 원본 메모리 보호 옵션을 저장할 변수
    DWORD OldProtect;
    
    /*
    VirtualProtect 함수를 사용해 MessageBoxA 주소로부터 5바이트 만큼의 메모리 보호 옵션을
    PAGE_EXECUTE_READWRITE(ERW--)로 변경한다.
    */
    if (VirtualProtect(pMessageBoxA, 12, PAGE_EXECUTE_READWRITE, &OldProtect) == FALSE)
    {
        printf("VirtualProtect Failed\n");
        return -1;
    }
    
    printf("[*] Changed the top 12 bytes memory protection option in MessageBoxA to ERW--\n");

    // 점프할 주소를 저장
    *(ULONGLONG *)(HookCode + 2) = (ULONGLONG)NewMessageBoxA;

    printf("[*] Patch code :    ");
    
    for (int i = 0; i < 12; i++)
    	printf("0x%02X ", HookCode[i]);
    
    putchar('\n');
    
    // 원본 12이트 백업
    memcpy(OriginCode, pMessageBoxA, 12);
    printf("[*] Original code : ");
    
    for (int i = 0; i < 12; i++)
    	printf("0x%02X ", OriginCode[i]);

	putchar('\n');

    // 후킹 코드로 패치
    memcpy(pMessageBoxA, HookCode, 12);

    printf("[+] Trampoline Hooking Success!\n");
    printf("Press the any key...");
    getchar();

    // 후킹된 MessageBoxA 함수 호출
    MessageBoxA(NULL, "Not Hooked...!", "Trampoline Hook", 0);

    return 0;
}
[+] user32.dll found!
[+] MessageBoxA found!
[*] Changed the top 12 bytes memory protection option in MessageBoxA to ERW--
[*] Patch code :    0x48 0xB8 0x50 0x15 0x40 0x00 0x00 0x00 0x00 0x00 0xFF 0xE0 
[*] Original code : 0x48 0x83 0xEC 0x38 0x45 0x33 0xDB 0x44 0x39 0x1D 0x02 0x61 
[+] Trampoline Hooking Success!
Press the any key...

정상적으로 실행되었다면 Press the any key가 출력되었을 때 아무 키를 입력하게 되면 코드와 다르게 Not Hooked...! 가 아닌 Hooked...! 라는 메시지를 출력한다.

반응형
Comments