나만의 메모노트

[리버싱 핵심원리] PE File Format (3) 본문

Security/Reversing

[리버싱 핵심원리] PE File Format (3)

sp3arm4n 2021. 8. 1. 03:06

NT Header

  • IMAGE_NT_HEADERS
    • NT Header의 구조체
    • 3개 멤버로 구성
      • PE Signature : 50450000h(“PE”00) 값을 가짐
      • File Header 구조체
      • Optional Header 구조체
  • 크기 : F8 (248byte)

IMAGE_NT_HEADERS 구조체
notepad.exe NT Header

File Header

  • IMAGE_FILE_HEADER 구조체
    • 파일의 개략적인 속성을 나타냄

IMAGE_FILE_HEADER
notepad.exe File Header

  • 주요 멤버
    • 각 멤버별 값들의 설정이 부정확할 경우 비정상 실행
      1) Machine
      • Machine 넘버는 CPU별로 고유한 값을 가짐 (32bit Intel x86 호환칩 = 14C의 값)
      • winnt.h 파일에 정의된 Machine 넘버의 값
      2) NumberOfSections
      • 섹션의 개수
        • 해당 값은 반드시 0보다 커야 함
        • 정의된 섹션 개수와 실제 섹션이 다르면 실행 에러가 발생
      3) SizeOfOptionalHeader
      • SizeOfOptionalHeader
        • IMAGE_OPTIONAL_HEADER32 구조체의 크기
          • IMAGE_OPTIONAL_HEADER32
            • IMAGE_NT_HEADERS 구조체의 마지막 멤버
            • C언어 구조체로써 이미 그 크기가 결정되지만, Windows의 PE loader는 SizeOfOptionalHeader 값을 보고 해당 구조체의 크기를 인식
          • PE32+ 형태의 파일인 경우 IMAGE_OPTIONAL_HEADER64 구조체를 사용
            • 두 구조체의 크기가 상이하므로 해당 멤버에 구조체 크기를 명시
        • 일반적인 PE 파일 형식을 벗어난 PE Patch 생성 가능
          • IMAGE_DOS_HEADER의 e_lfanew 멤버와 IMAGE_FILE_HEADER의 SizeOfOptionalHeader 멤버에 의해
      4) Characteristics
      • 파일의 속성을 나타내는 값
        • 실행 가능한 형태인지 (executable or not) 혹은 DLL 파일인지 등의 정보들이 bit OR 형식으로 조합됨
      • PE 파일 중 해당 값에 0002h가 없는 경우도 존재 (not executable)
        • *.obj와 같은 object 파일 및 resource DLL 같은 파일
      • TimeDataStamp
        • 실행 파일에 영향을 미치지 않으며, 해당 파일의 빌드 시간을 나타낸 값

Optional Header

  • IMAGE_OPTIONAL_HEADER32
    • 크기가 가장 큰 PE Header 구조체
      IMAGE_OPTIONAL_HEADER 구조체
      notepad.exe Optional Header
    • 주요 멤버
      • 각 멤버들은 파일 실행에 필수적인 요소
      • 해당 값들의 설정이 부정확할 경우 비정상 실행주요 멤버
      1) Machine
      • IMAGE_OPTIONAL_HEADER32 구조체의 Magic 넘버 = 10Byte
      • IMAGE_OPTIONAL_HEADER64 구조체의 Magic 넘버 = 20Byte
      2) AddressOfEntryPoint
      • EP(Entry Point)의 RVA (Relative Virtual Address) 값을 가지고 있음
        • 프로그램에서 최초로 실행되는 코드의 시작 주소 (매우 중요한 값)
      3) ImageBase
      • 프로세스의 가상 메모리(범위 : 0 ~ FFFFFFFF)에서 PE 파일이 로딩되는 시작 주소
        1. ① PE loader는 PE 파일을 실행시키기 위해 프로세스를 생성
        2. ② 파일을 메모리에 로딩
        3. ③ EIP 레지스터 값을 ImageBase + AddressOfEntryPoint 값으로 설정
          파일 영역 로딩 범위 Image Base 값
          EXE User memory 0~7FFFFFFF 00400000
          DLL 10000000
          SYS Kernel memory 80000000~FFFFFFFF -
      4) SectionAlignment, FileAlignment
      • FileAlignment : 파일에서 Section의 최소단위를 나타낸 것
      • SectionAlignment : 메모리에서 Section의 최소단위를 나타낸 것
      • 하나의 파일에서 FileAlignment와 SectionAlignment의 값은 같거나 다를 수 있음
      • File/Memory의 Section Size는 반드시 FileAlignment와 SectionAlignment의 배수가 되어야 함
      5) SizeOfImage
      • PE 파일이 메모리에 로딩되었을 때 가상 메모리에서 PE Image가 차지하는 크기
      • 파일의 크기와 메모리에 로딩된 크기는 다름
      6) SizeOfHeader
      • PE 헤더의 전체 크기
      • 해당 값은 FileAlignment의 배수여야 함
      • 1st Section location : 파일 시작에서 SizeOfHeader offset만큼 떨어진 곳
      7) Subsystem
      • 해당 값을 보고 시스템 드라이버 파일(.sys)과 일반 실행 파일(.exe, *.dll)을 구분
        의미 비고
        1 Driver file 시스템 드라이버(:ntfs.sys)
        2 GUI (Graphic User Interface) 파일 창 기반 애플리케이션(:notepad.exe)
        3 CUI (Console User Interface) 파일 콘솔 기반 애플리케이션 (:cmd.exe)
      8) NumberOfRvaAndSizes
      • IMAGE_OPTIONAL_HEADER32 구조체의 마지막 멤버인 DataDirectory 배열의 개수
      • 구조체 정의에 배열 개수 명시되어 있음
        • IMAGE_NUMBEROF_DIRECTORY_ENTRIES (16)
      • PE loader는 해당 값을 보고 배열의 크기를 인식 (16이 아닐 수도 있다는 의미)
      9) DataDirectory
      • IMAGE_DATA_DIRECTORY 구조체의 배열로 각 항목마다 정의된 값을 가짐
      • 주요 배열
        • EXPORT Directory
        • IMPORT Directory
        • RESOURCE Directory
        • TLS Directory

