이건 exe 가 아니라 dll이나 lib 구조 안에(라이브러리들)서 확인할 수 있는 구조라고 생각하면 되는 것 같다. EAT는 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 사용할 수 있도록 익스포트하는 함수의 시작 주소를 구할 수 있게 해준다.
음.. 그래서 dll은 자신의 함수를 다른 프로그램들에서 가져다 쓸 수 있게 해주는 라이브러리이기 때문에 첫 문장처럼 얘기를 써봤다
그래서 IAT는 한 exe가 여러 라이브러리에서 함수를 가져다 쓸 수 있기 때문에 구조체 배열의 형태를 가지지만(자기가 임포트 하는 라이브러리 개수만큼?) EAT는 한개의 구조체 배열로 이루어져 있다. 다음 제목에서 설명해야징
아무튼 큰 틀에서 보면 IAT와 큰 차이는 없는 것 같다. IAT는 _IMAGE_NT_HEADERS.OptionalHeader.DataDirectory[1]에서 참조할 수 있었는데, EAT는 _IMAGE_NT_HEADERS.OptionalHeader.DataDirectory[0]에서 참조할 수 있다.
위 사진은 IAT를 설명할 때 캡처해둔 바이너리인데(Easy Keygen.exe), 얘는 DataDirectory[0]에 아무값이 안들어있다. 앞에서 말한것처럼 exe 파일은 자신의 함수를 익스포트 하는것이 아니기 때문에 그렇다.
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORDCharacteristics;
DWORDTimeDateStamp;
WORDMajorVersion;
WORDMinorVersion;
DWORDName; // library file name
DWORDBase; // ordinal base
DWORDNumberOfFunctions; // 실제 export 함수 개수
DWORDNumberOfNames; // 이름을 가지는 함수 개수
DWORDAddressOfFunctions; // export 함수 주소(RVA)
DWORDAddressOfNames; // 함수 이름 주소(RVA)
DWORDAddressOfNameOrdinals; // 순서(인덱스)
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY
필드
뜻
Name
라이브러리명
Base
베이스 주소
NumberOfFunctions
실제 Export 함수 개수
NumberOfNames
이름이 있는 함수의 개수
AddressOfFunctions
함수 주소 배열
AddressOfNames
함수 이름의 주소 배열
AddressOfNameOrdinals
AddressOfFunctions의 몇번째 인덱스인지 나타냄
음.. 여기 뭔가 설명을 더 써야할 것 같은데 IAT 글과 통일성을 위해 뒤에서 같이 설명해야지 ㅎ 암튼 중요한 필드는 이게 다이다.
kernel32.dll 바이너리이다. IAT 볼때랑 똑같이 DataDirectory를 먼저 찾아가야했고, 붉은색이 _IMAGE_NT_HEADERS.Signature (4byte, \x50\x45\x00\x00)
초록색이 _IMAGE_NT_HEADERS.FileHeader
노란색과 초록색 사이의 빈곳이 _IMAGE_NT_HEADERS.OptionalHeader 이며, 노란색 부분이 _IMAGE_NT_HEADERS.OptionalHeader.DataDirectory 이다. 그중에 파랑색이 이번에 확인해볼 DataDirectory[0]이다. (IAT때와는 다르게 내가 본 kernel32.dll은 PE64라 OptionalHeader의 크기가 더 큼)
실행 환경1: Windows 10 64bit [Version 10.0.19043.1348]
처음엔 그냥 크롬이 kenel32.dll을 사용하길래 windbg로 붙어서 확인을 하려했다.
음.. 막상 프로그램이 실행되고 실제 kernel32.dll이 올라간 주소가 ImageBase와 달랐다.
0:000> !dh 00007ffd`ce3a0000
File Type: DLL
FILE HEADER VALUES
8664 machine (X64)
7 number of sections
38B369C4 time date stamp Wed Feb 23 14:01:56 2000
...
OPTIONAL HEADER VALUES
...
----- new -----
00007ffdce3a0000 image base
1000 section alignment
200 file alignment
3 subsystem (Windows CUI)
...
4160 DLL characteristics
High entropy VA supported
Dynamic base
NX compatible
Guard
그래서 windbg에서 pe 구조를 확인해보았더니 ImageBase가 다른값으로 바뀌어있다. 바뀐걸까.. 내가 뭔가 생각 못한 부분이 있는걸까.. 그리고 그 바로 위에 new라고 써있는 이유도 모르겠다.
그래서 좀 더 보니까 DLLcharacteristics 부분에 Dynamic base라고 되어있는것을 볼 수 있다.
CFF에서도 Optional Header를 다시 보니까 DLL can move에 체크가 되어있다.
이미 0x180000000에 뭐가 올라가 있거나 ASLR 관련된 이유일 수 있을 것 같다.
실행환경2: Windows 7 [Version 6.1.7601]
왠지 윈7에서는 될 것 같아서 환경을 바꾸어서 해봤다. 여기선 귀찮아서 직접 계산은 안했다.
kernel32.dll ImageBase: 0x78D20000
AcquireSRWLockExclusive RVA: 0xAA1EE
근데 얘도 실제 메모리에 올라간 값을 보면.. ImageBase랑 차이는 난다. 아무튼 찾고자 하는 함수의 RVA를 실제 dll이 올라간 베이스 주소에 더해준 곳에 함수가 있는 것을 볼 수 있다.
얘도 보니까 win10하고 똑같이 세팅이 되어 있다. 아무튼 이런식으로 dll에서 EAT를 참조하여 함수의 주소를 알아내는 것을 확인할 수 있다. 실제 함수가 올라갈 때 ImageBase와 다른 주소에 올라갈 수 있음을 알았으니 함수의 주소를 직접 계산하고자 할때는 ImageBase만 믿지 말고 직접 dll이 올라간 위치를 알아야 할 것 같기도 하다.
결국은 추측이여서 확실하지 않으니 지나가다 이 글을 봤는데 이유를 아시는 분은 알려주시면 감사하겠습니다.