ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 0x01.PE header
    0x.리버스 엔지니어링/PE File Format 2017. 8. 4. 12:04

    0x01.PE header




    앞 포스팅에서 설명했지만 DOS header ~ Section header(".rsrc") 까지를 헤더라고 부른다.


    1. DOS header


    마이크로소프트는 언제나 하위호환성을 신경쓰기 때문에 DOS를 고려해서 앞 부분에는 DOS header를 붙이는데 구조체의 크기는 40이다.


    typedef struct _IMAGE_DOS_HEADER{

    WORD    e_magic;

    WORD    e_cblp;

    WORD    e_cp;

    WORD    e_crlc;

    WORD    e_cparhdr;

    WORD    e_minalloc;

    WORD    e_maxalloc;

    WORD    e_ss;

    WORD    e_sp;

    WORD    e_csum;

    WORD    e_ip;

    WORD    e_cs;

    WORD    e_lfarlc;

    WORD    e_ovno;

    WORD    e_res[4];

    WORD    e_oemid;

    WORD    e_oeminfo;

    WORD    e_res2[10]'

    LONG     e_lfanew

    } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;


    헥스 에디터인 Hxd로 메모장(notepad)를 뜯어보면



    이렇게 앞 부분에 4D5A(MZ)라는 부분이 있는데, 이 것이 바로 Dos Signature이다. 구조체의 젤 첫 번째 멤버인 e_magic이 결국 도스 시그니처를 나타내는 것이다. (도스 시그니쳐가 MZ인 이유는 DOS 실행 파일을 고안한 개발자인 마크 주비코브스키의 영문 이니셜이라고 한다.)


    눈 여겨봐야할 다른 멤버는 마지막 멤버인 e-lfanew인데, 위의 헥스 에디터를 보면 000000E8 즉, 마지막 4바이트를 나타낸다. (그림의 E8 00 00 00 부분인데 리틀 엔디언 방식이기 때문). 이 멤버는 NT header의 옵션을 표시하는데, 파일에 따라 크기가 다르다.



    2. DOS stub


    이 헤더는 존재할 수도 있고 안할 수도 있다. 다른 말로하자면, 굳이 없어도 파일은 실행된다.



    위에서 40~4D의 영역은 어셈블리 명령어로 DOS에서만 인식이 된다. 그 뒤에 영문으로 적혀있는 부분이 바로 DOS에서 어셈블리 명령어가 실행될 경우에 표시되는 문구인 것이다.




    3. NT header


    typedef struct _IMAGE_NT_HEADRS{

    DWORD Signature

    IMAGE_FILE_HEADER FileHEader;

    IMAGE_OPTIONAL_HEADER32 OptionalHeader;

    } IMAGE_NT_HEADER32, *PIMAGE_NT_HEADER32;


    NT 헤더는 엄청 큰 구조체인데, 3개의 멤버를 가지고 있다.




    위의 에디터에서 PE의 값을 가진 50450000이 첫 번째 멤버인 DWORD signature이다.


    두 번째 멤버인 IMAGE_FILE_HEADER는 크기가 F8이나 되는데, 멤버는 구조체 형식으로 되어있다.


    typedef struct _IMAGE_FILE_HEADER{

    WORD      Machine;

    WORD      NumberOfSections;

    DWORD    TimeDateStamp;

    DWORD    PointerTSymbolTable;

    DWORD    NumberOfymblos;

    WORD      SizeOfOptionalHeader;

    WORD      Characteristcs;


    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;


    중요한 멤버들을 차례대로 살펴보면, Machine 멤버는 CPU별로 고유의 값을 가지고 있는데, 4C01는 0x014c 즉, INTEL 386을 의미한다.


    NumberOfSections는 섹션의 개수를 나타내는데, 이 개수라는것은 PE파일이 코드, 데이터, 리소스를 나뉘어 저장하는 그 섹션들의 개수를 의미한다. 위의 헥스 에디터의 EE~EF인 5가 이 개수를 의미한다.


    TimeDateStamp는 빌드 시간을 나타내는 값이다. 이는 개발도구에 따라서 차이가 나기 때문에 설명을 생략한다.


    SizeOfOptionalHeader는 NT_HEADERS의 구조체인 IMAGE_OPTIONAL_HEADER32의 구조체의 크기를 나타낸다. C언어 구조체라서 이미 크기가 정해져있지만, 윈도우즈는 이 값을 보고 구조체의 크기를 인식하기 때문에 중요한 멤버이다.



    위의 헥스 에티더의 00E0이 구조체의 크기를 나타낸다.


    마지막으로  Characteristcs는 파일의 속성을 나타내는 값이다. 파일이 실행가능한지 아닌지를 bit OR 형식으로 표현한다.


    NT Header의 마지막 멤버인 IMAGE_OPTIONAL_HEADER32의 구조체이다.


    typedef struct _IMAGE_DATA_DIRECTORY{

    DWORD    VirtualAddress;

    DWORD    size;

    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;



    #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

    WORD        Magic;

    BYTE          MajorLinerVersion;

    BYTE          MinorLinkerVersion;

    DWORD     SizeOfCode;

    DWORD     SizeOfInitializedData;

    DWORD     SizeOfUnitializedData;

    DWORD     AddressOfEntryPoint;

    DWORD     BaseOfCode;

    DWORD     BaseOfData;

    DWORD     ImageBase;

    DWORD     Sectionlignment;

    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       DIICharacteristics;

    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_OPTIONAL_HEADER32의 구조체이면 10B, 64이면 20B의 값을 가진다.


    AddressOfEntryPoint는 엔트리 포인트(EP)의 RVA(Relative Virtual Address) 값을 가지고 있어서 프로그램의 최초 실행코드의 시작주소를 나타낸다.


    ImageBase는 PE 파일이 로딩되는 가상 시작 주소를 나타낸다. 보통 EXE나 DLL 같은 파일들은 User Memory영역인 0~7FFFFFFF범위에서 로딩이 되고 SYS 같은 파일은 Kernel Memory 영역인 80000000~FFFFFFFF 범위에 로딩이 된다.


    SectionAlignment는 메모리에서 섹션의 최소단위를, FileAlignment는 파일에서 섹션의 최소 단위를 나타낸다. 섹션의 크기는 반드시 이 두 멤버의 배수가 되야 한다는 규칙이 있다.


    SizeOfImage는 PE가 메모리에 로딩되면 가상 메모리에서 PE Image가 사용하는 크기를 나타낸다.


    SizeOfHeader는 PE 헤더의 전체 크기를 나타내며, 이 역시 FileAlignment의 배수여야 한다.


    SubSystem의 값을 보고 아래와 같이 구분할 수 있다.


    의미 

    비고 

    Driver File 

    시스템 드라이버 

    GUI 

    그래픽 어플리케이션 

    CUI 

    커널 어플리케이션 


    NumberOfRvaAndSizes는 IMAGE_OPTIONAL_HEADER32 구조체의 마지막 멤버인 DataDirectory 배열의 개수를 나타낸다.


    DataDirecory는 IMAGE_DATA_DIRECTORY의 구조체의 배열로 각 항목은 미리 정의된 값을 가지고 있다.


    DataDirectory[0] = EXPORT Directory

    DataDirectory[1] = IMPORT Directory

    DataDirectory[2] = RESOURCE Directory

    DataDirectory[3] = EXCEPTION Directory

    DataDirectory[4] = SECURITY Directory

    DataDirectory[5] = BASERELOC Directory

    DataDirectory[6] = DEBUG Directory

    DataDirectory[7] = COPYRIGHT Directory

    DataDirectory[8] = GLOBALPTR Directory

    DataDirectory[9] = TLS Directory

    DataDirectory[A] = LOAD_CONFIG Directory

    DataDirectory[B] = BOUND_IMPORT Directory

    DataDirectory[C] = IAT Directory

    DataDirectory[D] = DELAY_IMPORT Directory

    DataDirectory[E] = COM_DESCRIPTOR Directory

    DataDirectory[F] = Reserved Directory


    헥스 에디터로 살펴보면 아래와 같다.


    첫 번째 멤버인 Magic의 값이 0B 01 즉,  10B를 나타내고 그 뒤로 멤버들의 값이 순서대로 저장되어 있다.

    '0x.리버스 엔지니어링 > PE File Format' 카테고리의 다른 글

    0x02.PE header(2)  (0) 2017.08.07
    0x00.PE File Format  (0) 2017.08.03

    댓글

Designed by Tistory.