13.6 EAT(Export Address Table)
라이브러리란 다른 프로그램에서 불러 쓸 수 있도록 관련 함수들을 모아놓은 파일(DLL/SYS)입니다. Win32 API가 대표적인 라이브러리이며, 그 중에서도 kernel32.dll 파일이 가장 핵심적인 라이브러리 입니다.
EAT(Export Address Table)은 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 핵심 메커니즘 입니다. 즉, EAT를 통해서만 해당 라이브러리에서 익스포트하는 함수의 시작 주소를 정확히 구할 수 있습니다. IAT와 마찬가지로 PE 파일 내의 특정 구조체(IMAGE_EXPORT_DIRECTORY)에 익스포트 정보를 저장하고 있습니다. IMAGE_EXPORT_DIRECTORY 구조체는 PE파일에 하나만 존재합니다.
참고로 IAT를 설명하는 IMAGE_IMPORT_DECRIPTOR 구조체는 여러 개의 멤버를 가진 배열 형태로 존재합니다. 왜냐하면 PE파일은 여러 개의 라이브러리를 동시에 임포트 할 수 있기 때문입니다.
PE 파일에서 IMAGE_EXPORT_DIRECTORY 구조체 위치는 PE 헤더에서 찾을 수 있습니다. IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress 값이 실제 IMAGE_EXPORT_DIRECTORY 구조체 배열의 시작 주소 입니다.
Offset | 데이터 | 설명 |
0x0168 | 2C 26 00 00 | VirtualAddress (RVA) |
0x016C | FD 6C 00 00 | Size (테이블 크기) |
1. VirtualAddress (RVA)
- 값: 0x0026262C (리틀 엔디언 방식이므로 0x262C로 해석)
- 설명: Export Table이 메모리에서 RVA 0x262C 위치에 로드됩니다.
- RVA 값이 262C이므로 FileOffset은 1A2C입니다.
2. Size
- 값: 0x00006CFD (리틀 엔디언 방식이므로 **0x6CFD**로 해석)
- 설명: Export Table의 크기는 0x6CFD 바이트입니다.
13.6.1 IMAGE_EXPORT_DIRECTORY
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; // 예약된 필드 (일반적으로 0)
DWORD TimeDateStamp; // 생성 시간 (UNIX 타임스탬프)
WORD MajorVersion; // 주요 버전 (일반적으로 0)
WORD MinorVersion; // 부 버전 (일반적으로 0)
DWORD Name; // DLL 이름의 RVA
DWORD Base; // Ordinal의 시작 번호
DWORD NumberOfFunctions; // ★실제 Export 함수 개수
DWORD NumberOfNames; // ★Export 함수 중 이름을 가지는 함수 개수
DWORD AddressOfFunctions; // ★Export 함수 주소 배열(배열의 원소 개수 = NOF)
DWORD AddressOfNames; // ★함수 이름 주소 배열(배열의 원소 개수 = NON)
DWORD AddressOfNameOrdinals; // ★Ordinal 테이블의 RVA(배열의 원소 개수 = NON)
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
라이브러리에서 함수 주소를 얻는 API는 GetProcAddress()입니다. 이 API가 바로 EAT를 참조해서 원하는 API 주소를 구하는 것입니다.
예시: "MessageBoxA"를 검색하는 과정
GetProcAddress()를 사용해 DLL에서 "MessageBoxA()"의 주소를 찾는 과정을 설명하겠습니다. kernel32.dll을 예로 들겠습니다.
FARPROC GetProcAddress(
HMODULE hModule, // DLL의 모듈 핸들
LPCSTR lpProcName // 함수 이름 또는 Ordinal
);
과정 설명
- DLL 로드 및 Export Table 접근
- hModule이 kernel32.dll의 메모리 베이스 주소를 가리킨다고 가정.
- LoadLibrary("kernel32.dll")로 kernel32.dll을 메모리에 로드하고, 베이스 주소(Base Address)를 가져옵니다.
- Export Table의 시작 위치를 찾습니다:
- PE Header → Optional Header → Data Directory[0]를 따라가면 Export Directory Table에 접근할 수 있습니다.
- AddressOfNames 배열로 이동
- AddressOfNames는 Export Name Table의 시작 위치를 나타냅니다.
- 이 배열에는 함수 이름(예: "MessageBoxA") 문자열들의 RVA 목록이 들어 있습니다.
- 함수 이름 비교
- "lpProcName**이 문자열인 경우
- Export Name Table에서 각 이름의 RVA를 통해 문자열을 확인합니다.
- strcmp("MessageBoxA", ExportName[i])로 원하는 이름을 찾습니다.(이진 탐색 사용)
- 찾은 이름의 인덱스(name_index)를 저장합니다.
- "lpProcName**이 문자열인 경우
- Ordinal 검색
- "lpProcName"이 숫자(Ordinal)로 전달된 경우:
- Export Directory Table의 Base 필드를 사용하여 실제 Ordinal 번호를 계산.
- 계산된 Ordinal 번호를 EAT의 인덱스로 사용.
- EAT에서 함수의 RVA를 가져옵니다.
- "lpProcName"이 숫자(Ordinal)로 전달된 경우:
- AddressOfNameOrdinals 배열로 이동
- AddressOfNameOrdinals는 함수 이름과 Export Address Table (EAT)의 인덱스를 연결합니다.
- name_index를 사용해 Ordinal 값을 가져옵니다.
- Export Address Table 접근
- AddressOfFunctions는 EAT(Export Address Table)의 시작 위치를 나타냅니다.
- Ordinal 값을 사용해 EAT에서 해당 함수의 RVA를 가져옵니다.
- RVA를 실제 주소로 변환
- DLL의 Base Address와 RVA를 더해 MessageBoxA 함수의 실제 메모리 주소를 계산합니다.
- 주소 반환
- 계산된 MessageBoxA()의 메모리 주소를 반환합니다.
13.6.2 kernel32.dll를 이용한 실습
실습 내용은 따로 포스팅하여 실습해보도록 하겠습니다.
13.7 Advanced PE
13.7.1 PEView.exe
13.7.2 Patched PE
13.8 마무리
'게임해킹 > 리버싱 핵심원리(나뭇잎책)' 카테고리의 다른 글
13장. IAT - 실습 해보기 (1) | 2025.01.22 |
---|---|
2부. 13장 PE File Format(2) (1) | 2025.01.16 |
11장 Lena's Reversing for Newbies (2) | 2024.12.16 |
10장 함수 호출 규약 (4) | 2024.12.04 |
9장 Process Explorer - 최고의 작업 관리자 (2) | 2024.11.26 |