알쓸전컴(알아두면 쓸모있는 전자 컴퓨터)

[reversing] EAT(Export Address Table) (기타 = 세션 찾기 64bit pe viwer) 본문

리버싱

[reversing] EAT(Export Address Table) (기타 = 세션 찾기 64bit pe viwer)

백곳 2018. 5. 15. 20:47

EAT (Export Address Table)



Windows 운영체제에서 라이브러리(Library) 란 다른 프로그램에서 불러 쓸 수 있도록 
관련 함수들을 모아놓은 파일(DLL/SYS)입니다.

Win32 API 가 대표적인 Library 이며, 그 중에서도 kernel32.dll 파일이 가장 대표적인 Library 파일이라고 할 수 있습니다.

EAT(Export Address Table) 은 라이브러리 파일에서 제공하는 함수를 
다른 프로그램에서 가져다 사용할 수 있도록 해주는 매커니즘 입니다.

앞서 설명드린 IAT 와 마찬가지로 PE 파일내에 특정 구조체(IMAGE_EXPORT_DIRECTORY)에 정보를 저장하고 있습니다.

라이브러리의 EAT 를 설명하는 IMAGE_EXPORT_DIRECTORY 구조체는 PE 파일에 하나만 존재합니다. 

PE 파일내에서 IMAGE_EXPORT_DIRECTORY 구조체의 위치는 PE Header 에서 찾을 수 있습니다.
IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress 값이 
실제 IMAGE_EXPORT_DIRECTORY 구조체 배열의 시작 주소 입니다. (RVA 값입니다.)

출처 : http://reversecore.com/24



저의 컴퓨터의 경우 kernel32.dll 가 64bit 라서 


해당 프로그램 사용이 불가 합니다. 


그래서 다른 view 프로그램을 받아서 사용 하였습니다. 


NikPEViewer.exe

http://www.codedebug.com/php/Products/Products_NikPEViewer_12v.php


해당 프로그램을 사용하였습니다. 


제가 사용한 DLL 은 


kernel32.dll


이거 입니다. 


IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress 값을 직접 hax 값으로 자리수 맞춰가며 찾는 

방법도 좋으나 


Tool 을 이용하게 효율 적이라고 생각 하여 Tool을 사용하여 해당 값을 찾겠습니다. 

NikPEViewer.exekernel32.dll 을 open 해서 보면 


하지만 1번은 찾아 보겠습니다. 



위와 같이 해당 부분 입니다. 


0x0008AEE0 이라는 RVA(VirtualAddress) 값이 있고 이 값을 RAW 로 변환하면 


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 addressarray
    DWORD   AddressOfNames;         // address of functino name string array
    DWORD   AddressOfNameOrdinals;  // address of ordinal array
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

* 출처 : Microsoft 의 Visual C++ 에서 제공하는 winnt.h


해당 구조체가 있는 곳이 나옵니다. 


RAW 를 구하기 위해서 변환 하겠습니다. 


먼저  공식은 


RAW = RVA(목표) - VirtualAddress + PointerToRawData  


여기서 필요한 값은 RVA = 0x0008AEE0 


이고 VirtualAddress + PointerToRawData 은 세션이 어딘지 알아야 구할수 있습니다. 


RVA = 0x0008AEE0 는 어디에 포함 되는 세션인지지 구해 보겠습니다. 



먼저 세션 테이블을 보겠습니다. 



먼저 text 세션은 


virtual address = 0x00001000

sizeofrawdata = 0x00071200 


이면 


text 세션은 

0x00001000 ~ (0x00001000+0x00071200 )


가 됩니다. 


text 세션에는 


0x0008AEE0  값이 포함 되지 않습니다. 


그럼 다음 


rdata 세션을 보겠습니다. 


virtual address = 0x00073000

sizeofrawdata = 0x00030200


rdata 세션은 

 0x00073000 ~ (0x00073000+ 0x00030200 )


입니다 


그러면 

rdata 세션에는 


0x0008AEE0  값이 포함 됩니다. 



RAW = RVA(목표) - VirtualAddress + PointerToRawData  


에서 


VirtualAddress + PointerToRawData  는 rdata 세션의 값을 사용 하면 됩니다. 


이전에 엑셀로 만들어 놓은 곳에 값을 대입해 보겠습니다. 

구분 (16진수) (10 진수)
RVA 08AEE0 569056
Sestion RVA 073000 471040
point to RAW 071600 464384
RAW 894E0 562400


프로그램에서 EXPORT TABLE 의 offset 주소와 직접 계산한 주소가 일치하니 정확하게 계산 한것이 됩니다. 


IMAGE_EXPORT_DIRECTORY 의 각 필드에 대해서 알아 보겠습니다. 


NumberOfFunctions : 실제 export 함수 갯수
NumberOfNames : export 함수중에서 이름을 가지는 함수 갯수 (<= NumberOfFunctions)
AddressOfFunctions : export 함수들의 시작 위치 배열의 주소 (배열의 원소개수 = NumberOfFunctions)
AddressOfNames : 함수 이름 배열의 주소 (배열의 원소개수 = NumberOfNames)
AddressOfOrdinals : ordinal 배열의 주소 (배열의 원소개수 = NumberOfNames)





