티스토리 뷰

PE Header - IAT(IMPORT ADDRESS TABLE)


DLL?

Dynamic Link Library 의 약자로, "동적 링크 라이브러리" 라고도 불리며, 마이크로소프트에 윈도우에서 구현된 여러 프로그램이 공통으로 필요로 하는 기능을 따로 분리하여, 필요할 때에만 불러내어 쓸 수 있게 만들어 놓은 라이브러리이다.




예를 들어, 크롬에서도 메세지박스를 띄울 수 있고, Windows 탐색기에서도 메시지박스를 띄울 수 있다. 이럴 경우, 각각의 프로그램에 모두 메시지박스를 띄우는 기능의 코드를 내장하는 것이 아니라, 윈도우에서 지원하는 기능(DLL)에서 가져다 씀으로써 각각의 파일들에 해당 기능들을 집어넣을 필요 없이, 원하는 DLL을 사용해 이 기능을 끌어다 쓴다고 선언해놓으면 된다. (이러한 기능을 하는 것이 바로 IAT이다.)


이렇게 특정 기능을 끌어쓰는 방법에는 크게 2가지 방법이 존재하는데,

Explict Linking : DLL을 사용할 때만 메모리에 로드하고, 사용이 끝난다면, 곧바로 해제한다.

Implict Linking : 프로그램이 시작되는 순간 DLL을 로드하고, 프로그램에 끝나면 해제한다.

또한, 굳이 자신은 DLL을 이용하기 싫다! 라고 한다면 Static Linking으로 프로그램 안에 미리 사용할 모든 DLL의 함수들을 같이 집어넣어 컴파일하는 방법이 있다.



ABOUT IAT

먼저 IAT가 실제로 어떻게 사용되는지 알아보도록 하자.

다음은 필자가 테스트로 컴파일해본 "test2.exe" 파일의 printf() 함수를 호출하는 부분의 어셈블러 코드이다.


CALL NEAR PTR DS:[ADDRESS] 의 형식으로 call 을 수행하고 있다. 여기서 중요한 점은,

CALL ADDRESS 식으로 주소를 이용해 바로 호출하는 것이 아닌, 해당 메모리 주소를 포인터로 이용해, 해당 주소에 들어있는 주소값으로 call 명령어가 수행된다는 것이다.


굳이 절대 주소로 call 을 하지 않을까?

첫번째로는 시스템마다 예외가 있지만 대표적으로 microsoft에서 기본적으로 지원하는 시스템 dll 라이브러리의 경우, 각각의 함수 주소가 윈도우의 버전이나, service pack, 그리고 시스템 언어에 따라 달라질 수 있다.

그러므로 이러한 dll의 주소를 절대적으로 적어놓지 않고, 실제로 프로그램이 실행되었을 때 dll을 프로그램에 로드하고, 해당 함수의 주소를 IAT에 적어둔다.

두번째로는 dll 이 프로그램에 로드될 때, 서로 다른 2개의 dll이 로드되었는데, ImageBase가 서로 같아져버리는 경우가 있을 수 있다. 이런 경우 하나의 dll 을 다른 ImageBase에 로드하고, 이에 대한 알맞은 함수의 주소를 IAT에 입력하기 위해서이다.


* 그림 참고.

[!] DS:MEMADDR 형식으로 되어 있는데,  왜 DS(Data Segment)인지는 나중에 내용 추가 필요.

즉 IAT(Import Address Table)이란,

프로그램에서 사용할 외부 라이브러리가 메모리에 로드되고 난 후, 해당 함수의 주소를 가지고 있는 테이블이다.



IMAGE_IMPORT_DESCRIPTOR

IAT는 로드된 dll 에서 사용할 함수의 주소값을 담고 있는 역할을 하는 테이블이다.

그렇다면, 어떤 dll을 로드하고, 어떤 함수를 가져와 사용할 것인가? 에 대한 정보를 저장하는 역할을 하는 것이 바로

PE 헤더에 포함되어 있는 IMAGE_IMPORT_DESCRIPTOR IMAGE_IMPORT_BY NAME 이다.

< IMAGE_IMPORT_DESCRIPTOR> - Import Directory Table

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;

일반적으로, 프로그램에서는 여러개의 라이브러리를 가져와서 사용하게 된다.

이 때, 위 구조체를 배열 형식으로 만들게 되며, 구조체 배열의 마지막은 전부 NULL 로 채우게 된다.

또한, IMAGE_IMPORT_DESCRIPTOR가  IMAGE_IMPORT_BY_NAME 의 주소를 포함하고 있다.


1. OriginalFirstThunk

해당 IMAGE_IMPORT_BY_NAME (INT)의 주소값 : RVA

[!] 포인터. 한 다리 더 걸쳐가면 해당 구조체가 존재한다.

IMAGE_IMPORT_BY_NAME 해당 구조체가 뭉쳐있는 것은 배열이라고 하기 어렵다. 애초에 string이 뭉쳐 있으므로 가변이고,

중간중간 이 문자열의 길이 때문에 align 이 존재함.

다시 말해 해당 값은 IMAGE_IMPORT_BY_NAME의 포인터 배열이라고 보는 것이 맞을듯.


2. Name

Library 이름 문자열의 주소(example.dll) 의 포인터 : RVA


3. FirstThunk

IAT(Import Address Table)의 주소 : RVA

해당 주소에 로드된 dll : 함수의 주소가 씌여지게 된다.


<IMAGE_IMPORT_BY_NAME> - Import Name Table

typedef struct _IMAGE_IMPORT_BY_NAME { WORD Hint; BYTE Name[1]; } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

OriginalFirstThunk가 가리키고 있는 IMAGE_IMPORT_BY_NAME 구조체 배열을 이루고 있다.


1. Hint 

해당 dll에서 해당 함수와 ImageBase와의 간격.


2. Name

원하는 함수의 이름.


** Stripped 된 바이너리의 경우, Name에 대한 정보가 없고 HInt(Ordinal)만 존재할 수도 있다.


정리하자면, 다음과 같이 구성되어 있다.




+ 동작 과정

1. 모든 섹션을 메모리에 로드하고, DataDirectory에서 Import Directory Table의 주소를 찾아 읽는다. (IID - Image Import Descriptor)

2. 해당 구조체의 Name 값을 얻어, DLL을 메모리에 로드한다.

3. INT - Import Name Table 에서 Name or Ordinal을 읽어 로드된 DLL에서의 시작 주소를 찾아 읽는다.

4. 해당 값을 IAT 주소에 기록한다.

5. 위 과정을 반복한다.

- IAT 주소에 4바이트 간격을 두어, Name Table에 기재되어있는 차례대로 해당 함수의 주소를 입력한다.

- NULL 구조체를 만나면 다음 Import Directory Table(IID)로 넘어가, 위의 과정을 반복한다.

- IID 의 NULL 구조체를 만나면, 해당 작업을 종료한다.


+ RVA를 이용해 FileOffset을 알기 위해서는 해당 데이터가 존재한 섹션을 찾아, 해당 섹션과의 Offset을 이용해 파일에서의 위치를 찾으면 되겠다.

[!] 주어지는 RVA : ImageBase와의 간격


참고:

http://www.reversecore.com/23 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함