본문 바로가기

[+] Information/[-] RCE

PE 구조 (4)

이번에는 PE 헤더 영역에 3번째 부분인 PE File Optional Header 부분에 대해 알아 볼 차례이다.

[PE File Optional Header]
이 부분은 실행파일의 실행정보가 담긴 부분이며, 필수적인 부분이어서 PE File Header 부분보다 더 중요시 된다.
Option이라는 이름이 붙은 이유는 오브젝트가 이 영역을 선택적으로 가질 수 있기 때문인데, 정작 오브젝트에서는 별다른 기능을 발휘하지 않는다.
PE File Optional Header 부분은 IMAGE_OPTIONAL_HEADER 구조체로 되어 있으며, 크기가 유동적이고 앞서 보았던
IMAGE_NT_HEADER의 SizeOfOptionalHeader 구조체멤버에 의해 크기가 결정 되며, PE File Header 바로 뒤에 위치해 있다. IMAGE_OPTIONAL_HEADER 구조체는 Standard Fields, NT additional Fields, IMAGE_DATA_DIRECTORY로 구분이 된다. 이제부터 3가지에 대해서 상세히 알아 볼 것이다. 


[Standard Fields]
파일을 로드하고 실행하는것에 대한 정보가 들어있다.
아래는 IMAGE_OPTIONAL_HEADER안에 있는 Standard Fields 영역에 구조이다.

[그림 1 - Standard Fields]


아래 notepad.exe 파일의 Standard Fields 영역을 보면서 각 구조체 멤버에 대해 설명하겠다.

[그림 2 - Standard Fields 영역의 구조체 멤버들 표시]


 - Magic : 실행 파일의 상태를 나타내는 부호없는 정수 값을 가지고 있으며, 이 값이 "0x010B" 라면 일반적인 실행 파일을
               뜻하는 것이고, "0x0107" 이라면 롬이미지, "0x020B" 라면 64bit Executable 타입이라는 것을 의미한다.
               오프셋은 0x00 ~ 0x01이며, 크기는 2바이트이다.
               위 이미지에서는 "0x010B" 값을 가지고 있으므로 일반 실행파일을 뜻하는 것을 알 수 있다.

 - MajorLinkerVersion : 링커의 상위 버전넘버를 저장하는 멤버이다. 오프셋은 0x02이며, 크기는 1바이트 이다.
                                  위 이미지에서는 "0x09" 라는 값을 가지고 있다.

 - MinorLinkerVersion : 링커의 하위 버전넘버를 저장하는 멤버이다. 오프셋은 0x03이며 크기는 1바이트 이다.
                                  위 이미지에서는 "0x00" 이라는 값을 가지고 있다. 

 - SizeOfCode : 코드 섹션(.text)의 크기 정보를 가지고 있으며, 코드 섹션이 여러개라면 그것들의 합에 대한 값을
                       가지고 있다. 오프셋은 0x04 ~ 0x07이며, 크기는 4바이트 이다.
                       위 이미지에서는 "0x0000A800" 의 값을 가지고 있다. 이 값은 10진수로 변환하면  "43008" 이 되므로
                       43008바이트의 크기를 가지고 있는 것이 된다.

 - SizeOfInitializedData : 초기화된 데이터 섹션의 크기를 값으로 가지고 있으며, SizeOfCode 멤버와 마찬가지로 자신이
                                    담당하고 있는 섹션의 수가 여러개라면 그들의 합에 대한 값을 가진다. 오프셋은 0x08 ~ 0x11
                                    이며, 크기는 4바이트 이다.위 이미지에서는 "0x00022400" 값을 가지고 있으며 10진수로
                                    변환시 "140288" 이 되므로 140288바이트의 크기를 가지고 있는 것이 된다.

 - SizeOfUninitializedData : 초기화되지 않은 데이터 섹션의 크기를 값으로 가지고 있으며, 섹션이 여러개 일시 위의
                                       구조체 멤버와 동일한 성격을 지닌다. 오프셋은 0x12 ~ 0x15이며, 크기는 4바이트 이다.
                                       위 이미지에서는 "0x00000000" 이라는 값을 가지고 있으며 이는 "0"을 뜻한다. 즉 초기화
                                       되지 않은 데이터가 없다는 뜻이 된다.

 - AddressOfEntryPoint : 메모리에 맵핑된 상태에서의 실행 코드 주소를 가지고 있다. 이 주소는 절대적인 주소가 아닌
                                    상대적인 주소(RVA)이며, 보통 .text 섹션 내의 특정 주소를 가리키게 된다. 실행 파일에서의
                                    이 주소는 실행 코드의 시작 주소이며, 디바이스 드라이버에서는 초기화 함수의 주소가 된다.
                                    반면 DLL 파일은 이 값이 선택적이며, 이 값이 없다면 반드시 0으로 되어야 한다. 오프셋은
                                    0x16 ~ 0x19 이며 크기는 4바이트 이다. 위 이미지에서는 "0x003689"라는 값을 가지고
                                    있다.

 - BaseOfCode : 실행 파일이 메모리에 맵핑된 상태에서의 코드섹션(.text) 주소를 가지고 있다. 이 값은 상대적 주소인
                         RVA 값이다. 오프셋은 0x20 ~ 0x23이며, 크기는 4바이트 이다. 위 이미지에서는 "0x00001000"
                         이라는 값을 가지고 있다.

 - BaseOfData : 실행 파일이 메모리에 맵핑된 상태에서의 데이터 섹션(.data) 주소를 가지고 있다. 이 값은 상대적 주소인
                        RVA 값이다. 오프셋은 0x24 ~ 0x27이며, 크기는 4바이트 이다. 위 이미지에서는 "0x0000C000"
                        이라는 값을 가지고 있다.


 위에서 RVA 라는 단어가 많이 나온다. 이쯤에서 RAV란 무엇인지 알고 가는 것이 좋을 것 같다.