<Fig. EAT 구조>




라이브러리에서 함수 주소를 얻는 API 는 GetProcAddress() 입니다.

GetProcAddress() 함수가 함수 이름을 가지고 어떻게 함수 주소를 얻어내는 순서를 설명드리겠습니다.


 

1. AddressOfNames 멤버를 이용해 "함수 이름 배열" 로 갑니다.
2. "함수 이름 배열"은 문자열 주소가 저장되어 있습니다. 문자열 비교(strcmp)를 통하여 원하는 함수 이름을 찾습니다.
   이 때의 배열 인덱스를 name_index 라고 하겠습니다.
3. AddressOfNameOrdinals 멤버를 이용해 "ordinal 배열" 로 갑니다.
4. "ordinal 배열" 에서 name_index 로 해당 ordinal_index 값을 찾습니다. 
5. AddressOfFunctions 멤버를 이용해 "함수 주소 배열 - EAT" 로 갑니다.
6. "함수 주소 배열 - EAT" 에서 아까 구한 ordinal_index 를 배열 인덱스로 하여 원하는 함수의 시작 주소를 얻습니다.


위 <Fig. EAT 구조> 는 kernel32.dll 의 경우를 보여주고 있습니다.

kernel32.dll 은 export 하는 모든 함수에 이름이 존재하며,
AddressOfNameOrdinals 배열의 값이 index = ordinal 형태로 되어있습니다.

하지만 모든 DLL 파일이 이와 같지는 않습니다.
export 하는 함수 중에 이름이 존재하지 않을 수 도 있으며 (ordinal 로만 export 함)
AddressOfNameOrdinals 배열의 값이 index != ordinal 인 경우도 있습니다.

따라서 위 순서를 따라야만 정확한 함수 주소를 얻을 수 있습니다.


참고로 함수 이름 없이 ordinal 로만 export 된 함수의 주소를 찾을 수 도 있습니다.


출처 : http://reversecore.com/24


먼저 addressofname 을 찾아 보겠습니다. 

IMAGE_EXPORT_DIRECTORY  값은 프로그램에 직접 파싱 해주지 않으니 직접 찾아야 겠네요


앞에서 말한 


이부분의 RAW 쪽입니다. 


즉 IMAGE_EXPORT_DIRECTORY 의 헥사 값이지요 




이겨서 


표시해 둔 부분은 중요하게 사용될 

    DWORD   AddressOfFunctions;     // address of function start addressarray
    DWORD   AddressOfNames;         // address of functino name string array
    DWORD   AddressOfNameOrdinals;  // address of ordinal array



AddressOfFunctions = 0x0008AF08 

AddressOfNames = 0x0008C85C

AddressOfNameOrdinals = 0x0008E1B0 


입니다. 


먼저 0x0008C85C 을 RAW 로 바꾸면 


구분 (16진수) (10 진수)
RVA 08C85C 575580
Sestion RVA 073000 471040
point to RAW 071600 464384
RAW 8AE5C 568924



그럼 0x08AE5C 를 쫒아 가보겠습니다. 



그럼 0x0008EE67 이라는 값이 나옵니다. 


그럼 또 다시 RAW 를 변환 하겠습니다. 

구분 (16진수) (10 진수)
RVA 08EE67 585319
Sestion RVA 073000 471040
point to RAW 071600 464384
RAW 8D467 578663


다시 0x08D467 을 따라가 보겠습니다. 



위와 같이 배열의 시작 입니다. 


그중에 addAtomA 의 값을 알아보겠습니다. 


에서 4바이트 씩 끊어서 정리 해보면 



이렇게 되면 addAtomA 는 5번째에 존재 하게 됩니다. 






그럼 이제 배열 시작으로 부터 5번째 인것을 알았으니 



AddressOfNameOrdinals = 0x0008E1B0 로 가보겠습니다. 


구분 (16진수) (10 진수)
RVA 08E1B0 582064
Sestion RVA 073000 471040
point to RAW 071600 464384
RAW 8C7B0 575408





WORD 로 2바이트 씩 끊어 서 보면 0x0004이라는 값이 들어 있습니다. 


그래서 


AddressOfFunctions = 0x0008AF08  의 5번째 배열의 값을 찾아야 됩니다. 


그것이 바로 addAtom 의 RAV 값 입니다. 


구분 (16진수) (10 진수)
RVA 08AF08 569096
Sestion RVA 073000 471040
point to RAW 071600 464384
RAW 89508 562440


0x00021D70 이 RVA 값이라고 나오 네요 


그럼 프로그램에서는 




값이 이상하네요 해당 프로그램 버그 인듯 합니다. 


버그 때문에 기본 개념이 흔들릴뻔 했네요 .....  


그래서 다른 PEViwer로 살펴 봤습니다. 



해당 값이 맞네요 . 


해당 프로그램은 


https://www.safer-networking.org/products/filealyzer/ 에서 받아서 설치하여 사용 하였습니다.

Comments