iohyeon 2020. 9. 20. 12:48

I. PE(Portable Executable) File

       : Microsoft에서 만든 Windows 운영체제(3.1 이후)에서 사용되는 32bit 형태의 실행 파일 형식, UNIX의 COFF(Common Object File Format) 기반

        : PE32 (64bit는 PE+ 혹은 PE32+)

         * 해당 게시물은 32bit를 기준으로 작성되었다.

 

       i. Type

PE File Type from ReversCode

             실행 가능 파일 : 실행 계열, 드라이버 계열, 라이브러리 계열 (단, 실행 계열만 셸에서도 실행)

 

       ii. RVA

             : Relative Virtual Address, ImageBase(기준 위치)에서부터의 상대 주소

             > VA & RVA

                    > VA : Virtual Address, 프로세스 가상 메모리의 절대 주소

                    → VA = RVA + ImageBase

                    RVA를 쓰는 이유 : 프로세스 가상 메모리 특정 위치에 로딩되려 할 때 해당 위치에 다른 PE 파일이 있을 경우 Relocation을 하기 위해

             > RVA to RAW

                    : PE 파일이 메모리에 로딩됐을 때 각 섹션에서의 메모리 주소(RVA)와 파일 offset Mapping

                    : RVA가 속해있는 섹션 찾기 비례식을 사용하여 파일 offset(RAW) 계산

                    : RAW - PointerToRawData = RVA - VirtualAddress

                      RAW = RVA - VirtualAddress + PointerToRawData

 

       iii. Basic Structure

Loading/Mapping PE File Format on memory from file from ReverseCore

            → 파일/메모리에서 섹션의 시작 위치는 각 파일/메모리의 최소 기본 단위의 배수에 해당하는 위치, 빈 공간은 NULL padding으로 채움, 구조체로 구성

                Image : 메모리에 로딩된 상태

             > DOS Header

                    : 하위 호환성 위해 DOS EXE Header 확장시킨 IMAGE_DOS_HEADER 구조체, 40의 크기, PE 구조 여부

IMAGE_DOS_HEADER Structure from ReverseCode

                    > e_magic : DOS Signature, "4D5A"("MZ")

                                   ! 없으면 PE 파일이 아니거나 패킹된 것

                    > e_lfanew : IMAGE_NT_HEADERS(NT Header 구조체)의 offset(위치) 표시

 

             > DOS Stub

                    : 코드와 데이터의 혼합으로 구성, 부정 크기, 존재 여부는 옵션

DOS Stub Structure from ReverseCode

                    cf) 16bit에서는 40~4D 영역이 어셈블리 명령어

 

             > IMAGE_NT_HEADERS

                    : NT Header 구조체, 3개로 구분

IMAGE_NT_HEADERS Structure from ReverseCore

                   > Sinature : "50450000"("PE"00)

                                  ! 없으면 PE 파일이 아니거나 패킹된 것

 

                   > File Header

                          : IMAGE_FILE_HEADER, 파일의 개략적인 속성

IMAGE_FILE_HEADER Structure form ReverseCore

                          > Machine : CPU 고유 값, 파일 동작 환경

Machine Number of CPU from ReverseCore

                                → IA-32 : 14Ch, IA-64 : 200h

                          > NumberOfSections : 섹션의 개수, 최소 1개 이상, 실제 섹션 개수와 다를 경우 실행 에러

                          > SizeOfOptionalHeader : NT Header의 IMAGE_OPTIONAL_HEADER32 구조체 크기 (64bit는 IMAGE_OPTIONAL_HEADER64 구조체)

                          > Characteristics : 파일 속성 및 형식, 실행 가능 형태 및 DLL 파일 여부 등의 정보들을 bit OR 형식으로 조합