[RVA(Relative Virtual Address)]
실행파일이 프로세스를 만들고 실행파일의 코드와 데이터가 가상메모리에 맵핑이되면 메모리에 맵핑되는 지점의 시작 주소가 베이스 주소(Base Address)가 된다. RVA는 이 가상 메모리상의 베이스 주소를 기준으로 로드된 실행 파일의 상대적인 위치를 의미한다. 가상메모리에서의 가상주소는 아래와 같은 형식으로 구할 수 있다.

가상 주소 = 베이스 주소(Base Address) + RVA
RVA는 가상 메모리에 맵핑된 이후의 오프셋 값이므로 PE 파일상의 오프셋과 같다고 생각하면 안된다.
물론 PE 파일은 가상메모리에 그대로 맵핑이 되어 순서가 맵핑 되기전과 같지만, 가상메모리에 맵핑이 되면 섹션 사이에
패딩이 생겨 오프셋값이 달라진다. 


이번에는 NT Additional Fields 영역을 알아볼 차례이다.

[NT Additional Fields]
이 영역은 Standard Fields 바로 다음부터 시작되며, 많은 구조체 멤버로 이루어져 있다.
이 영역에서 제공되는 정보는 윈도우 링커와 로더가 사용하는 정보다.
아래는 해당 영역의 구조이다.

[그림 3 - NT Additional Fields]

링커와 로더가 사용하는 정보다 보니 32bit 실행 파일과 64bit 실행 파일의 오프셋이 조금 다르다.
아래 이미지는 32bit 실행 파일이므로 참고하기 바란다.(같은 구조체이기 때문에 오프셋은 계속 이어감)

[그림 4 - NT Additional Fields의 구조체 멤버들 표시]

 - ImageBase : 가상메모리에 로드된 실행 파일의 주소를 가지고 있다. 이 값은 반드시 64KB의 배수여야 한다. 오프셋은
                       0x28 ~ 0x 31이며, 크기는 4바이트 이다. 위 이미지에서는 "0x01000000" 이라는 값을 가지고 있다.
