RVA TO RAW
PE 파일이 메모리에 로딩되었을 때 각 섹션에서 메모리의 주소(RVA)와 오프셋을 잘 매핑해야 한다. 이러한 매핑을 RVA TO RAW라고 부른다
RAW(File Offset)
- 매핑 방식
- RVA가 속해있는 섹션 찾기
- 공식을 이용하여 파일 오프셋을 계산
- 공식
- RAW - PointerToRawData(파일에서의 섹션 시작 위치) = RVA - VA(메모리에서 섹션 시작 위치)
- RAW = RVA - VA + PointerToRawData
예제 #1 RVA = 3000일 때, RAW는 얼마인가?
RVA는 400보다 크고 53200보다 작으므로 Section(text)에 있다
PointerToRawData: 00000400
VA: 01001000
RAW = RVA - VA + PointerToRawData
→ 3000 - 01001000 + 00000400 = FFFF FFFF FF00 2040
⇒ 오류!!! : imagebase를 고려하지 않음
imagebase: 01000000
VA - imagebase(주소를 조정하기 위해) = 1000
다시 ⇒ 3000-1000+400 = 2400(RAW)
#2 RVA = BC123일 때, RAW는?
RVA는 section(.reloc)에 위치
PointerToRawData: B9C00
VA: BC000
RAW = BC123 - BC000 + B9C00
IAT(1)
IAT: 윈도우 운영체제의 핵심 개념인 process와 memory 구조 등의 근간을 이해한다고 할 수 있음. 프로그램에서 어떤 라이브러리에서 어떤 함수를 사용하고 있는지 기술한 테이블(배열)
DLL: 동적 링크 라이브러리.
- dll의 초기 구상
- 프로그램에 라이브러리를 포함시키지 말고 별도의 파일 dll로 구성하여 필요할 때마다 호출하자
- 일단 한 번 로딩된 dll의 코드 리소스를 메모리 매핑 기술로 다같이 나누어 쓰자
- 라이브러리가 업데이트 됐을 때 해당 dll 파일만 교체하면 되니까 간편하다
- dll이 로딩되는 방식
- 프로그램에서 사용되는 순간 딱 로딩하고 사용 끝나면 메모리에서 해제되는 방법 → explicit linking
- 프로그램이 실행될 때 같이 연결되어 프로그램 종료 시 메모리에서 해제된다 → implicit linking
- dll 재배치
- 어떤 파일의 imagebaserk 10000인데 로딩을 하려고 하니 다른 파일이 이미 그 자리를 차지하고 있다면, 다른 빈 공간을 찾아서 로딩
IAT(2)
PE파일은 자신이 어떤 라이브러리를 import 하고 있는지 IAT 구조체를 통해서 명시하고 있다
아래의 모든 주소는 RVA
- OriginalFirstThunk: INT(Import name table) 주소(RVA)
- Characteristics:
- Name: library 이름 문자열 주소
- FirstThunk: IAT 주소를 가리킨다
참고로 INT와 IAT는 Long type 배열이고 null로 끝나고 INT와 IAT 값이 서로 같아야 한다
PE로더가 임포트 함수를 IAT에 입력하는 기본적인 순서가 있음!
- IAT 입력 순서
- IMAGE_IMPORT_DESCRIPTOR의 name 멤버를 읽고 나서 library 이름 문자열(kernel32.dll)을 읽기
- 해당 라이브러리를 로딩한다 → LoadLibrary(kernel32.dll)
- IMAGE_IMPORT_DESCRIPTOR의 OriginalFirstThunk 멤버를 읽어서 INT 주소를 얻는다
- 그 주소로 INT에서 배열의 값을 하나씩 읽어서 IMAGE_IMPORT_BY_NAME 주소(RVA)를 얻음
- IMAGE_IMPORT_BY_NAME에서 Hint(고유번호) 또는 Name 항목 > 함수 시작주소 얻음 (GetProcAddress() 함수로)
- IAT 배열 값에 위에서 구한(4번) 함수 주소를 입력
- INT null일 때까지 4~6 반복
IMAGE_OPTIONAL_HEADER32.DataDirectory[1].VirtualAddress → IMAGE_IMPORT_DESCRIPTOR
- 라이브러리 이름(Name)→ IMAGE_IMPORT_DESCRIPTOR의 name 멤버를 읽고 나서 library 이름 문자열(kernel32.dll)을 읽기
- Name 항목은 임포트 함수가 라이브러리에 파일의 이름 문자열 포인터이다
- OriginalFirstThunk - INT(import name table)→ IMAGE_IMPORT_BY_NAME
- INT: 임포트하는 함수의 정보가 담긴 구조체 포인터 배열. 이 정보는 필요로 하는 프로세스의 메모리에 로딩된 라이브러리에서 해당 함수의 시작주소를 정확히 구할 수 있다
- Ordinal은 고유번호인데 함수들이 변수들을 구별하기 위한 번호
- 정리하자면 IMAGE_IMPORT_BY_NAME은 DLL에서 함수를 호출할 때 필요한 정보(이름, 고유번호)을 담고있다 (그 정보를 토대로 주소를 서치)
<정리>
OriginalFirstThunk는 INT를 가리킨다. 그리고 INT와 IMAGE_IMPORT_BY_NAME의 차이점으느 INT는 함수 이름과 고유번호를 담고 있고, IMAGE_IMPORT_BY_NAME는 해당 함수에 대한 자세한 정보를 담고 있다.
그리고 NAME과 IMAGE_IMPORT_BY_NAME의 차이점은 가져와야 하는 DLL 파일의 이름을 가리키고 IMAGE_IMPORT_BY_NAME DLL에서 내보내야 하는 함수의 이름과 고유번호 값을 가지고 있는 구조체이다
'reversing' 카테고리의 다른 글
[dreamhack] rev-basic-0 (0) | 2025.03.23 |
---|---|
NT header, Section header (0) | 2025.02.12 |
함수 호출 규약, PE file (0) | 2025.02.12 |
레지스터, 프로세스 메모리 구조, 섹션, 스택, 힙 (0) | 2024.10.27 |
악성코드 종류와 분석 (1) | 2024.10.19 |