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
의 필드 중 Name
은 RVA
이다.
즉, 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
의 이름을 통해서 후킹할 모듈을 찾고 iat
와 int
를 통해 대상 api의 주소를 원하는 함수로 바꿔치기 해주면 된다.
끝