* 참고 : ImageBase 구조체 멤버값과 Standard Fields의 BaseOfCode값을 더하면 .text 가상메모리 주소다

 - SectionAlignment : 가상 주소에 맵핑 될 때 섹션이 할당 받을 가상 주소의 기준값을 가지고 있다. 섹션은 메모리에
                               맵핑 될 때 섹션별로 맵핑되기 때문이다. 섹션의 시작 주소는 항상 메모리 페이지의 배수여야 하므로
                               이 값은 FileAlignment와 같거나 커야 하며, 기본 값은 페이지의 크기와 같다. 오프셋은
                         0x32 ~ 0x35이며, 크기는 4바이트 이다. 위 이미지에서는 "0x00001000" 이라는 값을 가지고 있
                               다. 이 값이 BaseOfCode와 같은 것을 볼 수 있는데 이는 .text 섹션부터 메모리에 맵핑 된다는 것을
                               의미한다.

- FileAlignment : PE 파일 내에서 섹션들이 시작하는 주소의 기준 값이다. 따라서 PE 파일내에서의 섹션이 시작하는
                         주소는 항상 이 값의 배수가 된다. 이 값은 2에서 512사이에 있는 2의 멱승이거나 64KB가 되지만
                         기본값은 512이다. SectionAlignment의 값이 메모리 페이지 크기보다 작다면 FileAlignment의
                    값과 동일하여야 한다.
 오프셋은 0x36 ~ 39이며, 크기는 4바이트 이다. 위 이미지에서는
                    "0x00000200" 값을 가지고 있는데 이 값을 10진수로 변환하면 512가 된다. 기본 값을 가지고 있다는
                         뜻이 된다. 

 - MajorOperatingSystemVerison : 실행 파일을 실행하는데 필요한 OS의 최소 상위버전의 값을 가지고 있다.
                                                  오프셋은 0x40 ~ 0x41이며, 크기는 2바이트 이다. 위 이미지에서는 "0x0006"
                                                  이라는 값을 가지고 있다.

 - MinorOperatingSystemVersion : 실행 파일을 실행하는데 필요한 OS의 최소 하위버전의 값을 가지고 있다.
                                                  오프셋은 0x42 ~ 0x43이며, 크기는 2바이트 이다. 위 이미지에서는 "0x0001"
                                                  이라는 값을 가지고 있다.

 - MajorImageVersion : 실행파일의 상위버전의 값을 가지고 있다. 오프셋은 0x44 ~ 0x45이며, 크기는 2바이트 이다.
                                  위 이미지에서는 "0x0006" 이라는 값을 가지고 있다. 

 - MinorImageVersion :  실행파일의 하위버전의 값을 가지고 있다. 오프셋은 0x46 ~ 0x47이며, 크기는 2바이트 이다.
                                   위 이미지에서는 "0x0001" 이라는 값을 가지고 있다. 

 - MajorSubsystem : 실행 파일을 실행하는데 필요한 서브시스템의 상위버전의 값을 가지고 있다. 오프셋은
                               0x48 ~ 0x49이며, 크기는 2바이트 이다. 위 이미지에서는 "0x0006" 이라는 값을 가지고 있다.

 - MinorSubsystem : 실행 파일을 실행하는데 필요한 서브시스템의 상위버전의 값을 가지고 있다. 오프셋은 
                               0x50 ~ 0x51이며, 크기는 2바이트 이다. 위 이미지에서는 "0x0001" 이라는 값을 가지고 있다.

 - Win32VersionValue : 이 멤버는 VC++6.0 SDK까지는 예약 영역이었으며 7.0부터 지금의 이름으로 바뀌었다. 하지만
                                  여전히 사용하지 않아 보통 0으로 되어있다. 오프셋은 0x52 ~ 0x55이며, 크기는 4바이트 이다.
                                  위 이미지에서는 0의 값을 가지고 있다.

 - SizeOfImage : 메모리에 로드되었을 때 실행 파일의 크기 값을 가지고 있다. 이 값은 헤더를 포함했을 때의 크기이며,
                         반드시 SectionAlignment의 배수여야 한다. 이 값을 기준으로 해서 가상 메모리에서 실행 파일을
                         맵핑할 공간을 예약한다.
                         오프셋은 0x56 ~ 0x59이며, 크기는 4바이트 이다. 위 이미지에서는 "0x00030000" 이라는 값을
                         가지고 있다.

 - SizeOfHeader : DOS Stub, PE 헤더, 섹션 헤더의 합 값을 가지고 있다. 이 값은 무조건 FileAlignment의 배수여야
                          한다. 오프셋은 0x60 ~ 0x63이며, 크기는 4바이트 이다. 위 이미지에서는 "0x00000400" 값을
                          가지고 있다.

 - Checksum : 실행 파일의 체크섬 값을 가지고 있다. 체크섬 알고리즘은 IMAGEHELP.DLL 파일에 있으며 이 값은 모든
                      드라이버와 부팅시 로드된 DLL 파일, 중요한 윈도우 프로세스가 로드한 DLL 파일을 검증 할 때 사용된다.
                      오프셋은 0x64 ~ 0x67이며, 크기는 4바이트 이다. 위 이미지에서는 "0x00039741" 이라는 값을 가지고
                      있다.

 - Subsystem : 실행 파일을 실행하는데 필요한 서브 시스템의 값을 가진다. 오프셋은 0x68 ~ 0x69이며, 크기는
                       2바이트 이다. 위 이미지에서는 "0x0002" 라는 값을 가지고 있다. 목록표에 따르면 Windows GUI
                       서브시스템을 뜻한다. 아래는 Subsystem 값 목록표이다.

