본문 바로가기

0x00 /0x01 Reversing

- EAT (Export Address Table / PE File 관련)

# 이번 포스팅은 "EAT(Export Address Table)" 입니다. 한동안 공부를 더럽게 안하다가 다시 책을 펼쳐 공부를 

   시작하기로 했습니다.ㅎ 마지막 포스팅이 PE File의 IAT(Import Address Table) 이였었죠. 라이브러리에서 사용할

   함수등에 대한 정보를 기재하고 있는 테이블에 대한 내용이었습니다. 이번에는 라이브러리 파일에서 제공하는 함

   수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 EAT에 대해서 알아보도록 하겠습니다.






# EAT (Export Address Table)


- Export는 라이브러리 자신이 가지고 있는 함수를 다른 PE 파일에게 제공하는 것을 의미합니다. 만약 다른 PE 파일에서 "kernel32.dll"이라는

  라이브러리에 존재하는 함수를 사용하고 싶다 했을 때, "kernel32.dll"의 EAT(Export Address Table)을 통해서 사용하고자 하는 함수의 

  시작 주소를 구할 수 있습니다. Export 할 함수에 대한 정보를 담고 있는 Export Address Table의 주소는 PE 헤더->NT Header_Optional 

  Header->DataDirectory 구조체의 배열 중 첫 번째 구조체인 DataDirectory[0] 구조체에 IMAGE_EXPORT_DIRECTORY 구조체의 위치

  (RVA)와 크기 정보가 명시되어 있습니다.




# 지금부터 EXPORT 정보를 저장하고 있는 IMAGE_EXPORT_DIRECTORY 구조체에 대해서 알아보도록 하죠.




# IMAGE_EXPORT_DIRECTORY 


- 앞에서 말했듯이 IMAGE_EXPORT_DIRECTORY 구조체는 해당 라이브러리에서 EXPORT 할 함수들에 대한 정보를 담고 있는 구조체입니다.

  구조체를 한번 보고 각 멤버 변수들에 대해 알아보도록 합시다.



[ IMAGE_EXPORT_DIRECTORY 구조체 (출처:winnt.h) ]




- 위에 보이시는 것이 IMAGE_EXPORT_DIRECTORY 구조체입니다. 여기에서 실제로 중요한 멤버는 5가지 정도가 되겠습니다. 

  그 멤버들을 확인해보죠.



[ 출처 : 리버싱핵심원리 ]



# GetProcAddress() API 

- GetProcAddress() API 함수는 라이브러리에서 함수 주소를 얻을 때 사용하는 API 함수입니다. 이 API가 EAT(Export Address Table)를 

  참고하여 원하는 함수의 주소를 구하는 것입니다.



 # GetProcAddress() API 동작 원리 - 인자로 함수의 이름 또는 함수의 Ordinal 값이 들어갑니다.


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


2. '함수 이름 배열'은 문자열 주소가 저장되어 있습니다. 문자열 비교(strcmp)를 통하여 원하는 함수 이름 찾음

   (이때 배열의 인덱스를 name_index 라고 가정)


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


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


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


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

   [ 출처 : 리버싱핵심원리 ]



# user32.dll 을 통해서 위의 내용을 실습해 보도록 하겠습니다. (PEView , HXD 사용)


1. 우선 PEView 툴을 이용하여 user32.dll 의 IMAGE_EXPORT_DIRECTORY 구조체 영역을 찾아가보도록 하죠.

    IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[0] 구조체를 찾습니다.


- DataDirectory[0] 구조체를 보면 EXPORT Table의 RVA 값과 Size 값을 확인할 수 있습니다.  


- 위에서 구한 RVA 값을 이용하여, RAW 값을 구해봅시다. (RVA to RAW 내용을 아셔야 해요. 모르시는 분은 앞의 포스팅을 참고하시길 바래요)

  우선 IMAGE_EXPORT_DIRECTORY 구조체의 RVA 값이 "10548" 이라는 것을 확인할 수 있습니다. RAW 값을 구하기 위해서 어느 Section

  인지 확인해보도록하죠.




