ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • IAT
    Etc 2017. 6. 13. 02:09

    (2014년에 네이버 블로그에서 작성했던 글을 티스토리로 옮기며 이관했습니다)

     

     

     

    IAT는 Import Address Table의 약자로 프로그램에서 import한 라이브러리에서 사용하는 함수명, 함수 시작 주소가 저장된 테이블입니다.

     

    IAT는 IMAGE_IMPORT_DESCRIPTOR 구조체에서 RVA 형태로 명시되고 있는데요.

    이 구조체는 그 외에도 INT, import한 라이브러리의 이름 등의 값을 저장합니다.

     

    여기서 INT란 Import Name Table의 약자로, import 한 라이브러리의 함수 이름들이 배열 형태로 저장되어 있습니다.

     

    그럼 이제 IMAGE_IMPORT_DESCRIPTOR 구조체에서 필요한 부분만 살펴보도록 하겠습니다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        _ANONYMOUS_UNION union {
            DWORD Characteristics;
            DWORD OriginalFirstThunk;
        } DUMMYUNIONNAME;
        DWORD TimeDateStamp;
        DWORD ForwarderChain;
        DWORD Name;
        DWORD FirstThunk;
    } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
    cs
     
     

    1. Characteristics, OriginalFirstThunk

    - 현재 Characteristics 는 사용되고 있지 않아서 생각하지 않으셔도 됩니다. OriginalFirstThunk는 INT의 RVA를 가리킵니다..

     

    2. Name

    - import 한 라이브러리 이름의 RVA를 가리킵니다.

     

    3. FirstThunk

    - IAT의 RVA를 가리킵니다.

     

     

    그럼 이제 IMAGE_IMPORT_DESCRIPTOR 구조체에 값이 어떻게 저장되어 있는지 직접 확인해 보겠습니다.

     

    먼저 IMAGE_IMPORT_DESCRIPTOR 구조체의 오프셋을 알아내야 합니다.

    이 오프셋은 OPTIONAL HEADER의 DataDirectory 멤버에서 찾을 수 있습니다.

     

    DataDirectory는 IMAGE_DATA_DIRECTORY 구조체의 배열인데 IMAGE_IMPORT_DESCRIPTOR의 오프셋은 이 구조체의 인덱스가 1인 곳에 저장되어 있습니다.

     

    MSDN에 이 구조체를 정리해 놓은 문서가 있는데요. 생각보다 구조는 간단합니다.

    - https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms680305(v=vs.85).aspx

     

     

    1
    2
    3
    4
    typedef struct _IMAGE_DATA_DIRECTORY {
      DWORD VirtualAddress;
      DWORD Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
    cs
     
    1. VirtualAddress
    - directory의 RVA입니다.
     
    2. Size
    - directory의 사이즈입니다.
     
     
    Hxd Editor로 import table를 찾는 절차가 귀찮아서 Stud PE라는 툴로 쉽게 import table 오프셋을 구해봤습니다.
     
    아래 빨간색 네모박스의 오프셋(0x1A0)이 import table의 오프셋인데요. 앞 4바이트가 RVA, 뒤 4바이트가 Size입니다.
     

     

     

     

    그럼 이제 위 IMAGE_DATA_DESCRIPTOR 구조체의 RAW를 구해보도록 하겠습니다.

    참고로 저는 카카오톡 Windows Application을 대상으로 IAT를 구하고 있는데요

     

    IMAGE_DATA_DESCRIPTOR의 RVA는 0xAC906D이고, 이 오프셋이 속한 섹션은 .idata 입니다.

     

    섹션의 VirtualAddress(시작주소)는 0xAC9000이고, Raw Offset(시작위치)는 0x4A7400 입니다.

     

    RAW = 0xAC906D(RVA) - 0xAC9000(VirtualAddress) + 0x4A7400(Section Header Size)

     

    0x4A746D라는 값이 나왔습니다. 이 오프셋이 바로 IMAGE_DATA_DESCRIPTOR입니다.

    DataDirectory에서 확인한 import table의 Size는 0x95이므로 스크롤한 영역이 IMAGE_DATA_DESCRIPTOR입니다.

     

     

     

     

    이제 IMAGE_DATA_DESCRIPTOR 멤버의 값이 각각 어떤 것인지 알아보겠습니다.

    각각의 주소들은 모두 RVA 형태로 되어 있습니다.

     

    - [4Byte] RAW + 0x0 = OriginalFirstThunk(INT)

    - [4Byte] RAW + 0x4 = TimeDateStamp

    - [4Byte] RAW + 0x8 = ForwarderChain

    - [4Byte] RAW + 0xC = Name (import한 라이브러리 이름들)

    - [4Byte] RAW + 0x10 = FirstThunk(IAT)

     

     

     

     

    먼저, OriginalFirstThunk(INT) 값을 직접 살펴보겠습니다.

    INT는 import한 라이브러리의 함수 이름이 담긴 구조체 포인터 배열이라고 했습니다.

    RVA가 0xAC9043으로 아까와 같은 섹션에 속한 주소입니다.

     

    RAW = 0xAC9043 - 0xAC9000 + 0x4A7400

    RAW = 0x4A7443

     

     

    해당 오프셋으로 이동해 보니 또 RVA 배열이 보이는데요. 이 RVA 값들은 각각 IMAGE_IMPORT_BY_NAME 구조체입니다.

     

    배열의 끝은 NULL으로 끝나기 때문에 값이 하나밖에 없는 것으로 보이지만 NULL 뒤의 0xAC901E도 IMAGE_IMPORT_BY_NAME 구조체입니다.

     

    IMAGE_IMPORT_BY_NAME 값 사이의 NULL은 라이브러리의 INT마다 구분자 용도로 사용되는 것입니다.

    즉, 앞의 0xAC9014는 kernel32.dll의 INT이고, 뒤의 0xAC901E는 comctl32.dll의 INT입니다.

     

     

     

     

    RVA -> RAW 작업을 생략하고, 0xAC9014(IMAGE_IMPORT_BY_NAME)의 RAW로 이동해 보겠습니다.

    .1strcpy라고 보여지는데요. strcpy 함수이고, 그 앞의 6C00은 Oridinal 값으로 라이브러리에서 함수의 고유번호를 표기하는 것이라고 합니다.

     

     

     

     

    이번엔 Name 값을 확인해 보겠습니다.

    Name은 라이브러리의 이름이라고 했습니다.

     

    0xAC9053이 Name의 RVA인데요. RAW로 이동해 보면 kernel32.dll, comctl32.dll이라는 동적 라이브러리가 확인됩니다.

     

     

     

     

    마지막으로 FirstThunk(IAT)를 확인해 보겠습니다.

    RVA는 0xAC9033인데요. 이번에도 RAW 계산 과정을 생략하고 PE 분석 전문 툴로 간편하게 확인해 보았습니다.

    그런데 RAW가 INT와 같은 곳을 참조합니다.

     

    PE 로더는 OriginalFirstThunk(INT) 값이 없다면 그제서야 IAT로 메모리 매핑을 시도한다고 합니다.

    IAT는 함수의 VirtualAddress가 하드코딩 되어 있는 구조인데요. (ex: 0x742F2921)

     

    kernel32.dll, comctl32.dll는 고유한 ImageBase를 가지고 있지만 OS에 따라 VirtualAddress가 바뀔 수 있어서 개인적인 생각으로는 IAT에 주소가 하드코딩 되어 있으면 안 될 것 같습니다.

     

    하지만 DLL이 메모리 상에 매핑될 때에는 IAT가 INT가 아닌 함수 주소로 되어 있는데요.

    원리는 이렇습니다.

     

    1. IMAGE_IMPORT_DESCRIPTOR 구조체의 Name 멤버로 라이브러리 이름을 가져옵니다.

    2. LoadLibrary()로 라이브러리의 핸들을 얻습니다.

    3. GetProcAddress() 를 라이브러리의 핸들과 INT의 함수 이름으로 호출하며 함수 주소를 얻고, IAT에 매핑합니다.

    'Etc' 카테고리의 다른 글

    EAT  (0) 2017.07.03
Designed by Tistory.