ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • EAT
    Etc 2017. 7. 3. 02:39

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

     

     

     

     

    EAT(Export Address Table)는 라이브러리에서 함수 시작 주소를 구할 때 사용됩니다.

     

    라이브러리 외 PE 파일은 Export 할 함수가 없으니 EAT를 가리키는 주소가 NULL로 셋팅되어 있습니다.

     

    EAT 정보는 IMAGE_EXPORT_DIRECTORY 라는 구조체에서 확인할 수 있습니다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    typedef struct _IMAGE_EXPORT_DIRECTORY
    {
        DWORD Characteristics;
        DWORD TimeDateStamp;
        DWORD MajorVersion;
        DWORD MinorVersion;
        DWORD Name;
        DWORD Base;
        DWORD NumberOfFunctions;
        DWORD NumberOfNames;
        DWORD AddressOfFunctions;
        DWORD AddressOfNames;
        DWORD AddressOfOrdinals;
    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
    cs

     

     

     

    이 중 중요한 구조체 멤버만 살펴보겠습니다.

     

    1. NumberOfFunctions

    - Export 하는 함수의 개수입니다.

     

    2. NumberOfNames

    - Export 하는 함수 중 이름을 가지는 개수입니다.

     

    3. AddressOfFunctions

    - Export 하는 함수 주소 테이블입니다. NumberOfFunctions 사이즈만큼 존재합니다.

     

    4. AddressOfNames

    - 함수 이름 테이블입니다. NumberOfNames 사이즈만큼 존재합니다.

     

    5. AddressOfNameOrdinals

    - AddressOfNames의 인덱스 번쨰의 함수가 실제 AddressOfFunctions에서 몇 번쨰 인덱스에 위치하는지가 명시되어 있습니다. 스펙에는 DWORD로 명시되어 있지만 실제로는 2바이트로 이루어진 배열입니다.

     

     

    IAT에서 GetProcAddress()를 이용해 import하는 라이브러리의 함수 시작 주소를 구하는데요.

    이 GetProcAddress() 는 EAT의 스펙대로 동작합니다.

     

    GetProcAddress()의 동작원리입니다.
    1. AddressOfNames 에서 함수 이름과 인덱스(이 함수 이름이 몇 번째에 있었는지)를 기억합니다.2. AddressOfNameOrdinals에서 AddressOfNames의 함수가 실제 AddressOfFunctions에서 몇 번째 인덱스에 위치하는지를 구합니다.3. AddressOfFunctions에서 구한 함수 인덱스로 주소를 가져옵니다.

    그럼 kernel32.dll로 IMAGE_EXPORT_DIRECTORY를 찾아보겠습니다.OPTIONAL HEADER -> DataDirectory의 0번째 인덱스에 이 구조체를 가리키는 RVA가 있습니다.

     




    IMAGE_IMPORT_DESCRIPTOR 구조체가 저장된 Import Table 멤버처럼 8바이트입니다.이것 역시 첫 번째 멤버인 0x262C가 RVA, 두 번째 멤버인 0x6CFD가 Size입니다.
    0x262C는 .text 섹션에 속합니다.
    RAW = 0x262C - 0x1000(섹션 시작 위치 RVA) + 400(섹션 시작 위치 RAW)       = 0x1A2C

    AddressOfNames는 아래 캡처의 스크랩한 부분입니다.0x3538 RVA입니다.

     

     

     

     

    0x3538 역시 .text 섹션에 속하니 위 공식에서 RVA만 바꿔서 계산해 줍니다.

    RAW = 0x3538 - 0x1000 + 0x400 = 0x2938

     

    그럼 포인터(RVA)로 이루어진 배열이 나오는데요.

    이 포인터마다 함수 이름을 하나씩 갖고 있을 것입니다.

     

     

     

     

     

    4번째 포인터인 0x4BBC의 RAW를 살펴보겠습니다.

    AddConsoleAliasA() 라는 함수네요.

     

    그럼 AddressOfNameOrdinals 에서 AddressOfFunctions의 실제 위치를 확인해 보겠습니다.

     

    AddressOfNameOrdinals 계산과정은 생략하겠습니다. 0x381C입니다.

    배열의 4번째 인덱스는 3입니다.

     

    AddressOfFunctions 인덱스 3의 위치가 AddConsoleAliasA() 라는 함수의 시작주소겠네요.

     

     

     

     

     

    AddressOfFunctions의 RAW 계산도 마찬가지로 생략합니다. (0x1A54)

    3번째 인덱스를 확인해 보니 0x71CDF로 RVA가 되어 있네요.

     

    kernel32.dll의 ImageBase는 0x7C800000 입니다.

    다른 라이브러리라면 Relocation이 일어나겠지만 커널 영역에 로딩되는 라이브러리들은 각자 고유의 ImageBase를 가지고 있기 떄문에 Relocation이 일어나지 않습니다.

     

    따라서 AddConsoleAliasA() 의 VirtualAddress는 0x7C800000 + 0x71CDF = 0x7C871CDF이 됩니다.

     

    'Etc' 카테고리의 다른 글

    IAT  (0) 2017.06.13
Designed by Tistory.