본문 바로가기

보안

PE 포맷

공부 목적으로 적는 글



PE 파일

: Portable Excutable. 윈도우 운영체제에서 사용되는 실행파일. dll, obj코드, FON 폰트 파일 등을 위한 파일 형식.

  즉, 실행 가능한 파일 형식을 말한다.


PE 구조는 크게 PE Header와 PE Body로 나눌 수 있다.


헤더는 DOS Header, DOS Stub, NT Header, 그리고 Section Header들로 이루어져있고, PE Body는 Section들로 이루어져있다.

PE Header의 끝부분과 각  section사이에는 Null Padding 영역이 존재하는데

컴퓨터에서 파일, 메모리, 네트워크 패킷 등을 처리할 때 효율을 높이기 위해 최소 기본 단위 개념을 사용하는데 이 개념을 PE 파일에도 적용한 것.


CFF explorer로 확인한 카테고리

PE Header가 정의 돼있다.



Hex로 확인한 화면. 50 45 의 PE, 밑에는 text나 rdata도 확인할 수 있었다.

대충 확인할 수 있는건 저 정도인 듯


본격적으로 하나 하나 뜯어볼 예정이다.



Image DOS Header


DOS는 디스크 운영 체제

Win32 Platform SDK의 WinNT.H라는 헤더에 PE관련 구조체들이 선언되어있다.

WinNT.H에 선언돼있는 구조체는


이런식으로 선언 돼있는데

DOS Header에서 중요한 필드는 두가진데, e_magic, e_lfanew 이다.

두가지 이외에 다른 값들은 모두 0x00으로 채워져 있어도 상관 없다고 한다.


offset이 0x00인 e_magic은 항상 0x5A4D


hex로 보면 리틀엔디안 형식이라 4D 5A 순서로 돼있다.


이 매직넘버는 아스키 코드로 MZ인데 DOS 개발자의 이니셜을 따온 거라고 한다.


그리고 맨 마지막에 있는 e_lfanew(File address of new exe header)는 NT Header의 가장 첫 필드인 PE signature의 포인터



맨 처음 확인했던 hex 상의 PE 가 저 50 45 였고, 이 e_lfanew 필드는 DOS Stub을 건너뛰고 NT Header로 가게 한다.

그리고 offset이 0x3C인 것을 보면


이부분이 DOS Header에 해당하는 부분인걸 짐작할 수 있다.





DOS Stub


CFF explorer로 확인한 카테고리엔 정의돼있지 않지만


DOS Header의 끝인 e_lfanew의 offset과 NT Header의 첫번째 필드의 offset을 보면 그 중간이 DOS Stub인 걸 알 수 있다.


ASCII 화면에서 다른 이상한 문자들에 비해 "This program cannot be run in DOS mode"라고 문장이 있는데,

DOS Stub의 존재 목적은 OS가 PE 포맷을 알지 못할 때 실행되는 부분으로, 저 문장을 출력한다고 한다.


따라서, OS가 PE 포맷을 알지 못하는게 아니라면 이 부분이 쓰일 일은 없다.


e_lfanew에 의해 NT Header로 건너뛰게 된다.





Image NT Headers



NT Headers는 signature(50 45 00 00), File Header와 Optional Header로 이루어져있다.


Image File Header


signature인 50 45 다음에 오게되는 부분인데 COFF Header라고 부르기도 하는 듯


저 부분이다.


이런식으로 돼있다.


(1) Machine : 파일이 실행될 CPU 플랫폼으로 0x14C는 i386을 뜻한다.


(2) NumberOfSections : 말 그대로 section의 개수, 이 숫자를 수정함에 따라 섹션을 추가할 수도 삭제할 수도 있다.


(3) TimeDateStamp : 파일이 생성된 시간과 날짜를 초단위까지 나타낸다. 1970년 1월 1일 9시를 기준으로 지난 시간을 표시


계산해보니 1970년으로 부터 대략 48년이 지난 후에 생성 됐음을 알 수 있다.


(4) PointerToSymbolTable, NumberOfSymbol 은 디버깅 관련 필드로 별로 알 필요 없는 것 같다.


(5) SizeOfOptionalHeader : Optional Header 크기는 가변적인데, 이 필드로 크기를 지정할 수 있다. 보통 Data Directories를 포함한 Optional Header의 크기는 224바이트이고, Data Directories(128바이트)를 제외한 Optional Header의 크기는 96바이트


