나만의 메모노트

[리버싱 핵심원리] PE File Format (5) 본문

Security/Reversing

[리버싱 핵심원리] PE File Format (5)

sp3arm4n 2021. 8. 1. 04:23

EAT (Export Address Table)

  • Windows OS에서 라이브러리(Library)란?
    • 다른 프로그램에서 불러 쓸 수 있도록 관련 함수들을 모아 놓은 파일 (DLL/SYS)
      • 대표적인 라이브러리 : Win32 API
      • 핵심 라이브러리 파일 : kernel32.dll
  • 개념 : 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 핵심 메커니즘
    • 해당 라이브러리에서 Export하는 함수의 시작 주소를 정확히 구할 수 있음
    • Export 정보는 PE 파일 내 특정 구조체(IMAGE_EXPORT_DIRECTORY)에 저장
      • IMAGE_EXPORT_DIRECTORY 구조체는 PE File에 하나만 존재하며, PE Header에서 확인 가능
      • 실제 IMAGE_EXPORT_DIRECTORY 구조체 배열의 시작 주소
        • IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress (RVA) 값
  • kernel32.dll binary
    kernel32.dll 파일의 IMAGE_OPTIONAL_HEADER32.DataDirectory[0]
  • kernel32.dll 파일의 DataDirectory 배열 - Export
    offset value description
    00000160 00000000 loader flags
    00000164 00000010 number of directories
    00000168 0000262C RVA of EXPORT Directory
    0000016C 00006D19 size of EXPORT Directory
    00000170 00081898 RVA of IMPORT Directory
    00000174 00000028 size of IMPORT Directory
  • IMAGE_EXPORT_DIRECTORY 구조체
    IMAGE_EXPORT_DIRECTORY 구조체
    • 주요 멤버
      멤버명 의미
      NumberOfFunctions 실제 Export 함수 개수
      NumberOfNames Export 함수 중에서 이름을 가지는 함수 개수 (<=NumberOfFuncions)
      AddressOfFunctions Export 함수 주소 배열 (배열의 원소 개수 = NumberOfFunctions)
      AddressOfNames 함수 이름 주소 배열 (배열의 원소 개수 = NumberOfNames)
      AddressOfNameOrdinals Ordinal 배열 (배열의 원소 개수 = NumberOfNames)
    • kernel32.dll 파일의 IMAGE_EXPORT_DIRECTORY 구조체와 EAT 전체 구조
      kernel32.dll 파일의 IMAGE_EXPORT_DIRECTORY 구조체와 EAT 전체 구조
      kernel32.dll
      • Export하는 모든 함수에 이름이 존재
      • AddressOfNameOrdinals 배열의 값이 index = ordinal 형태
      • 예외
        • Export하는 함수 중 이름이 존재하지 않는 경우 (Ordinal로만 Export)
        • AddressOfNameOrdinals 배열의 값이 index != ordinal인 경우
    • GetProcAddress()
      • 라이브러리에서 함수 주소를 얻는 API
        • 해당 API가 바로 EAT를 참조 → 원하는 API 주소 획득
      • 동작 원리
        • AddressOfNames 멤버를 이용해 '함수 이름 배열'로 이동
          • '함수 이름 배열'은 문자열 주소가 저장되어 있음
        • 문자열 비교(strcmp)를 통해 원하는 함수 이름 찾기
          • 이 때 배열의 인덱스 = name_index
        • AddressOfNameOrdinals 멤버를 이용해 'ordinal 배열'로 이동
        • 'ordinal 배열'에서 name_index로 해당 ordinal 값 찾기
        • AddressOfFunctions 멤버를 이용해 '함수 주소 배열(EAT)'로 이동
        • '함수 주소 배열(EAT)'에서 원하는 함수의 시작 주소를 획득
          • 이 때 ordinal 값 = name_index
    • 함수 이름 없는 Ordinal 값에 IMAGE_EXPORT_DIRECTORY.Base 멤버를 뺀 값을 '함수 주소 배열(EAT)'의 인덱스로 하여 Export된 함수 주소를 찾을 수 있음
    • 위 동작 원리의 순서를 따라야만 정확한 함수 주소를 얻을 수 있음