본문 바로가기

High Level Technique/Reversing

IAT (Import Address Table)

IAT (Import Address Table)


IAT는 프로그램에서 어떤 DLL을 사용하는지 알려주는 테이블입니다.


*DLL ( Dynamic Linked Library)

DLL은 프로그램마다 동일한 라이브러리가 포함되어 실행되면 메모리 낭비가 심해지기 때문에 이를 방지하기 위해서 DLL 파일을 만들어 프로그램이 필요할 때만 불러

쓰도록 하기 위한 것입니다.

또 한번 로딩된 DLL은 Memory Mapping을 이용하여 Process에서 공유해 쓰도록 합니다.


*DLL 로딩 방식

Explicit Linking: 프로그램에서 이용되는 순간에 로딩하고 사용이 끝나면 해제되는 방법.

Implicit Linking: 프로그램이 시작할때 로딩되어 종료할 때 메모리에서 해제되는 방법.





IAT는 Implicit Linking 방식을 이용합니다.


Notepad 다운로드 

Windows10 - 32bit - notepad.exe


IAT를 확인하기 위해서 OllyDBG를 이용해 확인해 보겠습니다.




CreateFileW를 찾아보면 DS:[000AA150]=767B6890 이라는 값을 확인 할 수 있습니다.

즉, 000AA150의 위치로 이동하여 CreateFileW를 호출하게 된다는 말입니다.


여기서 의문점이 드는데, 그냥 000AA150으로 거치지 않고 767B6890이라는 값을 넣어주면(하드코딩) 바로 호출이 될텐데 왜 이러한 방식을 사용할까요?

프로그램이 어떤 환경에서 작동할지 모르기 때문에 CreateFileW의 주소가 저장될 위치(000AA150)을 준비하고 파일이 실행될때 000AA150위치에 CreatefileW의 주소를 넣어줍니다.


또한 DLL의 ImageBase는 10000000인데 여러 DLL이 로딩 될 때를 생각을 해보면 1.dll이 먼저 로딩되는 경우 ImageBase에 맞게 로딩된 후 2.dll은 이미 1.dll이 로딩되어 있기

때문에 ImageBase에 로딩될 수 없습니다. 이러한 경우 DLL Relocation을 통해 다른 비어있는 공간을 찾아 다시 로딩 됩니다.


이러한 이유로 바로 값을 넣어주지 않습니다.




IMAGE_IMPORT_DESCRIPTOR




프로그램에서 보통 여러개의 라이브러리를 Import하기 때문에 라이브러리 개수만큼 구조체 배열이 존재합니다. 구조체 배열 마지막은 NULL 입니다.


여기서 중요한 멤버는 다음과 같습니다.


* OriginalFirstThunk

INT의 주소를 나타냅니다. 여기서 INT 주소는 RVA 형식 입니다.


* Name

라이브러리 이름 주소 입니다. 마찬가지로 RVA 형식입니다.


* FirstThunk

IAT의 주소입니다. RVA 형식입니다.


※ IAT와 INT의 크기는 같아야 합니다. 또한 INT의 각 원소의 값은 IMAGE_IMPORT_BY_NAME 구조체 포인터인데, IAT와 같은 값을 가지고 있습니다 아닌경우도 있습니다..










그렇다면 이제 IAT의 기본적인 순서를 알아보겠습니다.



1. IMAGE_IMPORT_DESCRIPTOR의 Name 멤버를 읽어서 라이브러리의 이름 문자열을 찾습니다. (kernel32.dll)

2. 해당 라이브러리를 로딩 합니다. LoadLibrary(kernel32.dll)

3. IMAGE_IMPORT_DESCRIPTOR의 OriginalFirstThunk 멤버를 읽어서 INT 주소를 얻습니다.

4. INT에서 배열 값을 읽어 해당 IMAGE_IMPORT_BY_NAME 주소를 얻습니다. 여기서 주소는 RVA 입니다.

5. IMAGE_IMPORT_BY_NAME의 Hint 또는 Name 항목을 이용하여 해당 함수의 시작 주소를 얻습니다. GetProcAddress(GetCurrentThreadId)

6. IMAGE_IMPORT_DESCRIPTOR의 FirstThunk 멤버를 읽어 IAT 주소를 얻습니다.

7. 해당하는 IAT 배열 값에 위에서 구한 함수 주소를 넣습니다.

