PE File Format(1)

컴컴한해커·2025년 1월 4일

리버스 엔지니어링

목록 보기
3/18

📌PE File이란?

Portable Executable File로 Windows 운영체제에서 사용되는 실행 파일

종류주요 확장자
실행 계열EXE, SCR
드라이버 계열SYS, VXD
라이브러리 계열DLL, OCX, CPL, DRV
오브젝트 파일 계열OBJ

OBJ를 제외한 모든 파일은 실행 가능


📌 PE File 기본 구조


1. Dos Header ~ Section Header : PE Header
2. Section + NULL : PE Body --> 여기서 NULL Padding을 사용하는 이유 : 처리 효율을 높이기 위해 최소 기본 단위 개념을 사용

  • example : 귤을 한 박스에 담으면 귤을 개수 단위로 세지 않고 박스 단위로 센다. 대량으로 묶어서 관리하면 처리 효율이 높기 때문이다.

📢주소 표현 : VA & RVA

  • VA(Virtual Address) : 프로세스 가상 메모리의 절대 주소
  • RVA(Relative Virtual Address) : 프로세스 가상 메모리의 상대 주소
  • Image Base : 기준 위치
    --> RVA + Image Base = VA ( 상대 주소 + 기준 위치 = 절대 주소 )

📌 PE Header

📢 Dos Header

  • IMAGE_DOS_HEADER의 크기 : 40h
  • 알아야 할 구조체 멤버
    • e_magic : DOS Signature(4D5A -> "MZ")
    • e_lfanew : NT Header의 offset(가변적)

      IMAGE_DOS_Header를 보면 위와 같다.
      ❓e_magic은 자료형이 WORD인데 왜 리틀 엔디언으로 표기가 되지 않고 빅 엔디안으로 표기가 되었을까?
      ❗Chatgpt의 답변 : ASCII 문자로 해석될 여지가 있으면 자료형에 상관없이 텍스트 순서 그대로 저장된다.

📢 DOS Stub

  • 존재 여부는 옵션, 즉 필수가 아님
  • 코드와 데이터의 혼합으로 이루어져 있음 --> Assembly Code + Data
  • notepad.exe의 경우 이 Dos Stub 안의 Assembly Code들을 PE File로 인식하기 때문에 해석하지 못한다. 대신 DOS Debugger를 이용해서 실행 할 수 있다. --> 이 특성을 잘 활용하면 한 실행 파일에서 Windows와 DOS에서 모두 실행 가능한 파일을 만들 수 있다.
    example : McAfee에서 무료로 배포했던 scan.exe 파일이 이와 같은 특징을 가지고 있다.(DOS 환경에서는 16 bit DOS용 코드가, Windows 환경에서는 32 bit Windows 코드가 각각 실행됨)

📢 NT Header

  • IMAGE_NT_HEADERS 구조체의 크기 : F8h
  • Signature 멤버 변수 : 50450000h -> "PE"00
  • File Header 멤버 변수
typedef struct _IMAGE_FILE_HEADER {
	WORD Machine;
    WORD NumberOfSections;
    DWORD TimeDateStamp;
    DWORD PointerToSymbolTable;
    DWORD NumberOfSymbols;
    WORD SizeOfOptionalHeader;
    WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
  1. Machine
    • CPU 별로고유한 값
  2. NumberOfSections
    • 코드, 데이터, 리소스 등 각각의 섹션에 대한 개수 -> 0보다 커야함
  3. SizeOfOptionalHeader
    • 이 값을 보고 IMAGE_OPTIONAL_HEADER의 구조체의 크기를 인식
  4. Characteristics
    • 파일의 속성 --> 실행 가능한지, DLL 파일인지 --> bit OR 형식으로 조합
  5. TimeDataStamp
    • 파일의 실행에 영향을 미치지 않는 값, 파일의 빌드 시간
  • Optional Header 멤버 변수
  1. Magic
    • IMAGE_OPTIONAL_HEADER32의 경우 10B, HEADER64의 경우 20B의 값을 가짐
  2. Address Of Entry Point
    • EP(Entry Point)의 RVA(Relative Virtual Address)의 값을 가지고 있음. --> 프로그램 최초로 실행되는 코드의 시작 주소로 매우 중요함
  3. ImageBase
    • PE 파일이 로딩되는 시작 주소
    • PE Loader는 PE 파일을 실행시키기 위해 프로세스를 생성하고 메모리에 로딩한 후 EIP 레지스터 값을 ImageBase + AddressOfEntryPoint 값으로 세팅
  4. SectionAlignment, FileAlignment
    • 각각 메모리, 파일에서의 최소단위를 나타냄
    • 메모리/파일의 섹션 크기는 반드시 SectionAlignment, FileAlignment의 배수가 되어야 함
  5. SizeOfImage
    • 가상 메모리에서 PE Image가 차지하는 크기
  6. SizeOfHeader
    • PE 헤더의 전체 크기 --> FileAlignment의 배수여야 함
  7. Subsystem
  8. NumberOfRvaAndSizes
    • IMAGE_OPTIONAL_HEADER32 구조체의 마지막 멤버인 DataDirectory 배열의 개수를 의미
    • PE 로더는 이 멤버를 보고 배열의 크기를 인식
  9. DataDirectory

📢 Section Header

메모리 속성별 액세스 권한

종류액세스 권한
code실행, 읽기 권한
data비실행, 읽기, 쓰기 권한
resource비실행, 읽기 권한

IMAGE_SECTION_HEADER 구조체의 중요 멤버

항목의미
VirtualSize메모리에서 섹션이 차지하는 크기
VirtualAddress메모리에서 섹션의 시작 주소(RVA)
SizeOfRawData파일에서 섹션이 차지하는 크기
PointerToRawData파일에서 섹션의 시작 위치
Characteristics섹션의 속성(bit OR)

📢 RVA to RAW

정의

파일이 메모리에 로딩되기 전의 file offset과 로딩되고 나서의 주소를 매칭하는 것
--> RVA는 메모리에 로딩되었을 때의 주소, RAW는 로딩되기 전의 file offset을 의미

비례식

RAW - PointerToRawData = RVA - VirtualAddress
RAW = RVA - VirtualAddress + PointerToRawData

예외 상황
: RVA가 2번째 섹션인데, RAW가 3번째 섹션이다.
--> "해당 RVA에 대한 RAW 값은 정의할 수 없다"라고 표현

PE View를 통해서 간단히 구할 수 있지만, 이정도는 밥 먹듯이 할 줄 알아야 한다.

0개의 댓글