Windows PE(Portable Executable) File Format - 4
IAT / EAT
PE 파일에는 어떤 라이브러리에서 어떤 함수를 사용하고 있는지에 대한 정보를 가지고 있는데 이 정보를 IAT(Import Address Table) 라고 한다. 또 비슷한 맥락으로 PE 파일이 어떤 함수를 제공하는지에 대한 정보도 가지고 있는데 이 정보를 EAT(Export Address Table) 라고 한다.
라이브러리
IAT는 어떤 라이브러리에서 어떤 함수를 사용하고 있는지에 대한 정보를 가지고 있는 테이블이라고 했는데 이 때 라이브러리가 어떤 걸 뜻하는지 우선 알아본다.
프로그램을 작성할 때 코드 재사용 및 개발시간 단축등을 위해서 자주 사용하는 공통적인 함수, 데이터 등을 묶어놓은 것을 뜻한다. 이 때 윈도우에서 라이브러리는 크게 정적라이브러리와 동적 라이브러리로 2 가지로 구분할 수 있다.
정적 라이브러리 (LIB)
정적 라이브러리는 프로그램을 작성 후 최종 실행 파일이 만들어질 때 라이브러리의 내용이 최종 실행 파일 코드 자체에 포함되는 형식이다.
동적 연결 라이브리리 (DLL, Dynamic Link Library)
위에서 알아본 정적 라이브러리의 단점으로는 라이브러리 전체가 모두 실행파일에 포함되어 실행파일의 용량이 커지고 프로그램이 실행되어 메모리에 로드되었을 때 사용하지 않는 코드들도 같이 로드가 되기 때문에 메모리의 낭비도 생기게 된다. 그 문제를 해결하기 위해서 동적 연결 라이브러리라는 개념이 등장하게 된다.
정적 라이브러리와의 차이점은 라이브러리의 내용이 실행 파일에 포함되어 있지 않고 별도의 파일로 분리되어 있고 프로그램이 실행되어 메모리에 로드될 때 같이 로드되게 된다.
동적 연결 라이브러리가 항상 프로그램 실행 시 메모리에 로드되는 것은 아니고 아래 2 가지의 로드 방식을 가지고 있다.
암시적 링크 (Implict Linking) 프로그램의 실행과 동시에 메모리에 로드되었다가 프로그램 종료 시 메모리에서 해제되는 방법.
명시적 링크 (Explicit Linking) 프로그램에서 해당 라이브러리를 실제 사용하는 시점이 로드하고 사용이 완료되면 메모리에서 해제하는 방법.
IAT(Import Address Table)
이제 여기까지 알아보면 IAT가 어디에 사용되는지 알 수 있게 된다. IAT는 프로그램이 암시적 링크로 동적 연결 라이브러리를 사용하는 경우 실행 시 로드해야 할 DLL과 함수에 대한 정보를 제공한다.
IAT에 대한 정보는 이전에 알아본 NT 헤더에 존재하는 IMAGE_OPTIONAL_HEADER 구조체에 있는 DataDirectory 필드를 통해 알아낼 수 있다. DataDirectory[1].VirtualAddress 필드에서 IAT를 나타내는 구조체의 시작 주소(RVA)값을 알아낼 수 있다.
IMAGE_IMPORT_DESCRIPTOR
IAT에 대한 정보를 가지고 있는 DataDirectory[1].VirtualAddress 주소는 _IMAGE_IMPORT_DESCRIPTOR 구조체 배열의 시작 주소를 나타낸다.
보통은 프로그램은 여러 개의 라이브러리를 임포트 하는 경우가 많은데, 그렇기 때문에
_IMAGE_IMPORT_DESCRIPTOR구조체 배열의 형태를 가지고 있고 마지막 구조체의 경우 NULL로 끝나게 된다. (별도로 사이즈에 대한 정보를 가지고 있지는 않다)
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)
DWORD ForwarderChain; // -1 if no forwarders
DWORD Name;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
CHAR Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
위 구조체의 멤버 중 아래 3개의 멤버가 중요하다.
- OriginalFirstThunk
- INT(Import Name Table)의 주소(RVA) (INT의 각 요소는
_IMAGE_IMPORT_BY_NAME구조체 배열의 시작 주소가 들어있다, 마찬가지로 배열의 마지막인 경우 NULL)
- INT(Import Name Table)의 주소(RVA) (INT의 각 요소는
- Name
- 라이브러리의 이름 문자열의 주소(RVA) (예를 들어 Kernel32.dll 에서 CreateFileW 함수를 Import 하고 있다면 이 멤버에 "Kernel32.dll" 문자열에 대한 주소가 들어있다.)
- FirstThunk
- IAT(Import Address Table)의 주소(RVA) (IAT의 각 요소는 Import 하는 함수들의 시작 주소가 들어있다. 마찬가지로 배열의 마지막인 경우 NULL)
- 파일 자체에는 INT와 동일한 값이 들어가 있지만 PE 로더에 의해 실행되면 실제 함수의 주소에 쓰여진다

참고
https://research32.blogspot.com/2014/12/int-in-notepadexe.html