- 이 사진에서 윗쪽 넓게 드래그된 부분(파란색)이 IMAGE_NT_HEADERS 구조체 멤버인 IMAGE_OPTIONAL_HEADER 구조체입니다. 그 부분

   가운데 160h부터 IMAGE_DATA_DIRECTORY 구조체 배열이 시작되는 부분이구요. 가장 첫 번째 구조체 배열 원소인 DataDirectory[0] 

  구조체를 빨간 테두리로 표시했는데요. 160~164 부분이 IMAGE_EXPORT_DIRECTORY 구조체의 RVA 주소를 나타내며, 뒤이은 4Byte가

  IMAGE_EXPORT_DIRECTORY 구조체의 사이즈를 나타냅니다. 위에서 PEView로 확인한 "10548"과 같은 값인걸 확인할 수 있습니다.


- 그 아래는 이제 섹션 헤더 부분이 되겠는데요. 각 섹션 헤더 마다 다른 색으로 표시를 해두었습니다. 각 섹션 헤더에는 섹션들의 정보를 가지고 

  있는데요.

  RVA 값과 PointerToRawData 값도 확인할 수 있습니다. 각 섹션 헤더 첫번째 테두리(파란색)는 해당 섹션의 RVA 값을 나타내구요, 각 두번째

  테두리(빨간색)는 PointerToRawData 값을 나타냅니다. RAW 값을 구하기 위해서 확인해야 할 값들이라 한번 확인해본 것입니다.


- 그럼 이제 RAW 값을 구해보도록 하죠. 우선 IMAGE_EXPORT_DIRECTORY 구조체의 RVA 값이 "10548" 입니다. 그럼 .text Section 영역에 

  해당되겠네요. 따라서, VirtualAddress 값은 "10000" 이 되고, PointerToRawData 값은 "400" 이 됩니다. 

  그럼 아래의 식에 대입해서 RAW 값을 구하면,



  RAW = RVA - VirtualAddress + PointerToRawData        ->       RAW = 10548 - 10000 + 400 = "948" 

 


 # IMAGE_EXPORT_DIRECTORY 구조체의 RAW 값은 948 입니다. 

   그럼 구한 RAW 값을 이용해서 헥사에디터로 찾아가보도록 합시다.



- HXD를 이용해서 IMAGE_EXPORT_DIRECTORY 구조체를 찾아가 해당 구조체 부분을 드래그한 모습입니다.

  이 부분이 위에서 공부했던, IMAGE_EXPORT_DIRECTORY 구조체 부분이며, 앞에서 보신 여러가지 멤버 변수들이 포함되어 있습니다.


- 정확한지 PEView를 통해서 다시 보도록하죠.


- 보이시나요? 앞에서 구한 RAW 값이 "948"로 일치하는게 확인되구요. 멤버 변수들이 가지고 있는 값들을 확인할 수 있습니다. 

- 라이브러리 이름도 보이구요.ㅎ



- 이 부분은 IMAGE_EXPORT_DIRECTORY 구조체 멤버 중 AddressOfNames 멤버 변수가 가지고 있는 RVA 값을 RAW 값으로 변경해서, 함수

  이름들의 주소를 가지고 있는 EXPORT Name Pointer Table을 찾아가, 실제 함수 이름이 저장되어 있는 부분을 찾아온 모습입니다.


- 바로 앞부분에서 IMAGE_EXPORT_DIRECTORY 구조체의 멤버 변수들을 이용해서 여러 부분들을 살펴 보았습니다. 

  다시 한번 강조하고 싶은 부분은 GetProcAddress() API를 이용하여 참조하고자 하는 함수 주소를 찾는데 있어서 EAT를 활용하여 찾는다는

  점입니다. 따라서, EAT(Export Address Table)는 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 쓸 수 있도록 해주는

  핵심이다. 뭐 이런 내용인것 같습니다.




# 급하게 포스팅하느라, 부족한 부분이 많이 있네요. 나중에 천천히 GetProcAddress() 동작 원리좀 다시 봐야겠습니다.

  이번 포스팅은 여기서 마무으리...


 






# 참고 도서 및 참고 자료


- 리버싱 핵심원리

- Windows 구조와 원리