미친해커

[Reversing] EAT Hooking Step 2 본문

Reversing/Hooking

[Reversing] EAT Hooking Step 2

미친해커 2022. 7. 28. 04:10
반응형

이번 포스팅에서는 EAT에서 함수의 주소를 구하는 원리와 EAT 후킹 방법에 대해 설명하려고 한다. EAT는 IAT와 다르게 오프셋이 저장되기 때문에 x86이라면 모를까 x64 환경에서는 100% 성공한다고 장담할 수는 없다. 하지만 해당 블로그는 따로 명시되어 있지 않다면 Windows x64를 기준으로 작성하기 때문에 x64 환경에서 EAT 후킹 방법에 대해서 설명하려고 한다.

How to do EAT hooking ways?

EAT에서 사용하는 오프셋은 최대 4바이트로 Windows x64는 8바이트 주소를 사용하기 때문에 해당 DLL의 ImageBase로부터 4바이트 이상의 주소로 이동하도록 후킹할 수는 없다.

 

위에서 설명했지만 주소가 4바이트를 넘지 않는다면 오프셋만 덮어씌워서 후킹이 가능하다. (여기에서는 편리를 위해 x86을 기반으로 코드를 작성하겠다)

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

int WINAPI NewMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
    return MessageBoxA(hWnd, "Hooked..!", "Hooked..!", uType);
}

int main(int argc, char *argv[])
{
    ULONG_PTR ImageBase = GetModuleHandleA("user32.dll");

    if (ImageBase == NULL)
        ImageBase = LoadLibraryA("user32.dll");

    int (WINAPI *HookMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT) = GetProcAddress(ImageBase, "MessageBoxA");
    HookMessageBoxA(NULL, "Not Hooked..!", "Not Hooked..!", 0);

    printf("[*] Module Name : user32.dll\n");
    printf("[*] ImageBase : %p\n", ImageBase);

    IMAGE_DOS_HEADER *DOS = ImageBase;
    printf("[*] Image Dos Header : 0x%p\n", DOS);

    IMAGE_NT_HEADERS *NT = ImageBase + DOS->e_lfanew;
    printf("[*] Image Nt Header : 0x%p\n", NT);

    IMAGE_EXPORT_DIRECTORY *EXPORT = ImageBase + NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    printf("[*] Export Table : 0x%p\n", EXPORT);

    printf("[+] Number Of Functions : %d\n", EXPORT->NumberOfFunctions);
    printf("[+] Number Of Names : %d\n", EXPORT->NumberOfNames);

    DWORD *AddressOfFunctions = ImageBase + EXPORT->AddressOfFunctions;
    DWORD *AddressOfNames = ImageBase + EXPORT->AddressOfNames;
    WORD *AddressOfNameOrdinals = ImageBase + EXPORT->AddressOfNameOrdinals;

    for (int i = 0; i < EXPORT->NumberOfNames; i++)
    {
        if (strcmp(ImageBase + AddressOfNames[i], "MessageBoxA") == 0)
        {
            DWORD flOldProtect;
            VirtualProtect(&AddressOfFunctions[AddressOfNameOrdinals[i]], 4, PAGE_READWRITE, &flOldProtect);
            AddressOfFunctions[AddressOfNameOrdinals[i]] = (ULONG_PTR)NewMessageBoxA - (ULONG_PTR)ImageBase;
            break;
        }
    }

    HookMessageBoxA = GetProcAddress(ImageBase, "MessageBoxA");
    HookMessageBoxA(NULL, "Not Hooked..!", "Not Hooked..!", 0);

    return 0;
}

EAT Hooking.exe
0.05MB

[*] Module Name : user32.dll
[*] ImageBase : 766C0000
[*] Image Dos Header : 0x766C0000
[*] Image Nt Header : 0x766C00E8
[*] Export Table : 0x7675CC10
[+] Number Of Functions : 1215
[+] Number Of Names : 998

위 코드를 x86 아키텍쳐로 컴파일 후 실행하면 처음에 GetProcAddress 함수를 이용해 구한 함수는 정상적으로 메시지가 출력되지만 두번째에 GetProcAddress 함수를 이용해 구한 함수는 인자가 조작되어 호출되는 것을 확인할 수 있따.

 

이렇게 GetProcAddress 함수를 통해 구한 MessageBoxA 함수의 주소와 NewMessageBoxA 함수의 주소가 같은 것을 확인할 수 있다. 하지만 IAT를 통해 함수를 호출하는 경우에는 후킹이 되지 않고 정상적인 호출이 가능하다.

반응형
Comments