-
13 PE File Format(4) - IAT리버싱 엔지니어링/리버싱 핵심 원리 2022. 3. 23. 20:53
IAT
: 프로그램이 어떤 라이브러리에서 어떤 함수를 사용하고 있는지를 기술한 테이블
- Windows 운영체제의 핵심 개념인 process, memmory, DLL 구조 등에 대한 내용이 함축
DLL
: 동적 연결 라이브러리(Dynamic Linked Library)
동적 연결 라이브러리라 불리는 이유?
- 16비트 DOS 시절, C 라이브러리에서 함수의 binary 코드를 그대로 프로그램에 삽입
- Windows OS에서 멀티 태스킹을 지원하여 16비트 DOS 시절 방식이 비효율적
- 따라서, 새로운 방법 고안
- 프로그램에 라이브러리를 포함시키지 말고 별도의 파일(DLL)로 구성하여 필요할 때마다 불러 쓰자.
- 한 번 로딩된 DLL 코드, 리소스는 Memory Mapping 기술로 여러 Process에서 공유해 쓰자.
- 라이브러리가 업데이트되었을 때 해당 DLL 파일만 교체하면 돼서 쉽고 편하다.
- 실제 DLL 로딩 방식은 2가지
- Explicit Linking : 프로그램에서 사용되는 순간에 로딩하고 사용이 끝나면 메모리에서 해제
- Implicit Linking : 프로그램 시작할 때 같이 로딩되어 프로그램 종료할 때 메모리에서 해제
- IAT는 Implicit Linking에 대한 메커니즘을 제공하는 역할
OllyDbg를 통한 IAT 확인 : CreatFileW 호출 코드
- CreateFile 호출 시 직접 호출하지 않고 01001104 주소에 있는 값을 가져와 호출 (모든 API 호출 방식과 동일)
- 01001104 주소는 '.text' 섹션의 메모리 영역 (더 정확히는 IAT 메모리 영역), 값은 768F3A90
- 768F3A90 주소가 notepad.exe 프로세스 메모리에 로딩된 kernel32.dll의 CreateFileW 함수 주소
(?) 그냥 CALL 768F3A90라고 하면 더 편하지 않을까?
=> 해당 방식이 16비트 DOS 시절 사용한 방식
=> 어떤 Windows, 언어, Service Pack에서 실행될지 알 수 없음. 환경에 따라 kernel32.dll 버전이 달라지고 함수의 주소가 달라짐. 따라서, 모든 환경에서 함수 호출을 보장하기 위해 실제 주소가 저장될 위치(ex. 01001104)를 준비 → 파일 실행 시 저장될 주소(ex. 01001104)에 함수 주소를 입력해줌.
=> DLL Relocation 때문에 실제 주소를 하드코딩할 수 없다. (VA가 아닌 RVA를 사용해야하는 이유도 됨)
ex) a.dll을 ImageBase 값인 메모리 1000000에 로딩
b.dll을 로딩하려니 a.dll이 존재 따라서 비어있는 메모리 공간(ex. 3E000000)을 찾아 로딩
IMAGE_IMPORT_DESCRIPTOR
: 어떤 라이브러리를 import하고 있는지를 명시
- IMAGE_IMPORT_DESCRIPTION 구조체
typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; // INT(Import Name Table) address (RVA) }; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; // library name string address (RVA) DWORD FirstThunk; // IAT(Import Address Table) address (RVA) } IMAGE_IMPORT_DESCRIPTOR; typedef struct _IMAGE_IMPORT_BY_NAME { WORD Hint; // ordinal BYTE Name[1]; // function name string } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
- 라이브러리의 개수만큼 위 구조체의 배열 형식으로 존재, 마지막은 NULL 구조체로 끝남
중요 멤버
항목 의미 OriginalFirstThunk INT(Import Name Table)의 주소(RVA) Name Library 이름 문자열의 주소(RVA) FirstThunk IAT(Import Address Table)의 주소(RVA) 참고)
- PE 헤더에서 Table은 배열을 뜻함
- INT와 IAT는 long type(4바이트 자료형) 배열, NULL로 끝남. 크기 따로 명시 X
- INT에서 각 원소의 값은 IMAGE_IMPORT_BY NAME 구조체 포인터
- INT와 IAT의 크기는 같아야함.
notepad.exe의 kernel32.dll에 대한 IMAGE_IMPORT_DESCRIPTION
PE 로더가 임포트 함수 주소를 IAT에 입력하는 기본 순서
1. IID(IMAGE_IMPORT_DESCRIPTION)의 Name 멤버를 읽어 라이브러리의 이름 문자열("kernel32.dll")을 얻는다.
2. 해당 라이브러리를 로딩 → LoadLibrary("kernel32.dll")
3. IID의 OriginalFirstThunk 멤버를 읽어 INT 주소를 얻는다.
4. INT에서 배열의 값을 하나씩 읽어 해당 IMAGE_IMPORT_BY_NAME 주소(RVA)를 얻는다.
5. IMAGE_IMPORT_BY_NAME의 Hint(ordinal) 또는 Name 항목을 이용해 해당 함수의 시작 주소를 얻는다.
→ GerProcAddress("GetCurrentThreadId")
6. IID의 FirstThunk(IAT) 멤버를 읽어 IAT 주소를 얻는다.
7. 해당 IAT 배열 값에 위에서 구한 함수주소를 입력한다.
8. INT가 끝날 때까지(NULL을 만날때 까지) 위 4~7과정을 반복한다.
실습
: notepad.exe를 이용한 실습
- IMAGE_IMPORT_DESCRIPTION 위치 : PE 바디
- PE 헤더의 IMAGE_OPTIONAL_HEADER32.DataDirectory[1].VirtualAddress 값이 실제 배열 시작 주소(RVA)
- IMAGE_IMPORT_DESCROPTIOM을 IMPORT Directory Table 이라고도 한다.
IMAGE_OPTIONAL_HEADER32.DataDirectory[1] 구조체 값
- 첫 번째 4바이트가 VirtualAddress, 두 번째 4바이트가 Size 멤버
- RVA of IMPORT Directory : 00007604
- size of IMPORT Directory : 000000C8
- RVA to RAW를 통한 File Offset 구하기
- RAW = 7604 - 1000 + 400 = 6A04 (참고 : https://wh514.tistory.com/22)
File Offset(6A04) 확인
IMAGE_IMPORT_DESCRIPTION 구조체 멤버별로 살펴보기
File Offset Member RVA RAW 6A04 OriginalFirstThunk(INT) 00007990 00006D90 6A08 TimeDateStamp FFFFFFFF - 6A0C ForwarderChain FFFFFFFF - 6A10 Name 00007AAC 00006EAC 6A14 FirstThunk(IAT) 00012C4 000006C4 위 표를 참고하여 순서대로 진행
1. 라이브러리 이름(Name)
: Name 항목은 임포트 함수가 소속된 라이브러리 파일의 이름 문자열 포인터
RVA : 7AAC → RAW : 6EAC
- "comdlg32.dll" 문자열 확인
2. OriginalFirstThunk - INT
: INT는 임포트하는 함수의 정보(Ordinal, Name)가 담긴 구조체 포인터 배열 → 프로세스에 로딩된 라이브러리에서 해당 함수의 시작 주소를 정확히 구할 수 있음
RVA : 7990 → RAW : 6D90
- 주소 배열 형태 (배열의 끝은 NULL)
- 주소 값 하나하나가 각각의 IMAGE_IMPORT_BY_NAME 구조체를 가리킴
- 배열의 첫번째인 7A7A(RVA)를 따라가보자
3. IMAGE_IMPORT_BY_NAME
RVA : 7A7A → RAW : 6E7A
- 파일 옵셋의 최초 2바이트 값(000F)는 Ordinal, 함수 고유번호
- Ordinal 뒤로 'PageSetUpDlgW' 함수 이름 문자열 확인 (마지막은 '\0' : Terminating NULL)
4. FirstThunk - IAT(Import Address Table)
RVA : 12C4 → RAW : 6C4
- 파일 옵셋 6C4~6EB 영역 : 'comdlg32.dll' 라이브러리에 해당하는 IAT 배열 영역
- 배열은 NULL로 끝남
- IAT 첫 번째 원소 값은 76324906으로 하드코딩, 메모리에 로딩될 때 정확한 주소 값으로 대체됨
'리버싱 엔지니어링 > 리버싱 핵심 원리' 카테고리의 다른 글
14 실행 압축 (0) 2022.03.25 13 PE File Format(5) - EAT (0) 2022.03.24 13 PE File Format(3) - RVA to RAW (0) 2022.03.23 13 PE File Format(2) - PE 헤더(DOS Header, NT Header,섹션 헤더) (0) 2022.03.23 13 PE File Format(1) - PE 파일, VA&RVA (0) 2022.03.23