[c++] iat hook, descriptor name

wangki·2025년 5월 16일
0

cpp

목록 보기
1/7

개요

iat hook을 진행 시 후킹을 원하는 모듈의 Import Descriptor Table을 순회하며 모듈명을 체크를 한다. 어떻게 Import Descriptor Table에 접근하는 지 간단하게 코드로 살펴보겠다.

void parse_import_descriptor() {
    BYTE* base = (BYTE*)GetModuleHandle(NULL);

    IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base;    // exe의 handle 자체가 결국 dos_header의 base 주소임

    if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
        printf("DOS 헤더 아님\n");
        return;
    }

    IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew);
    if (nt->Signature != IMAGE_NT_SIGNATURE) {
        printf("NT 헤더 아님\n");
        return;
    }

    IMAGE_DATA_DIRECTORY import_dir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    if (import_dir.VirtualAddress == 0) {
        printf("Import Directory 없음\n");
        return;
    }

    IMAGE_IMPORT_DESCRIPTOR* import_desc = (IMAGE_IMPORT_DESCRIPTOR*)(base + import_dir.VirtualAddress);
}

dos header - nt header - import directory - import descriptor table 순으로 접근할 수 있다.

 IMAGE_IMPORT_DESCRIPTOR* import_desc = (IMAGE_IMPORT_DESCRIPTOR*)(base + import_dir.VirtualAddress);

 printf("===== 현재 모듈 Import Table =====\n");
 while (import_desc->Name != 0) {
     char* dll_name = (char*)(base + import_desc->Name);
     printf("DLL: %s\n", dll_name);

     PIMAGE_THUNK_DATA thunk_data = (PIMAGE_THUNK_DATA)(base + import_desc->OriginalFirstThunk);

     while (thunk_data->u1.AddressOfData != 0) {
         // thunk가 ordinal 방식으로 import되었는지 확인
         if (!(thunk_data->u1.Ordinal & IMAGE_ORDINAL_FLAG)) {
             PIMAGE_IMPORT_BY_NAME import_name = (PIMAGE_IMPORT_BY_NAME)(base + thunk_data->u1.AddressOfData);
             printf("   API: %s\n", import_name->Name);
         }
         else {
             WORD ordinal = (WORD)(thunk_data->u1.Ordinal & 0xFFFF);
             printf("   API by ordinal: %u\n", ordinal);
         }
         ++thunk_data;
     }

     ++import_desc;
 }

IMAGE_IMPORT_DESCRIPTOR의 필드 중 NameRVA이다.
즉, base address에 더해주면 descriptor의 이름 문자열의 주소값을 반환한다.

char* dll_name = (char*)(base + import_desc->Name);
printf("DLL: %s\n", dll_name);

위와 같이 출력을 하게되면 현재 import된 모듈의 이름을 알 수 있다.

출력 예시를 보면 KERNEL32.dll이라고 출력된다.
여기서 중요한 것이 있다. 툴체인에 따라서 .dll을 붙일 수도 있고 안 붙일 수도 있다는 것이다.
이것이 왜 중요하냐? iat hook을 하기 위해서 보통 KERNEL32.dll에 있는 api 또는 api set schema를 비교한다. .dll이 붙지 않은 descriptor라면 후킹에서 제외되는 것이다.

결론

descriptor의 이름을 통해서 후킹할 모듈을 찾고 iatint를 통해 대상 api의 주소를 원하는 함수로 바꿔치기 해주면 된다.

0개의 댓글