DLL

- 여러 함수들이 모인 라이브러리 파일

- 프로그램에서 라이브러리 함수를 사용하게 되면 해당되는 DLL을 불러와 사용

- 이런 DLL 로딩 방식이 Implict Linking, Explict Linking 두 가지 방식이 존재함

 

IAT

- 프로그램이 어떤 라이브러리에서 어떤 함수를 사용하고 있는지를 기술한 테이블

- 프로그램이 켜지는 순간 프로그램에서 사용하는 DLL들을 불러온 후, 프로그램 종료시 DLL들을 다시 해제시키는 방법에 대한 메카니즘 제공(Implict Linking)

 

IMAGE_IMPORT_DESCRIPTOR(IID)

= 자신이 어떤 라이브러리를 import하고 있는지 명시해주는 구조체

- OriginalFirstThunk = INT(Import Name Table)의 주소 RVA

- Name = Library일므 문자열의 주소 RVA

- FirstThunk = IAT의 주소 RVA

 

IMAGE_THUNK_DATA32

= INT와 IAT를 구성하고 있는 구조체, INT와 IAT의 크기는 동일

 IAT와 INT는 IMAGE_THUNK_DATA32 구조체 배열로 구성된다.

따라서OriginalFirstThunk와 FirstThunk는 IMAGE_THUNK_DATA32 구조체 배열의 주소(RVA)을 가진다.

 

IMAGE_IMPORT_BY_NAME

 

과정

1. IID의 Name멤버를 읽어서 라이브러리의 이름 문자열을 얻는다.

2. 해당 라이브러리를 로딩한다. ex) LoadLibrary("ADVAP132.dll")

3. IID의 OriginalFirstThunk멤버를 읽어서 INT주소를 얻는다.

4. INT에서 배열의 값을 하나씩 읽어 해당 IMAGE_IMPORT_BY_NAME주소(RVA)를 얻는다.

5. IMAGE_IMPORT_BY_NAME의 hint of name의 이용하여 해당 함수의 시작 주소를 얻는다. GetProcAddress("OpenProcessToken")

6. IID의 FirstThunk 멤버를 읽어서 iat의 주소를 얻는다.

7. 해당 IAT배열 값에 위에서 구한 함수 주소를 입력한다.

8. INT가 끝날 떄까지 (NULL을 만날때 까지) 4-7의 과정을 반복한다.

 

IAT실습

RVA = 7604

해당 주소에 들어가면 IMPORT Table의 RVA뒤쪽이 Size이다.

RVA를 알기 때문에 offset(RAW)를 구한다.

7604 - 1000 + 0400 = 6A04이므로 파일에서 6A04를 보면 밑과 같다.

RAW값을 보면 다음과 같다.

Description RAQ
INT 00006D90
Time Date Stamp -
Forwarder Chain -
Name 00006EAC
IAT 000006C4

1. Name 00006EAC

2. INT 00006D90

INT는 임포트 하는 함수의 정보가 담긴 구조체 포인터 배열이다. 프로세스 메모리에 로딩된 라이브러리에서 해당 함수의 시작주소를 알아낼 수 있다. 주속값 하나하나가 각각의 IMAGE_IMPORT_BY_NAME구조체를 가리키고 있다.

 

3. IMAGE_IMPORT_BY_NAME

RVA: 7A7A를 RAW로 변환한다.

7A7A + 1000 - 0400 = 6E7A

제일 앞에 ...(000F)는 라이브러리에서 함수의 고유번호라고 한다. 이 Oridinal뒤에 함수 이름 문자열을 보면 INT는 IMAGE_IMPORT_BY_NAME구조체의 포인터 배열임을 알수 있다.

 

4. IAT 000006C4

comdlg32.dll라이브러리에 해당하는 IAT배열 영역이다. IAT의 첫번째 원소값인 76324906은 의미 없는 값이고 메모리에 로딩될때 정확한 주소값으로 대체된다.


EAT

프로그램에서 어떤 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 핵심 메커니즘이다. 즉 EAT를 통해서만 해당 라이브러리에서 익스포트하는 함수의 시작 주소를 정확히 구할 수 있다.

 

- IAT와 마찬가지로 PE 파일 내의 특정 구조체 IMAGE_EXPORT_DIRECTORY에 익스포트 정보를 저장하고 있으며 라이브러리의 EAT를 설명하는 이 구조체는 PE파일에 하나만 존재한다.

- PE 파일에서 IMAGE_EXPORT_DIRECTORY구조체의 위치는 PE헤더에서 찾을 수 있으며IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress값이 실제  IMAGE_EXPORT_DIRECTORY구조체 배열의 시작주소이다.

 

항목 의미
NumberOfFunctions 실제 Export 함수 개수
NumberOfNames Export함수 중에서 이름을 가지는 함수 개수
AddressOfFunctions Export함수 주소 배열
AddressOfNames 함수 이름 주소 배열
AddressOfNameOrdinals Ordinal배열

 

EAT로딩 과정

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

2. 함수이름배열은 문자열 주소가 있으므로 문자열 비교를 통하여 원하는 함수 이름을 찾는다.

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

4. 'ordinal배열'에서 name_index를 이용하여 해당 ordinal값을 찾는다.

5. AddressOfFunctions멤버를 이용하여 함수 주소 배열로 이동한다.

6. EAT에서 ordinal을 배열 인덱스로 하여 원하는 함수의 시작주소를 얻는다.

 

해당 주소로 이동한 모습니다.

IAT와 같이 앞쪽 4바이트가 RVA 뒤쪽 4바이트가 Size의 멤버임을 볼 수 있다.

 

RVA값이 262C이므로 RAW를 께산해보면 262C - 100 + 0400 = 1A2C이다.

항목 의미
NumberOfFunctions 실제 Export함수 개수
NumberOfNames Export함수 중에서 이름을 가지는 함수 개수
AddressOfFuncions Export 함수 주소 배열
AddressOfNames 함수 이름 주소 배열
AddressOfNmaeOrdinals Ordinal배열

라이브러리에서 함수 주소를 얻는 API는 GetProcAddress()이다.  API가 EAT를 참조해서 원하는 API주소를 휙득한다.

 

1. 함수 이름배열

AddOfNames멤버의 RVA = 3538RAW = 3538 - 1000 _ 0400 = 2938
2. AddAtom은 AddOfNames의 RVA들 중에 3번째에 속해있고 배열 인덱스로는 2가 된다.

 

3. Oridnal배열AddAtom함수의 Oridnal값을 알아낸다 멤버값은 441c RAW : 381C이다.

4. ordinal

AddressOfNameOrdinal[index] = ordinal ( index = 2, ordinal = 2)

 

5. 함수 주소 배열

RAW : 1A54이다.

 

참고

https://kyumoonhan.tistory.com/119

https://su0-0su.tistory.com/56

+ Recent posts