작은 메모장

PE 파일의 구조 본문

KISA 사이버 보안 훈련/리버스 엔지니어링 훈련

PE 파일의 구조

으앙내눈 2023. 7. 3. 23:40

PE(Portable Executable)의 기본구조

- 윈도우 운영체제에서 사용되는 EXE, DLL, SYS등의 확장자를 가진 파일

- 동적 라이브러리 정보, API 익스포트 및 임포트 정보, 실행을 위한 코드, 실행에 필요한 리소스 정보 등을 구조화 및 관리하는 방법을 정의

- 실행 과정에서 로더에 의해 가상 메모리 공간에 매핑된 후에도 파일의 레이아웃은 거이 바뀌지 않음

 

PE 파일은 크게 DOS헤더, PE 헤더, 섹션으로 구성되며, 각각의 공간은 서로 다른 정보를 담고 있음

 

DOS Header

1) DOS Header

- MS-DOS 파일에 대한 호환성을 유지하기 위해 존재, "MZ"로 시작

- 구조체 : IMAGE_DOS_HEADER

- 주요 멤버

  1. e_magic: DOS signature로, PE 파일임을 나타내는 첫 2바이트 "MZ
    해당 문자열이 아니라면 PE파일로 인식하지 않음
  2. e_lfanew: NT header가 시작되는 위치의 옵셋, 이 값이 가리키는 위치에 NT header가 존재

2) DOS Stub

- DOS환경에서 실행되는 코드를 위한 영역, 없어도 됨

- DOS환경이라면 "This program cannot be run in DOS mode" 문자열을 출력하고 종료

- 코드와 데이터의 혼합으로 이루어짐

 

PE Header

1) NT Header

- 파일 실행에 필요한 정보가 저장

- Signature, File Header, Optional Header의 3개의 멤버로 구성되어 있음

- 구조체: IMAGE_NT_HEADERS

[1] Signature

     - 가장 첫 멤버, 일반적으로 50450000h("PE"00)을 가짐, 변경 불가

[2] File Header

     - 파일의 개략적인 속성을 나타냄

     - 구조체: IMAGE_FILE_HEADER

     - 주요 멤버

  1. Machine: 파일의 실행 대상 플랫폼을 나타냄, I386(0x014C), IA64(0x200), AMD64(0x8664)등
  2. NumberOfSections: 파일에 존재하는 섹션의 개수를 나타냄, 반드시 0보다 커야함
  3. SizeOFOptionalHeader: 다음에 이어지는 Optional Header의 크기를 알려줌
  4. Characteristics: 파일의 속성을 나타내는 값, exe파일인지, dll파일인지 등의 정보들이 bit OR연산으로 최종값이 설정
  5. TimeDateStamp: 파일의 실행에 영향을 미치지 않는 값, 파일의 빌드 시간을 나타냄

[3] Optional Header

     - 파일 실행에 필요한 주요 정보들을 저장

     - 구조체: IMAGE_OPTIONAL_HEADER

     - 주요 멤버

  1. Magic: IMAGE_OPTIONAL_HEADER32인지, 64인지를 구분(32인 경우 0x10B, 64인 경우 0x20B)
  2. AddressOfEntryPoint: 파일이 메모리에 매핑된 후 코드 시작 주소, ImageBase값에 이 값을 더해 코드 시작 지점을 설정
  3. ImageBase: PE파일이 로딩되는 시작 주소, exe/dll파일은 user memory영역에 위치, sys파일은 kernel memory영역에 위치
  4. SectionAlignment, FileAlignment: 메모리/파일에서 섹션의 최소단위를 나타냄, 각 섹션을 반드시 Alignment의 배수여야함
  5. SizeOfImage: 메모리에 로딩될 때 가상 메모리에서 PE Image가 차지하는 크기
  6. SizeOfHeader: PE Header의 전체 크기, FileAlignment의 배수여야 함
  7. Subsystem: 동작환경을 정의한 내용, sys파일(0x1), GUI파일(0x2), CLI(0x3)의 값으로 세팅
  8. NumberOFRvaAndSize: DataDirectory배열의 개수, 일반적으로 16개를 가짐
  9. DataDirectory: IMAGE_DATA_DIRECTORY구조체의 배열, 디렉토리별로 각각의 정보를 담음
    - Export Directory: DLL등의 파일에서 외부에 함수를 공개하기 위한 정보를 담음
    - Import Directory: 프로그램 실행을 위해 Import하는 DLL이름과 사용할 함수 정보가 담긴 주소 정보를 담음
    - TLS Directory: 스레드 지역 저장소 초기화 섹션에 대한 포인터
    - IAT Directory: IAT의 시작주소를 가리킴

2) Section Header

- 각 Section의 헤더들이 존재하는 곳

- 각 Section들은 메타데이터를 저장하고 메모리에 로드될 때 필요한 정보를 포함

- 주요 멤버

  1. VirtualSize: 메모리 상에서 섹션의 크기
  2. VirtualAddress: 메모리 상에서 섹션의 시작주소
  3. SizeOfRawData: 파일에서 섹션의 크기
  4. PointerToRawData: 파일에서 섹션의 Offset
  5. Characteristics: 섹션의 속성, Bit OR 연산

 

Section

섹션의 유형에는 다음과 같다

  1. Code
    .text: 프로그램 실행 코드를 담고 있는 섹션
  2. Data
    .data: 읽고 쓰기가 가능한 데이터 섹션, 초기화된 전역변수와 정적변수 등이 위치
    .rdata: 읽기 전용 데이터 섹션으로 상수형 변수, 문자열 상수 등이 위치
    .bss: 초기화되지 않은 전역변수를 담구 있는 섹션
  3. Import API
    .idata: Import할 DLL과 API에 대한 정보를 담고 있는 섹션, 대표적으로 IAT
    .didat: Delay-loading importDLL 정보(프로그램 실행 후 DLL 사용시에만 연결하며 릴리즈 모드 시 다른 섹션에 병합)
  4. Export API
    .edata: Export할 API정보를 담고 있는 섹션(주로 DLL에서 사용되며 .text 또는 .rdata에 병합)
  5. Resource
    .rsrc: 리소스 관련 데이터를 담고 있는 섹션(아이콘, 커서 등)
  6. 재배치 정보
    .reloc: 기본 재배치 정보를 담고 있는 섹션
  7. TLS
    .tls: 스레드 지역 저장소
  8. Debugging
    .debug$p: 미리 커파일된 헤더 사용시에만 존재