IAT (Import Address Table)  함수주소 기록 과정
Security/Reverse Engineering

IAT (Import Address Table) 함수주소 기록 과정

맨날 보고 보고 또 봐도 헷갈리는 IAT(Import Address Table) 에 함수주소를 기록하는 과정을 PEView 를 이용하여 하나하나 살펴보도록 하겠습니다.

진짜 어려운거 다 집어치우고 핵심 프로세스만 적도록 할게요.  그래도 IAT(Import Address Table) 가 왜 필요한지는 알고가야 되겠죠?


IAT 에 함수주소를 기록하는 제일 큰 이유는, DLL 동적라이브러리를 사용하기 위함입니다. DLL을 가져와서 함수를 빌려쓰려고 하는데, DLL이라는 이놈이 항상 똑같은 메모리 공간에 올라가지 않습니다. 그래서 항상 DLL 내 함수 주소도 바뀌죠. 이 바뀐 함수 주소를 프로그램이 실행 될 때, PE 로더가 IAT에 함수주소를 찾아서 기록을 해줍니다.


이 IAT에 함수주소를 기록하는 과정이 꽤나 복잡합니다. 최대한 쉽게 써서 다음에 까먹었을때 바로 기억날 수 있도록 써보겠습니다.


1. IAT (Import Address Table) 은 어디에 있을까?

먼저 IAT 테이블이 어디에 있는지 부터 알아봅시다. 적어도 툴을 사용하여 찾아갈 정도는 알아야 하니까요. PEView 라는 툴로 메모장을 열어 주었습니다.

IMAGE_NT_HEADERS 안에 IMAGE_OPTIONAL_HEADER 안에 IMPORT Table 에서 IMPORT Directory Table 의 RVA를 얻을 수 있습니다. 네 그냥 어려우니 그렇다치고 넘어갑시다. 

그리고 IMPORT Directory Table을 눌러보면 뭔가 DLL 들의 이름이 쭉 보입니다. 네 여기가 IAT의 주소가 나와있는 곳입니다. IMPORT Directory Table 가 IMAGE_IMPORT_DESCRIPTOR 구조체들의 배열 의 시작주소를 가리키고, 이 IMAGE_IMPORT_DESCRIPTOR 구조체안에  IAT의 RVA가 나와있습니다. 이 주소에 우리가 쓸 함수주소를 기록 합니다. 여기에 네 이것도 어려우니 그냥 아 여기있구나 정도만 알고 넘어갑시다.


정리하면, 

IMAGE_NT_HEADER -> IMAGE_OPTIONAL_HEADER -> IMPORT Table(IMPORT Directory Table 의 RVA) -> IMAGE_IMPORT_DESCRIPTOR -> IAT(Import Addresss Table)

중요한건 이 IAT 에 PE로더가 우리가 쓸 함수주소를 기록한다는 것 입니다. 그럼 PE로더가 어떻게 IAT에 기록하는지를 알아봐야겠죠?



2. PE로더의 IAT 기록 과정

먼저 생각을 해봅시다. 우리는 현재 DLL 안에 있는 함수를 쓰는게 목적이죠. 하지만 함수의 주소를 알아야 콜을 할 수가 있습니다. 그 함수의 주소를 PE로더가 찾아서 적어줄텐데요. 이 PE로더가 함수주소를 기록하는 방법을 알아볼 예정입니다.

아까 IMPORT Directory Table 이 IMAGE_IMPORT_DESCRIPTOR 구조체 들을 담고 있는걸 보았는데요. 이 IMAGE_IMPORT_DESCRIPTOR안에 우리가 IMPORT할 DLL의 정보가 다 나와있습니다. PE로더도 젤 먼저 이 테이블을 참조하여 정보를 얻습니다.

예를 들어, ADVAPI32.dll 안에 함수들의 주소를 기록한다고 치겠습니다.

먼저 PE로더는 IMAGE_IMPORT_DESCRIPTOR 내 Name 을 참고하여 DLL 의 이름을 얻습니다. 그 얻은 문자열로 LoadLibrary("DLL이름") 함수를 사용하여 해당 DLL의 핸들 을 얻습니다. 핸들은 해당 DLL을 제어하기 위한 키(key) 라고 생각할 수 있겠습니다.


그 다음 IMAGE_IMPORT_DESCRIPTOR 내 INT(Image Name Table) 을 참조합니다. 여긴 왜 참조하는 걸까요? INT 내부를 한번 보겠습니다.

INT 내부입니다. 여기에는 우리가 기록할 dll안에 있는 함수들의 이름들이 나와있습니다. 서수+문자열의 정보를 담고있는 구조체의 RVA지만 PEView 툴에서 편리하게 보여주네요. 

PE로더는 이 함수이름과 아까 얻은 dll의 핸들을 사용하여 GetProcAddress(핸들,"함수이름") 함수를 사용하여 함수의 주소를 얻게됩니다. 실제 함수 주소를 구했으니 이제 IAT에 기록만하면 .. ! 우리가 쓸 수 있습니다.


IMPORT_IMAGE_DESCRIPTOR 에서 IAT 주소를 얻어서 해당 주소에 실제 함수주소를 기록합니다. 이제 프로그램에서는 이 IAT만 참조하면 DLL내 함수들을 빌려 쓸 수 있습니다. 

프로그램에서 IMPORT 하는 DLL은 하나가 아니므로 모든 DLL 에 대한 작업을 반복합니다. 


여기서 하나 궁금한점이 생깁니다. 함수주소를 기록하기 위해서 사용한 LoadLibrary 와 GetProcAddress 함수는 어떻게 사용한 것일까요? 이 함수들은 kernel32.dll 안에 있고, 이 kernel32.dll 은 모든 프로그램에서 사용하기 때문에 부팅할 때 이미 메모리에 올라가 있고, 항상 똑같은 자리에 올라가있어서  IAT에 기록하는 과정없이 이 가능합니다.


뭔가 쉽게쉽게 쓰려고 했는데 어려워져 버렸네요.. 내용자체가 어렵다 보니까 많은내용을 생략했음에도 복잡합니다.