ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 13 PE File Format(5) - EAT
    리버싱 엔지니어링/리버싱 핵심 원리 2022. 3. 24. 23:08

     EAT 

    : EAT(Export Address Table)는 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 핵심 메커니즘

     

    • 라이브러리 : 다른 프로그램에서 불러 쓸 수 있도록 관련 함수들을 모아놓은 파일(DLL/SYS)
      • Win32 API가 대표적 라이브러리, 그 중에서도 kerner32.dll 파일이 핵심적인 파일
    • EAT를 통해서만 해당 라이브러리에서 익스포트하는 함수의 시작 주소를 정확히 구할 수 있음
      • PE 파일 내의 IMAGE_EXPORT_DIRECTORY에 익스포트 정보를 저장
      • PE 파일에 하나만 존재 
    • IMAGE_EXPORT_DIRECTORY 위치 → PE 헤더에서 IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress 값이 시작 주소

    kernel32.dll  파일의 IMAGE_OPTIONAL_HEADER32.DataDirectory[0]

    offset value description
    00000168 262C RVA of EXPORT Directory
    0000016C 6CFD size of EXPORT Directory

     

     IMAGE_EXPORT_DIRECTORY  

    • IMAGE_EXPORT_DIRECTORY 구조체
    typedef struct _IMAGE_EXPORT_DIRECTORY {
        DWORD Characteristics;
        DWORD TimeDateStamp;                // creation time date stamp
        WORD MajorVersion;
        WORD MinorVersion;
        DWORD Name;                         // address of library file name
        DWORD Base;                         // ordinal base
        DWORD NumberOfFunctions;            // number of functions
        DWORD NumberOfNames;                // number of names
        DWORD AddressOfFunctions;           // address of function start address array
        DWORD AddressOfNames;               // address of function name string array
        DWORD AddressOfNameOrdinals;        // address of ordinal array
    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

    중요 멤버

    항목 의미
    NumberOfFunctions 실제 Export 함수 개수
    NumberOfNames Export 함수 중에서 이름을 가지는 함수 개수 (<=NumberOfFunctions)
    AddressOfFunctions Export 함수 주소 배열 (배열 원소 개수 = NumberOfFunctions)
    AddressOfNames 함수 이름 주소 배열 (배열의 원소 개수 = NumberOfNames)_
    AddressOfNameOrdinals Ordinal 배열 (배열의 원소 개수 = NumberOfNames)

     

    라이브러리에서 함수 주소를 얻는 API : GetProcAddress()

    GetProcAddress() 동작원리

    1. AddressOfNames 멤버를 이용해 '함수 이름 배열'로 이동

    2. '함수 이름 배열'은 문자열 주소가 저장, 문자열 비교(strcmp)를 통해 원하는 함수 이름을 찾음(이때의 배열 인덱스를 name_index라 가정)

    3. AddressOfNameOrdinals 멤버를 이용해 'ordinal 배열'로 이동

    4. 'ordinal 배열'에서 name_index로 해당 ordinal값을 찾음

    5. AddressOfFunctions 멤버를 이용해 '함수 주소 배열(EAT)'로 이동

    6. '함수 주소 배열(EAT)'에서 아까 구한 ordinal을 배열 인덱스로 하여 원하는 함수의 시작 주소를 얻음

     

    IMPORT_EXPORT_DIRECTIORY 구조체와 EAT 전체 구조 

    kernel32.dll

    • kernel32.dll의 경우 AddressOfNameOrdinals 배열의 값이 index = ordinal 형태로 되어있음
      • 익스포트하는 함수 중에 이름이 존재하지 않을 수 있음. 따라서, index != ordinal인 경우도 있음.

    kernel32.dll을 이용한 실습

    : kernel32.dll 파일의 EAT에서 AddAtomW 함수 주소를 찾는 실습

     

    IMAGE_EXPORT_DIRECTORY 구조체 RAW는 1A2C : Hex Editor

    File Offset Member Value RAW
    1A2C Characteristic 00000000 -
    1A30 TimeDateStamp 48025BE1 -
    1A34 MajorVersion 0000 -
    1A36 MinorVersion 0000 -
    1A38 Name 00004B8E 3F8E
    1A3C Base 00000001 -
    1A40 NumberOfFunctions 000003B9 -
    1A44 NumberOfNames 000003B9 -
    1A48 AddressOfFunctions 00002654 1A54
    1A4C AddressOfName 00003538 2938
    1A50 AddressOfNameOrdinals 0000441C 381C

     

    1. 함수 이름 배열

    AddressOfNames 값은 RVA = 3538 RAW = 2938

    • 배열의 원소의 개수 = NumberOfNames(03B9)
    • RVA 값을 하나하나 따라가면 함수 이름 문자열이 나타남

     

    2. 원하는 함수 이름 찾기

    RVA = 4B9B → 3F9B로 가서 'AddAtomW' 찾기

    • 배열의 세 번째 원소, 배열 인덱스(index) : 2

     

    3. Ordinal 배열

    RVA = 441C → 381C로 가서  'AddAtomW' 함수의 Ordinal 값 알아내기

    • 2바이트 ordinal로 이루어진 배열
    • index 값(2)을 배열에 적용
      • AddressOfNameOrdinals[index] = ordinal (index = 2, ordinal = 2)

     

    4. 함수 주소 배열 - EAT

    AddressOfNames 값은 RVA = 2654 → RAW = 1A54

    • AddressOfFunctions[ordinal] = RVA (ordinal = 2, RVA = 000326D9)
    • AddAtomW 함수 주소 = ImageBase + RVA(00326D9)

    댓글

Designed by Tistory.