[그림 5 - Subsystem 값 목록표]

 - DllCharacteristics : PE 파일이 DLL 파일인 경우 파일의 속성 정보를 의미한다. 오프셋은 0x70 ~ 0x71이며, 크기는
                         2바이트 이다. 위 이미지에서는 "0x8140" 이라는 값을 가지고 있다.

 - SizeOfStackReserve : 예약할 스택의 크기 값을 가지고 있다. 오프셋은 0x72 ~ 0x75이며, 크기는 4바이트 이다.
                                   위 이미지에서는 "0x00040000" 이라는 값을 가지고 있다.

 - SizeOfStackCommit : 커밋할 스택의 크기 값을 가지고 있다. 오프셋은 0x76 ~ 0x79이며, 크기는 4바이트 이다.
                                   위 이미지에서는 "0x00011000"이라는 값을 가지고 있다.

 - SizeOfHeapReserve : 예약할 힙의 크기 값을 가지고 있다. 오프셋은 0x80 ~ 0x83이며, 크기는 4바이트 이다.
                                   위 이미지에서는 "0x00100000" 이라는 값을 가지고 있다. 

 - SizeOfHeapCommit : 커밋할 힙의 크기 값을 가지고 있다. 오프셋은 0x84 ~ 0x87이며, 크기는 4바이트 이다.
                                  위 이미지에서는 "0x00001000" 이라는 값을 가지고 있다.

 - LoaderFlags : 예약된 영역으로 0으로 채워져 있다. 오프셋은 0x88 ~ 0x91이며, 크기는 4바이트 이다.
                        위 이미지에서는 0 값을 가지고 있다. 

 - NumberOfRvaAndSize : Optional Header의 나머지 부분에 있는 데이터 디렉터리 엔트리의 숫자 값을 가지고 있다.
                                      오프셋은 0x92 ~ 0x95이며, 크기는 4바이트 이다. 위 이미지에서는 "0x00000010" 값을
                                      가지고 있다. 



글이 많이 길어진 관계로 나머지 한 부분인 IMAGE_DATA_DIRECTORY 구조체는 다음 글에서 다루도록 하겠다.

'[+] Information > [-] RCE' 카테고리의 다른 글

PE 구조 (6)  (0) 2011.12.31
PE 구조 (5)  (0) 2011.12.31
PE 구조 (3)  (0) 2011.12.30
PE 구조 (2)  (0) 2011.12.29