-
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 - RVA 262C → File Offset 1A2C
- 262C - 1000 + 400 (참고 : https://wh514.tistory.com/24 )
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)
'리버싱 엔지니어링 > 리버싱 핵심 원리' 카테고리의 다른 글
15 UPX 실행 압축된 notepad 디버깅 (0) 2022.03.27 14 실행 압축 (0) 2022.03.25 13 PE File Format(4) - IAT (0) 2022.03.23 13 PE File Format(3) - RVA to RAW (0) 2022.03.23 13 PE File Format(2) - PE 헤더(DOS Header, NT Header,섹션 헤더) (0) 2022.03.23 - 라이브러리 : 다른 프로그램에서 불러 쓸 수 있도록 관련 함수들을 모아놓은 파일(DLL/SYS)