ii4gsp
윈도우 실행 파일 구조 본문
PE 파일
윈도우 실행 파일을 PE(Portable Executable) 파일이라 부른다.
PE 파일은 다양한 정보를 포함한 커다란 구조체들로 이루어져 있으며,
내부적으로 수많은 테이블과 멤버를 가지고 있다.
종류 | 설명 | ||||||||
EXE | 실행 파일 | ||||||||
SCR | 실행 파일(화면보호기) | ||||||||
DLL | 라이브러리 | ||||||||
OCX | 라이브러리(ActiveX) | ||||||||
SYS | 시스템 드라이버 | ||||||||
OBJ | 오브젝트 파일 |
화면보호기 파일인 SCR이 실행 파일의 종류라는 사실을 모르는 경우가 많아
이러한 점을 악용해서 SCR 파일로 제작된 악성코드가 만들어지기도 한다.
파일의 첫 바이트부터 구조체가 시작된다.
PE 파일의 구조는 파일로 존재할 때와 메모리에 로드된 후에 달라진다.
파일에서는 첫 바이트부터의 거리를 뜻하는 offset을 사용하고,
메모리에서는 가상 주소와 상대적 가상 주소를 사용한다.
메모리에 로드된 후에 사이즈가 조금 커진 것을 볼 수 있는데, 일반적으로 File Alignment 값보다
Section Alignment 값이 더 크기 때문이다.
Alignment란 여러 가지 내부 연산을 처리할때 효율성을 위해 특정 단위로 간격을 맞추는 것을 의미한다.
PE에서 남는 공간은 널바이트로 채워진다.
IMAGE_DOS_HEADER 구조체
typedef struct_IMAGE_DOS_HEADER { // DOS header
WORD e_magic; // Magic number
WORD e_cbip;
WORD e_cp;
WORD e_cric; // Relocations
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; // winNT.h
PEview로 계산기를 열어보면 PE 헤더가 보일 것이다.
하나씩 분석 해보도록 해보겠다.
PE 포맷의 시작 부분에 위치한 64바이트 구조체인 DOS_HEADER와 DOS Stub은 윈도우가 아닌 DOS 운영체제를 위한 것이다.
DOS에서 PE 파일이 실행되는 경우를 위해 만들어진 헤더이다.
e_magic 멤버는 해당 파일이 PE 파일임을 나타내는 첫 두 바이트로, MZ(5A4D)로 고정되어 있다.
파일의 첫 두 바이트가 MZ가 아니라면 로더는 PE로 인식하지 않는다.
제일 밑줄을 보면 e_lfanew멤버가 NT Header가 시작되는 위치의 offset을 나타낸다.
calc.exe는 0xE8 값을 가지고있다.
실제로 0xE8의 위치에는 NT Header가 위치한다.
DOS Stub
대부분의 PE 파일에 존재하지만 없어도 실행에 아무런 지장이 없다.
위의 문자열을 보면 알수있듯이 DOS에서 실행이 불가능하다는 메세지를 출력한다.
IMAGE_NT_HEADERS 구조체
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32
시그니처인 50450000 "PE"00 4바이트를 시작으로 FileHeader와 OptionalHeader를 멤버로 갖는 구조체이다.
IMAGE_FILE_HEADER 구조체
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
WinNT.h에 정의되어있고 20byte 사이즈의 구조체이다.
FileHeader 구조체에서 Machine, NumberOfSections, SizeOfOptionalHeader, Characteristics 4 가지 멤버들이 중요하다.
Machine
Machine은 이 파일의 실행 대상 플랫폼을 나타낸다.
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_AM33 0x01d3
NumberOfSections
파일에 존재하는 섹션의 수를 나타낸다.
SizeOfOptionalHeader
IMAGE_OPTIONAL_HEADER의 구조체 크기를 나타낸다.
Characteristics
파일의 속성을 나타내고 실행 파일인지, DLL인지 등의 정보들이 OR 값으로 표시된다.
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
#define IMAGE_FILE_16BIT_MACHINE 0x0040
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
#define IMAGE_FILE_32BIT_MACHINE 0x0100
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
#define IMAGE_FILE_SYSTEM 0x1000
#define IMAGE_FILE_DLL 0x2000
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
Characteristics 필드를보면 Intel x86용 바이너리임을 알 수 있다.
5개의 섹션을 가지고 있고, Characteristics의 값이 0x102임으로 0x100인 32bit 속성과 0x2인 실행 파일 속성을 가지고있음을 알 수 있다.
IMAGE_OPTIONAL_HEADER 구조체
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
Magic
IMAGE_NT_OPTIONAL_HDR32_MAGIC인지 IMAGE_NT_OPTIONAL_HDR64_MAGIC인지 구분해준다.
32는 0x10b, 64는 0x20b
Address of EntryPoint
파일이 메모리에서 실행되는 시작 지점(Entry Point)를 알려준다.
Section Alignment, File Alignment
각 섹션을 정렬하기 위한 저장 단위이다.
섹션에 크기가 남더라도 널바이트로 채워서 Alignment 값을 맞춰 준다.
각 섹션은 반드시 Alignment의 배수여야 한다.
Subsystem
동작 환경을 정의한 것으로, 이 프로그램이 GUI인지 콘솔인지를 알려준다.
0x1은 시스템 드라이버 파일 *.sys
0x2는 윈도우 기반 프로그램이 해당되는 GUI
0x3은 콘솔 창 기반의 CLI 프로그램
IMAGE_DATA_DIRECTORY 구조체
디렉토리별로 각각의 정보를 담고 있다.
EXPORT Directory
DLL 등의 파일에서 외부에 함수를 공개하기 위한 정보를 가진다.
IMPORT Directory
프로그램 실행을 위해 import하는 DLL 이름과 사용할 함수 정보가 담긴 INT의 주소와 IAT의 주소 같은 정보가 들어있다.
IMAGE_SECTION_HEADER 구조체
섹션은 실제 파일의 내용들이 존재하는 부분으로, 섹션별로 해당 섹션의 정보를 담고 있는 헤더를 가지고 있다.
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
VirtualSize, VirtualAddress
메모리 상에서의 섹션이 차지하는 크기와 섹션의 시작 주소(RVA)이다.
SizeOfRawData, PointerToRawData
파일 상에서의 섹션이 차지하는 크기와 섹션의 시작위치이다.
Characteristics
각 섹션의 특징을 알려준다.
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information.
#define IMAGE_SCN_TYPE_OVER 0x00000400 // Reserved.
#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat.
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable.
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.
bit OR로 이루어진다.
IMAGE_SECTION_HEADER .text
섹션의 크기와 위치 등을 알 수 있으며, .text 섹션에 코드가 포함되어 있으며 읽기 및 실행 권한이 존재한다.
'시스템 해킹 > Technique' 카테고리의 다른 글
SEH Overwrite 기법 (0) | 2020.01.15 |
---|---|
구조적 예외 처리 SEH (Structured Exception Handler) (0) | 2020.01.15 |
쉘코드 모음 (0) | 2020.01.08 |
[2] 버퍼 오버플로우 (Buffer Overflow) 개념 (0) | 2019.11.16 |
[1] 버퍼 오버플로우 (Buffer Overflow) 개념 (0) | 2019.11.16 |