pe파일 분석(IAT & Pre Binding)
@ PE 파일 분석(IAT & Pre Binding)
1. IAT
- Import Address Table
- DLL 파일이 메모리 상에 로드되는 주소값을 갖고 있는 테이블이며, 암시적 링킹에서 사용한다.
- 'calc(ASLR X).exe'를 올리디버거로 오픈하여 '0x01012D89' 내용을 확인한다.
- 메모리 덤프창에서 '0x0100114C'로 이동한다.
- 10 1E 0B 76 -> 0x760B1E10
- 'KERNEL32.dll'의 'GetStartupInforA' 함수를 호출할때, 직접 호출하지 않고 PE 로더가 프로그램 실행시 '0x0100114C' 주소에 설정한 해당 함수 주소 값(0x760B1E10)을 갖고와서 호출함
- 'calc(ASLR X).exe'를 올리디버거로 오픈하여 '0x01044129' 내용을 확인한다.
- 메모리 덤프창에서 '0x01001000'로 이동한다.
- 18 04 41 76 -> 0x76410418
- 'SHELL32.dll'의 'SHGetSpecialFolderPathW' 함수를 호출할때, 직접 호출하지 않고 PE 로더가 프로그램 실행시 '0x01001000' 주소에 설정한 해당 함수 주소 값(0x76410418)을 갖고와서 호출함
2. IDT
- Import Directory Table
- DLL 이미지 내의 EP(Entry Point)에 대한 RVA 정보를 포함하고 있다.
- IDT 마지막 항목은 Directory Table 끝을 나타내는 NULL 값이 설정되어 있다.
- IDT는 PE 바디 영역에 있으며, 해당 위치는 IMAGE_OPTIONAL_HEADER에 'Number of Data Diretories'에서
확인할 수 있다.
1) IDT 구조체 배열 주소와 크기 구하기
pFile Data Description Value
00000158 00051AFC RVA IMPORT Table
0000015C 00000154 Size
IDT 구조체 배열 주소 = 0x00051AFC <- .text 섹션 범위에 포함되어 있음
IDT 구조체 크기 = 0x154(340byte)
2) IDT 구조체 RAW 주소 구하기
- RAW = RVA - Virtual Address + Pointer to Raw Data
RVA 0x51AFC
Virtual Address 0x1000
Pointer to Raw Data 0x400
파일에서 .text 섹션 범위 0x400 ~ 0x53200(0x400 + 0x52E00) 이전
- RAW = 0x51AFC - 0x1000 + 0x400 = 0x50EFC
- RVA가 '0x51AFC'인 경우, RAW는 '0x50EFC'이며, 파일에서 .text 섹션 범위에 포함된다.
3) IDT 구조체 영역 확인
- IDT 구조체의 RAW는 '0x00050EFC'이고, 크기는 0x154(340byte)이다. PEview에서 확인하도록 한다.
3. IDT 구조체 배열 분석
- IDT 구조체의 첫번째 요소의 영역은 다음과 같이 20Byte로 구성되어 있다.
20 1D 05 00 FF FF FF FF FF FF FF FF 14 1D 05 00 00 10 00 00
*OriginalFirstThunk 4byte 20 1D 05 00 -> 00 05 1D 20
- INT(Import Name Table)의 RVA 주소이다.
- 즉, Import되는 함수 정보들이 있는 영역의 시작 주소이다.
- INT RVA = 0x00051D20
- RAW = 0x51D20 - 0x1000 + 0x400 = 0x51120
- 파일에서 INT 시작 주소는 '0x00051120' 이다.
TimeDateStamp 4byte FF FF FF FF -> FF FF FF FF
- 시간 날짜 정보
- 바인딩 안된 경우 : 0
- 바인딩 된 경우 : -1(0xFFFFFFFF)
ForwardChain 4byte FF FF FF FF -> FF FF FF FF
- 바인딩 여부와 관련 정보
*Name 4byte 14 1D 05 00 -> 00 05 1D 14
- DLL 이름의 RVA 주소이다.
- 즉, DLL 정보들이 있는 시작 주소이다.
- DLL Name RAV = 0x00051D14
- RAW = 0x51D14 - 0x1000 + 0x400 = 0x51114
- 파일에서 DLL Name 시작 주소는 '0x00051114' 이다.
*FirstThunk 4byte 00 10 00 00 -> 00 00 10 00
- IAT(Import Address Table)의 RVA 주소이다.
- 즉, INT 목록에 있는 각각의 함수들이 메모리 상에 로드되는 주소 값들이 있는 시작 주소이다.
- IAT RAV = 0x00001000
- RAW = 0x1000 - 0x1000 + 0x400 = 0x400
- 파일에서 IAT 시작 주소는 '0x00000400' 이다.
1) DLL Name
- 파일에서 DLL Name 시작 주소는 '0x00051114' 이다.
- 53 48 45 4C 4C 33 32 2E 64 6C 6C 00
- SHELL32.dll.
2) INT
- 파일에서 INT 시작 주소는 '0x00051120' 이다.
- 각각의 포인터 배열 요소는 4byte이며, 배열의 끝은 Null(4byte)로 설정된다.
50 23 05 00 6A 23 05 00 7E 23 05 00 A5 00 00 80 8C 23 05 00 00 00 00 00
50 23 05 00 -> 00 05 23 50 -> SHELL32.dll 첫번째 함수 RVA
6A 23 05 00 -> 00 05 23 6A -> SHELL32.dll 두번째 함수 RVA
7E 23 05 00 -> 00 05 23 7E -> SHELL32.dll 세번째 함수 RVA
A5 00 00 80 -> 08 00 00 A5 -> Ordinal
8C 23 05 00 -> 00 05 23 8C -> SHELL32.dll 네번째 함수 RVA
00 00 00 00 -> 00 00 00 00 -> NULL
[참고] Ordinary 번호
- 'E1 00(0x00E1)'는 라이브러리 함수의 고유 번호인 Ordinary이며, 이 다음에 함수 이름이 나온다.
Ex1) SHELL32.dll 첫번째 함수의 RAW 구하기 및 함수 이름 확인
- RAW = RVA - Virtual Address + Pointer to Raw Data
- RAW = 0x52350 - 0x1000 + 0x400 = 0x51750
- SHGetSpecialFolderPathW
Ex2) SHELL32.dll 두번째 함수의 RAW 구하기 및 함수 이름 확인
- RAW = RVA - Virtual Address + Pointer to Raw Data
- RAW = 0x5236A - 0x1000 + 0x400 = 0x5176A
- SHGetFolderPathW
Ex3) SHELL32.dll 세번째 함수의 RAW 구하기 및 함수 이름 확인
- RAW = RVA - Virtual Address + Pointer to Raw Data
- RAW = 0x5237E - 0x1000 + 0x400 = 0x5177E
- ShellAboutW
Ex4) SHELL32.dll 네번째 함수의 RAW 구하기 및 함수 이름 확인
- RAW = RVA - Virtual Address + Pointer to Raw Data
- RAW = 0x5238C - 0x1000 + 0x400 = 0x5178C
- ShellExecuteExW
3) IAT
- 파일에서 IAT 시작 주소는 '0x00000400' 이다.
68 04 82 73 -> 0x73820468
- SHELL32.dll의 첫번째 함수 'SHGetSpecialFolderPathW'는 실행 파일이 로딩되면 '0x73820468에 위치한다.
- 그러나 올리디버거로 '0x73820468' 위치로 이동하면 메모리에 없는 주소로 나온다.
- 이유는 Prebinding 기능 때문에 메모리에 없는 주소로 나옴
- 마우스 우클릭 -> Search for -> Name in all Module -> 'SHGETSP' 검색
Import는 '0x01001000'이며, Export는 '0x76410418'이다.
- 올리디버거에서 '0x76410418'로 이동하여 'SHGetSpecialFolderPathW' 함수 시작 코드를 확인한다.
- 'Ctrl+F2'를 실시하여 '0x01001000'에서 Import 함수들을 확인한다.
01001000 > . 18044176 DD SHELL32.SHGetSpecialFolderPathW -> 0x76410418
01001004 > . 28574776 DD SHELL32.SHGetFolderPathW -> 0x76475728
01001008 > . 49A14B76 DD SHELL32.ShellAboutW -> 0x764BA149
0100100C > . C3DD4F76 DD SHELL32.SHCreateDirectory -> 0x764FDDC3
01001010 > . F61D4176 DD SHELL32.ShellExecuteExW -> 0x76411DF6
4. Prebinding
- 링킹할때 IAT에 실제 Import하는 함수의 주소를 미리 구성하는 기능
- 그렇기 때문에 로딩 시간에 IAT를 완성하지 않고 링키시 IAT를 미리 완성했기 때문에 성능 향싱 및 시간 단축
- 이때, 로드는 BOUND IMPORT TABLE 정보를 기반으로 DLL 바운드 여부를 확인한다.
- 또한, DLL이 바운딩된 경우 링크시 IAT에 기록된 함수 주소와 메모리 상에 주소가 다르게 배정된다.
1) BOUND IMPORT TABLE
- IMAGE_NT_HEADERS -> IMAGE_OPTIONAL_HEARER -> Numer of Data Directories
000001A8 00000270 RVA BOUND IMPORT Table
000001AC 00000154 Size
2) BOUND IMPORT Directory Table
- IMAGE_NT_HEADERS -> BOUND IMPORT Directory Table
00000270 4CE7B9DE Time Data Stamp
00000274 0098 Offset to Module Name
00000276 0000 Number of Module Forwarder Refs
- Offset to Module Name : Import된 DLL 파일명이 있는 주소
첫 비트에서 '0x98' 만큼 이후에 DLL이 바운드되어 있음