DataDirectory 배열

Section Header

  • Section Header
    • 각 Section의 속성(property)을 정의하는 것
      • Section의 속성에는 File/Memory에서의 시작 위치, 크기, 접근 권한 등이 있음
  • 초기 PE File Format
    • PE File을 여러 개의 Section 구조로 분류 👉 프로그램의 안정성을 높이기 위함
    • 비슷한 성격의 자료를 Section이라고 이름 붙인 곳에 모아두기로 함
    • 각각의 Section의 속성을 Section Header에 기술함
  • code/data/resourse마다 각각의 특성, 접근 권한, 등을 다르게 설정할 필요가 있음 
    종류 접근 권한
    code 실행, 읽기 권한
    data 비실행, 읽기, 쓰기 권한
    resourse 비실행, 읽기 권한
  • IMAGE_SECTION_HEADER
    • Section Header는 각 Section별 IMAGE_SECTION_HEADER 구조체의 배열로 구성
    • 주요 멤버
      멤버명 의미
      VirtualSize 메모리에서 섹션이 차지하는 크기
      VirtualAddress 메모리에서 섹션의 시작 주소(RVA)
      SizeOfRawData 파일에서 섹션이 차지하는 크기
      PointerToRawData 파일에서 섹션의 시작 위치
      Characteristics 섹션의 속성(bit OR)
      IMAGE_SECTION_HEADER 구조체
    • VirtualAddress와 PointerToRawData는 아무 값이나 가질 수 없음
      • 각각 SectionAlignment와 FileAlignment에 맞게 결정됨
    • VirtualSize와 SizeOfRaqData는 서로 다른 값을 가짐
      • 파일에서의 섹션 크기와 메모리에 로딩된 섹션의 크기가 다르기 때문
    • Characteristics는 아래 그림에 표시된 값들의 조합(bit OR)

  • Name
    • C언어의 문자열처럼 NULL로 끝나지 않음
    • ASCll 값만 사용한다는 제한도 없음
    • 참고용으로 사용할 뿐 어떤 정보로써 활용하기에는 100% 장담할 수 없음
      • PE 스펙에는 Section Name에 대한 어떠한 명시적인 규칙이 없으므로 어떠한 값을 넣어도 되고 심지어 NULL로 채워도 됨
        notepad.exe Section Header

RVA to RAW

  • RVA
    • PE 파일이 메모리에 로딩되었을 떄의 메모리 주소
  • RAW
    • PE 파일이 로딩되기 전에 File Offset
  • RVA to RAW
    • PE 파일의 각 섹션이 메모리에 로딩되기 전의 File Offset과 메모리에 로딩된 후에 로딩된 위치의 주소를 매칭하는 것 (일반적인 매핑)
    • 매핑하는 방법
      • RVA가 속해 있는 섹션을 찾는 방법
      • 간단한 비례식을 사용해서 파일 offset(RAW)을 계산하는 방법