(6) Characteristic : 해당되는 항목들 값을 OR시켜서 저장하는 듯 


File executable은 0x2, 32bit word machine은 0x100으로 0x0102


대충 저런식





Image Optional Header


Optional Header는 PE Header중에 가장 많은 부분을 차지하고, 가장 중요한 부분이다.


Optional Header의 필드는 standard fields와 NT additional fields 두가지가 있는 것 같다.




[Standard fields]


(1) Magic : PE signature처럼 Optional Header의 signature. 32bit용 구조체라면 0x10B, 64bit용 이라면 0x20B


0x10B로 32bit용 구조체임을 확인


(2) AddressOfEntryPoint : Entry Point 의 RVA 값

여기서 RVA, VA, ImageBase의 개념이 필요하다.


VA : 가상메모리(Virtual Memory)의 절대 주소

RVA : Relative Virtual Address. ImageBase로부터의 상대적인 주소.

RAW : PE파일이 로딩되기 전의 File Offset. RAW = VA - ( ImageBase + SectionVA ) + SectionRVA

ImageBase : 메모리에 올라갈 때의 Base 주소. exe파일은 0x400000, dll파일은 0x10000000. VA = RVA + ImageBase

RVA가 0x1000이라면 VA는 0x401000이 된다.

그렇다면 AddressOfEntryPoint 값이


0x16D6이므로 EntryPoint의 VA는 ImageBaser값인 0x400000을 더한 0x4016D6




[NT additional fields]


(1) BaseOfCode : .text Section 의 시작 부분의 RVA


(2) SectionAlignment : 메모리에서 section의 최소 단위. section의 크기는 SectionAlignment의 배수여야 한다.


따라서 section 크기는 모두 0x1000의 배수. 인텔 기반 윈도우의 경우 메모리 페이지 크기가 4k 이기 때문에 0x1000을 디폴트 값으로 한다.


(3) FileAlignment : 파일에서 section의 최소 단위


File Alignment 와  Section Alignment 값의 차이 때문에 파일과 메모리 상의 section 크기의 차이가 나게 된다.




(4) SizeOfImage : 메모리상 PE Image의 크기


(5) SizeOfHeader : PE Header의 크기


(6) NumberOfDataDirectories : Optional Header의 다음인 DataDirectories의 개수. 보통 16개라고 정의 돼있다. PE Loader가 이 값을 보고 개수를                                                   인식. 16개라고 돼있지만 실제로는 15개이다. 마지막 엔트리 값이 00으로 설정 되어있기 때문.





Image Data Directories


각 section의 VA와 size를 지정 한다.


Export Directory, Import Directory, Import Address Table Directory 등의 RVA와 Size가 지정돼있다.





Section Headers


Section Headers 부분은 각 section의 속성을 정의해 놓은 부분

Section은 크게 code, data, resource로 나뉜다.



hex view


(1) Name : 8바이트 이하 기준 없이 지정


(2) VirtualSize : Section 크기


(3) Virtual Address : SectionRVA. 메모리상 Section 시작 주소. SectionAlignment(0x1000) 값에 따라서 바뀐다.


(4) SizeOfRawData : 파일에서 Section이 차지하는 크기


(5) PointerToRawData : 파일에서 Section 시작 주소. FileAlignment(0x200) 값에 따라서 바뀐다.


(6) Characteristics : bit OR 값




RVA To RAW


PE 파일이 로딩 됐을 때 RVA값과 File Offset을 잘 매핑 해야 되는데, 이때 이 매핑을 RVA To RAW라고 한다.


RAW = RVA - VirtualAddress + PointerToRawData


ex). RVA = 0x1160

0x1160은 .text에 해당하는 영역으로


VirtualAddress 값이 0x1000이고 PointerToRawData가 0x400으로

RAW = RVA(0x1160) - VirtualAddress(0x1000) +  PointerToRawData(0x400) = 0x560




너무 지체된 거 같아서 IAT는 다음 글에서..


지적은 선하게 부탁드립니당

'보안' 카테고리의 다른 글

[wargame.kr] md5 compare  (0) 2020.01.19
[wargame.kr] DB is really GOOD  (0) 2020.01.15
[wargame.kr] strcmp  (0) 2020.01.14
[wargame.kr] md5 password  (0) 2020.01.12
[wargame.kr] login filtering  (0) 2020.01.11