2. 목차
• PE File Format
• 시작하기 전에..
• 복습-DataDirectory
• 잠깐, DLL이란?
• 함수 Import
• IMAGE_IMPORT_DESCRIPTOR
• IMAGE_THUNK_DATA32
• IMAGE_IMPORT_BY_NAME
• IAT
• IAT바인딩 과정
• 함수 Export
• IMAGE_EXPORT_DIRECTORY
• 과제
• 직접 찾아보기
• PE viewer 업데이트
• 부록
• 참고 사이트
4. 복습
• 전 시간에 배운 내용
• IMAGE_DOS_HEADER
• IMAGE_NT_HEADER
• IMAGE_FILE_HEADER
• IMAGE_OPTIONAL_HEADER
• IMAGE_SECTION_HEADER
• 이번에 배울 내용
• IMAGE_OPTIONAL_HEADER의 마지막 값인 DataDirectory를 이용하여 접근 하는 정보들
• 함수의 Import / Export 방법
5. 복습 - DataDirectory
DataDorectory
• 보통 명시된 수(IMAGE_NUMBEROF_DIRECTORY_ENTRIES,
16(0x10))만큼의 배열
• IMAGE_DATA_DIRECTORY struct의 배열, winnt.h에 정의되어 있음
• 배열의 각 항목마다 정의된 값을 가짐
6. 복습 - DataDirectory
• winnt.h에 정의되어 있는 Data Directory와
IMAGE_NUMBEROF_DIRECTORY_ENTRIES
• VirtualAddress를 이용하여 각 항목이
의미하는 데이터를 얻으러 갈 수 있음
9. 잠깐, DLL이란?
• Dynamic-Link Library
• MS Windows에서 구현된 동적 라이브러리
• 다른 프로그램이 불러서 쓸 수 있는 다양한 함수들을 가지고 있음
• 16비트 시절 -> DLL이 없음, 라이브러리만 있음
• 컴파일 시 라이브러리에서 해당 함수의 코드를 그대로 가져와서 프로그램에 넣었음
• 멀티 태스킹을 지원한 이후로 이러한 방식은 비효율적이 됨
• 여러 프로그램이 동시에 실행되어야 하는 상황에서 모든 프로그램마다 따로 라이브러리 코드를 넣는 것은 낭비
• 효율적인 멀티 태스킹을 위해 DLL 개발
• 프로그램에 라이브러리를 포함시키지 말고 별도의 파일(DLL)로 구성하여 필요할 때마다 불러 쓰자
• 일단 한 번 로딩된 DLL의 코드, 리소스는 Memory Mapping 기술로 여러 프로세스에서 공유해 쓰자
• 라이브러리가 업데이트되었을 때, 해당 DLL 파일만 교체하면 되니 쉽고 편해서 좋다
10. 잠깐, DLL이란?
• Linking (DLL 로딩)
• 묵시적 링킹(Implicit Linking) ->앞으로 살펴볼 것
• 실행파일 자체에 어떤 DLL의 어떤 함수를 사용하겠다는 정보를 포함
• OS가 프로그램 실행 시 해당 함수를 초기화한 후 이용
• 프로그램이 시작할 때 가상 메모리에 올리고, 프로그램 종료할 때 가상 메모리에서 해제
• 명시적 링킹(Explicit Linking)
• 프로그램이 실행 중일 때 API를 이용하여 DLL 파일이 있는지 검사
• 동적으로 DLL을 로드하고, 해제함
• LoadLibrary함수로 불러오면 가상 메모리에 올리고, FreeLibrary 함수를 호출하면 가상 메모리에서 해제
11. 잠깐, DLL이란?
• 프로그램에서 많은 DLL을 이용
• DLL도 EXE처럼 PE File Format
• Image base 등 PE header에 따라 메모리에 올림
• 서로 PE header의 값이 같을 수 있음
• Image base 등의 값이 겹치면 다른 곳에 올려야 함
• 이를 relocation이라 함
• 즉, DLL의 주소가 예상과는 다를 수 있음
• 따라서 주소를 하드 코딩하기 어렵고, 유지/보수가 불편함
• 그래서 생긴 개념이 IAT(Import Address Table)
• 프로그램 실행 시 PE 로더가 사용할 라이브러리 함수의 주소를 기록해 줌
• 코드에서는 사용할 함수의 정보가 적혀 있는 테이블의 주소를 써 둠
• 프로그램을 실행할 때 테이블에 내용을 쓰므로, DLL이 다른 imagebase를 이용해도 상관 없음
12. 잠깐, DLL이란? – 매우 단순한 예시
어셈블리 코드
Call 50
주소 50
“Somefunction()의 주소는
100이다.” 라는 정보가 써
있음
(이 정보는 프로그램을
로딩할 때 씀)
Example.dll의 Somefunction()이 올라온 실제 (가상메모리) 주소 : 100
SomeFunction() 의 실제 (가상메모리) 주소를 기록해 둘 위치 : 50
주소 100
Somefunction()의 코드
실행
이러면 DLL이 예상과 다른 장소에 있더라도 코드를 바꿀 필요가 없음
(프로그램 실행 시 DLL이 실제로 올라온 주소를 테이블에 써 두므로)
21. IMAGE_THUNK_DATA32
• winnt.h에 정의된 IMAGE_THUNK_DATA32
• 마지막 NULL 배열이 끝을 의미
• u1
• Union으로, 값이 무엇인가에 따라 용도가
다르게 부름
• Ordinal(서수) 필드를 사용하는 경우, 이
필드가 가리키는 것은 IOT(Import
Ordinal Table)
• AddressOfData 필드를 사용하는 경우,
이 필드가 가리키는 것은 INT(Import
Name Table)이며
IMAGE_IMPORT_BY_NAME배열을
가리킴
• 앞으로 자세히 볼 것은 INT
23. IMAGE_IMPORT_BY_NAME
• winnt.h에 정의된 IMAGE_IMPORT_BY_NAME 구조체
• Padding으로 인해 구조체 크기는 4가 됨
• Name필드 정의는 char 1개 이지만, 사실상 크기에 제한이
없으며 각자의 사이즈에 맞게 할당되는 듯
26. IMAGE_IMPORT_DESCRIPTOR
TimeDateStamp
• 시간과 날짜를 나타내는 타임 스탬프지만
실제 시간과는 상관이 없음
• IMAGE_IMPORT_DESCRIPTOR가 가리키는
해당 DLL이 바인딩 과정을 거치기 전에는
항상 0, 완료된 후에는 -1
• 바인딩이란?
• 로더가 라이브러리를 로드하고, IAT에
값을 기록하는 것(뒤에서 자세히 다룸)
34. Import Address Table (IAT)
실제로 어떻게 함수가 호출되는가 예를 보자.
다음은 printf을 호출하는 모습이다. printf는
msvcrt dll에 속한다는 것을 알 수 있다.
Ollydbg 옵션을 해제하여 symbolic address를
보이지 않도록 설정했다.
printf를 호출하기 위해 0040285C를
호출한다.
35. Import Address Table (IAT)
PE viewer로 import하는 dll의 정보를 찾아보았다.
여태까지는 파일을 한 번 직접 보기 위하여 실제
파일을 까 보았지만 앞으로는 PE viewer
프로그램을 자주 사용할 것이다.
위는 IMAGE_IMPORT_DESCRIPTOR에서 읽어온
dll의 정보이고, 아래는 그 dll과 관련된 INT의
정보이다.
여태까지 예제로 본 것은 KERNEL32.dll이었는데,
printf는 msvcrt.dll에 속한다.(헷갈리지 말자)
해당 dll의 정보를 파일에서 찾아보자.
36. Import Address Table (IAT)
위의 PE viewer를 참고하여 찾은 msvcrt.dll의 정보이다.
msvcrt.dll의 INT
msvcrt.dll의 IAT
37. Import Address Table (IAT)
다시 코드로 돌아와서, call하는 0040285C를
살펴보았다.
40285C에는 또 다른 코드, JMP [4071D4] 가
있다. 이는 ‘4071D4에 저장된 주소’로
점프하라는 코드이다.
38. Import Address Table (IAT)
4071D4가 어디인지 찾아보자. 이는
mscvrt.dll의 IAT에 속한다.
4071D4에 저장된 값은 7594C5B9이다.
39. Import Address Table (IAT)
점프 코드를 실행하면 7594C5B9로 점프한다.
이는 printf함수의 코드이다.
이렇게 함수에 접근하기 위하여 IAT에 저장된
값을 이용한다는 것을 확인할 수 있다.
40. IAT 바인딩 과정
1. IMAGE_IMPORT_DISCRIPTOR(IID)의 Name 멤버를 읽어서 라이브러리의 이름 문자열(ex.
“kernel32.dll”)을 얻는다.
2. 해당 라이브러리를 로딩한다. (불러온다)
3. IID의 OriginalFirstThunk 멤버를 읽어서 INT 주소를 얻는다.
4. INT에서 배열의 값을 하나씩 읽어 해당 IMAGE_IMPORT_BY_NAME 주소(RVA)를 얻는다.
5. IMAGE_IMPORT_BY_NAME의 Hint(Ordinal) 또는 Name 항목을 이용하여 해당 함수의 시작주
소를 얻는다.
6. IID의 FirstThunk 멤버를 읽어서 IAT 주소를 얻는다.
7. 해당 IAT 배열 값에 위에서 구한 함수 주소를 입력한다.
8. INT 배열의 끝까지(NULL을 만날 때까지) 4~7을 반복한다.
43. IAT 바인딩 과정
IMAGE_IMPORT_DISCRIPTOR Name DLL 이름 얻기 DLL 파일에서
정보 불러오기
OriginalFirstThunk INT 접근
IMAGE_IMPOR
T_BY_NAME
얻기
Hint
(Ordinal)
(해당 함수 번호)
Name
함수 시작 주소
구하기
44. IAT 바인딩 과정
IMAGE_IMPORT_DISCRIPTOR Name DLL 이름 얻기 DLL 파일에서
정보 불러오기
OriginalFirstThunk INT 접근
IMAGE_IMPOR
T_BY_NAME
얻기
Hint
(Ordinal)
(해당 함수 번호)
Name
함수 시작 주소
구하기
FirstThunk IAT 접근 IAT 기록
다 기록할 때까지 반복
47. IMAGE_EXPORT_DIRECTORY
• 함수를 다른 프로그램에서 불러 쓸 수 있도록 하기 위한 구조체이다.
• .edata나 .rdata에 있다.
• .edata는 함수 export를 위한 섹션이다.
• Export하지 않는 프로그램은 관련 없음
• DLL에서 중요
• .edata대신 .rdata 섹션에 있을 수도 있다.
• 앞에 r이 붙은 섹션 이름은 보통 read only 섹션을 의미한다.
• API를 제공하여 프로그램이 연동되게 하는 경우 EXE에도 Export 관련 정보가 있을 수 있다.
• EAT라는 매커니즘을 이용한다.
• EAT는 자신이 제공하는 함수에 대한 것이므로, IAT처럼 여러 개 있지 않다.
• 많은 dll을 대상으로 하는 것이 아니기 때문에
• IMAGE_EXPORT_DIRECTORY 구조체가 PE파일에 하나만 존재한다.
59. IMAGE_EXPORT_DIRECTORY
• 찾고자 하는 DLL의 이름을 찾고, AddressOfNames 배열의 몇
번째 인덱스에서 그 이름을 찾았는지 알아낸다.
• 위에서 찾은 인덱스와 같은 인덱스를 이용하여
AddressOfNameOrdinals 배열에 접근하여 저장된 값을
구한다.
• 이 값은 AddressOfFunctions의 인덱스이다.
• 위에서 찾은 AddressOfFunctions의 인덱스를 이용하여
AddressOfFunctions 배열에 접근한다.
• 함수 포인터를 얻을 수 있다.
AddressOfNames RVA RVA RVA RVA
“FuncA” “FuncB” “FuncC” “FuncD”
AddressOfNameOrdinals 0 2 3 4
FuncA
코드
<index 2>
AddressOfFunctions RVA null RVA RVA RVA
FuncB
코드
FuncC
코드
FunD
코드
60. IMAGE_EXPORT_DIRECTORY
• DLL을 이용하기 위해 GetProcAddress 함수를 호출하면, 함수
이름을 찾고, 그에 해당하는 주소를 찾아 반환한다.
• 서수를 이용하여 GetProcAddress를 호출할 수도 있다. 이
때는 서수를 이용하여 찾는다. (이름 찾는 것보다 더 빠르다)
• DLL을 이용하는 PE에 적힌 INT를 읽고, 이름이나 서수를
알아내어 해당 DLL파일의 EAT를 읽어 원하는 함수를 찾은 후,
IAT에 주소를 써 준다.
62. 직접 찾아보기
• printf(“Hello world!”); 프로그램을 만들고, 직접 INT와 IAT를 찾아보자.
• PPT를 보고 따라해 보자.
• 여기저기 뒤적거려보고, 주소들을 따라가보면 좋다.
• 직접 만든 DLL의 함수가 이용되는 모습을 보는 것도 좋은 경험이다.
63. PE viewer 업데이트
• Import 하는 함수 정보도 알아낼 수 있도록 PE viewer를 업데이트 해보자.
• Dll 이름과 그 Dll에서 import할 함수 이름을 인쇄하도록 하자.
65. 참고 사이트
• IAT 자세히 살펴보기
• http://reversecore.com/23
• http://yokang90.tistory.com/26
• EAT 자세히 살펴보기
• http://blog.naver.com/skddms/110180144875
• http://reversecore.com/24