8. INT가 끝날때 까지 반복합니다. 



IMAGE_IMPORT_DESCRIPTOR 구조체 배열은 IMAGE_OPTIONAL_HEADER32의 DataDirectory[1]에 위치합니다. IMPORT Directory Table이라고도 불린다고 합니다.




PEView에서 보는 것처럼 처음 4바이트는 RVA값, 다음 4바이트 값은 Size를 나타냅니다.


RVA 값이 1A3B0 이므로 RVA to RAW 공식을 이용해서 값을 구하면 다음과 같습니다.


RAW = RVA- VirtualAddress + PointerToRawData

즉, 파일의 임의위치 = 메모리의 임의위치 - 메모리의 해당 섹션 시작위치 + 파일의 해당 섹션 시작위치 입니다.


RAW = 1A3B0 - 1A000 + 16000 

RAW = 163B0 이 됩니다.


어떻게 찾을 수 있나요?

연습하는 입장에서 Hex Editor로 하는 것이 맞지만 쉽게 찾기 위해서 PEView를 이용합니다.

먼저 RVA 값이 1A3B0라는 것을 알고 있습니다. 그러면 해당 RVA값이 어디에 속하는지 알아야 합니다. PEView에서 확인합니다.



PEView에서 3번째 버튼을 눌으면 주소값이 RVA 형태로 변합니다. SECTION .idata 영역은 1A000 부터 1B9F0 까지 이므로 찾고자 하는 RVA값인 1A3B0는 

.idata 영역에 속합니다.


따라서 VA값은 해당 영역의 시작 주소 이므로 1A000이 됩니다.  ImageBase 값은 제외합니다. 



그리고 파일의 해당 섹션 시작위치를 알야아 하는데 이것도 PEView를 통해 확인하면 아래와 같습니다.



식을 완성하면 RAW = 1A3B0 - 1A000 + 16000 과 같이 됩니다. 따라서 RAW 값은 163B0 이 됩니다.






163B0를 찾아가면 각 멤버의 값을 확인 할 수 잇습니다.








*Name 찾기


마찬가지로 163B0에서 Name 값은 1A982 입니다. (RVA 값)

이 값 또한 RAW 로 변경하면 16982 가 됩니다.




PEView에서 찾았던 ADVAPI32.dll 문자가 16982에 존재하는 것을 알 수 있습니다.








* OriginalFirstThunk-INT 찾기

RVA값이 1A554 입니다. RAW로 변환하면 16554가 됩니다.





배열 하나하나가 각각의 IMAGE_IMPORT_BY_NAME 구조체를 가리키고 있습니다.


첫 번째 값인 00 01 A9 1E 를 찾아가면 다음과 같습니다.


RAW = 1691E 가 됩니다.

1691E를 찾아가면 다음과 같습니다.




RegSetValuseExW를 호출합니다.









*FirstThunk - IAT 찾기

RVA 값이 16000 이므로 RAW 값은 16000이 됩니다.

마찬가지로 16000을 찾아가면 다음과 같습니다.



16000이 돼 버리면 01 A9 1E가 됩니다. 이 값을 찾아가면 OriginalFirstThunk-INT 찾기에서 이동한 곳으로 가버립니다.


※이 부분은 좀더 공부를 해봐야 할 것 같습니다. windows10 을 기준으로 해서 그런지 뭔가 바뀐거 같습니다...

실제 OllyDBG에서는 AA000 위치에 존재합니다.





정확히 찾지는 못했지만 위와 같은 방식으로 찾아가면 됩니다. 그리고 OS의 버전에 따라 많이 달라진 것 같습니다.

Windows의 ASLR 기법에 의해 변한 것으로 추정합니다.


혹시 이 부분에 대해서 아시는분은 댓글 남겨주시면 감사하겠습니다.!!

'High Level Technique > Reversing' 카테고리의 다른 글

PE 재배치 (PE Relocation)  (0) 2015.12.21
EAT (Export Address Table)  (0) 2015.12.21
IMAGE_SECTION_HEADER  (0) 2015.07.09
NT Header - IMAGE_OPTIONAL_HEADER - IMAGE_DATA_DIRECTORY  (0) 2015.07.09
NT Header - IMAGE_OPTIONAL_HEADER  (0) 2015.07.09