Characteristics in IMAGE_NT_HEADERS from ReverseCode

                                    0002h(Executable, obj나 DLL의 경우 없음), 2000h(File_DLL)

                        → Machine, NumberOfSections, SizeOfOptionalHeader, Characteristics가 정확히 세팅돼있지 않으면 파일 정상 실행되지 않음

                          > TimeDateStamp : 해당 파일의 빌드 시간, 개발 도구와 그 옵션에 따라 VB나 VC++는 이 값을 세팅해주지만, Delphi는 이 값을 세팅해주지 않음

 

                   > Optional Header

                          : PE 헤더 구조체 중 가장 큰 크기

IMAGE_OPTIONAL_HEADER32 Structure from ReverseCode

                          > Magic : Optional Header의 비트 수, 32bit에서 10Bh, 64bit에서 20Bh

                          > AddressOfEntryPoint : EP(Entry Point)의 RVA 주소 값, 프로그램에서 최초로 실행되는 코드의 시작 주소

                          > ImageBase : 메모리에서 PE 파일이 로딩/매핑되는 시작 주소, 메모리 적재 전엔 0

                                             : EXE, DLL 파일은 user memory 영역인 0~7FFFFFFF 범위 에 로딩 SYS 파일은 kernel memory 영역인 80000000~FFFFFFFF 범위에 로딩

                                              : 일반적으로 개발 도구(VB/VC++/Delphi)들이 만든 EXE 파일의 Image Base 값은 00400000, DLL 파일의 IrnageBase값은 10000000

                                              → PE 로더는 PE 파일을 실행시키기 위해 프로세스 생성하고 메모리에 로딩한 후 EIP 값을 ImageBase+AddressOfEntryPoint 값으로 세팅

                          > FileAlignment, SectionAlignment : 파일에서의 섹션 최소 단위, 메모리에서의 섹션 최소 단위

                          > SizeOfImage : PE 파일이 메모리에 로딩됐을 때 가상 메모리에서 PE Image의 크기

                          > SizeOfHeader : PE 헤더의 크기, FileAlignment의 배수, 파일 시작에서 SizeOfHeader offset만큼 떨어진 위치가 첫번째 섹션 위치

                          > Subsystem : 시스템 종류가 시스템 드라이버(SYS)인 지 일반 실행(EXE, DLL)인 지 구분

Subsystem from ReverseCode

                          > NumberOfRvaAndSizes : NT Header의 IMAGE_OPTIONAL_HEADER32 구조체의 DataDirectory 배열의 개수, 보통 10h

                          > DataDirectory

DataDirectory Structure Array from ReverseCode
DataDirectory Structure

                                EXPORT, IMPORT, RESOURCE, TLS Directory

                        → 위 값들이 정확히 세팅돼있지 않으면 파일 정상 실행되지 않음

 

             > IMAGE_SECTION_HEADER

                    : 각 섹션의 속성(File/Memory에서의 시작 위치, 크기, 엑세스 권한 등)

Memory Access Authority of Sections from ReverseCode 
IMAGE_SECTION_HEADER Structure from ReverseCode

                          > VirtualSize, VirtualAddress, SizeOfRawData, PoinToRawData, Charateristics :

Important members of IMAGE_SECTION_HEADER Structure from ReverseCode

                                  > VirtualAddress, PoinToRawData : 각각 IMAGE_OPTIONAL_HEADER32의 SectionAlignment와 FileAlignment에 맞게 결정

                                  > Characteristics : 아래 값들의 bit OR 조합으로 형성

Characteristics in IMAGE_SECTION_HEADER from ReverseCode

                                        CNT_CODE : 코드 섹션

                                         CNT_INITIALIZED_DATA, CNT_UNINITIALIZED_DATA : 데이터가 초기화, 비초기화된 섹션

                                         MEM_EXECUTE, MEM_READ, MEM_WRITE : 실행, 읽기, 쓰기가 가능한 섹션

                          > Name : NULL로 끝나야한다거나 ASCII값만 와야한다는 제한이나 규칙 x