---
# System prepended metadata

title: File PE
tags: [research]

---

# PE File 
## PE file là gì?
* **PE File Format (Portable Executable File Format)** là định dạng file riêng của Windowns. 
* Tất cả các file có thể thực thi được trên Windowns như: .exe, .dll, .net, ... đều là định dạng PE, ngoại trừ VxDs và DLL (16 bit) 
## Các thuật ngữ cần lưu ý
* **VA (Virtual Address)** là địa chỉ ảo khi chương trình được load vào bộ nhớ.
Ví dụ: lhi ta load file vào IDA thì có thể thấy hàm main() có địa chỉ là 0x401000, đó là địa chỉ **VA**
* **Base Address** là địa chỉ cơ bản khi chương trình được nạp vào bộ nhớ.
* **RVA (Relative Virtual Address)** là địa chỉ ảo tương đối của file, giá trị này được tính toán như sau:
```
RVA = Virtual Address(VA) - Base Address
Ví dụ: RVA = 0x401500 - 0x400000 = 0x1500 --> RVA 
```
* **File offset** là thuật ngữ để chỉ vị trị của một trường, hoặc một giá trị nào đó của raw file ( ví dụ như e_magic có file offset là 0x00 ) nghĩa là vị trí này file chưa chạy vẫn ở trong bộ nhớ vật lý
Cách tính file offset:
```
 File_offset = (RVA - pSect->VirtualAddress) + pSect->PointerToRawData
```
## Phân tích PE File
### Cấu trúc cơ bản:
![portable_executable_32_bit_structure](https://hackmd.io/_uploads/SkwlX1-J0.jpg)
* Gồm 2 phần chính là Header và Section
* Header gồm:
     * DOS MZ Header
     * DOS STUB
     * PE Header
     * Section table
* Section : gồm ít nhất 2 section là code và data
### DOS MZ HEADER
* Bắt đầu với 64 bytes (0x40), DOS MZ header chứa các thông tin cơ bản của một PE file hợp lệ
* Vùng này được dùng trong trương hợp chương trình chạy trên nền DOS, hệ điều hành DOS nhận biết đây là một file thực thi hợp lệ và sẽ thực thi nội dung trong phần DOS STUB.
![image](https://hackmd.io/_uploads/B1x1jyW1C.png)
* Trong phàn DOS Header này chúng ta cần quan tâm đến hai thành phần quan trọng là `e_magic` và `e_lfanew` 
* **e_magic** chứa hai giá trị 4Dh, 5Ah (Ký tự "MZ", tên của người sáng lập MS-DOS: Mark Zbikowsky). Giá trị này đánh dấu một DOS Header hợp lệ và được phép thực thi
* **e_lfanew** là một DWORD nằm ở cuối cùng của DOS Header, và trước nơi bắt đầu của DOS stub.Nó là trường chứa offset  của PE header, Windows Loaders sẽ tìm kiếm offset này vì vậy nó có thể bỏ qua DOS stub và đi đến tới PE file
### DOS Stub
* DOS Stub chỉ là một chương trình DOS EXE nhỏ hiển thị một thông báo lỗi, là phần để tương thích với Windows 16 bít.
![Screenshot 2024-03-27 080747](https://hackmd.io/_uploads/r186WebJA.png)
### PE Header
![image](https://hackmd.io/_uploads/H1n45gby0.png)
PE Header thực chất là cấu trúc **IMAGE_NT_HEADERS** 
![image](https://hackmd.io/_uploads/SyLC5g-kC.png)
**Signature** là DWORD có giá trị: 50h, 45h, 00h, 00h ("PE\0\0")
**File header** là một struct 20 bytes, nó chứa thông tin về sơ đồ bố trí vật lý và những đặc tính của file.
![image](https://hackmd.io/_uploads/rJhrhgWyC.png)
   Trong đó có các thành phần quan trọng cần lưu ý:
   * **Machine** : giá trị xác định PE File này được biên dịch cho dòng máy nào như Intel 386, Intel 64
   * **NumberOfSections** : chứa số section của file. Nếu muốn thêm/xóa trong PE File, ta cần thay đổi trường này.
   * **SizeOfOptionHeader** : kích thước của Optional heaher.
   * **Characteristics** : xác định định dạng PE File(exe,dll,..).

**OptionalHeader** bao gồm 224 bytes tiếp theo sau FILE_HEADER
![image](https://hackmd.io/_uploads/ryCZe--JC.png)
  Trong đó có các thành phần quan trọng cần lưu ý:
* **Magic** : xác định là file 32 bit (0B 01) hay 64 bit (0b 02).
* **AddressOfEntryPoint** : lưu trữ địa chỉ ảo tương đối(RVA) của câu lệnh đầu tiên được thực thi khi chương trình PE loader sẵn sàng để run PE File(.text). Nếu muốn chương trình bắt đầu từ một địa chỉ khác (để thực thi câu lệnh với mục đích khác) thì cần thay đổi địa chỉ này về địa chỉ tương đối của câu lệnh muốn thực thi.
* **SizeOfCode** : kích thước của code thực thi
* **SizeOfInitializedData** : kích thước dữ liệu được khởi tạo.
* **BaseOfCode** : chứa địa chỉ RVA của phần code
* **ImageBase** : Địa chỉ được ưu tiên nạp vào memory chi PE File, mặc định là 0x00400000.
* **SectionAlignment** : phần liên kết các section trong bộ nhớ, có nghĩa là một section luôn luôn bắt đầu bằng bội só của sectionAlignment. Ví dụ: sectionAlignment là 1000h, section đầu tiên bắt đầu ở vị trí 401000h và kích thước là 10h , section tiếp theo sẽ bắt đầu tại địa chỉ 402000h.
* **FileAlignment** : Phần liên kết của các section trong file. Tương tự như sectionAlignmennt nhưng áp dụng với raw file
* **SizeOfImage** : Toàn bộ kích thước của PE image trong bộ nhớ. Nó là tổng tất cả các headers và sections được liên kết tới Section Alignment.
* **SizeOfHeader** : kích thước của tất cả các headers + section table = kích thước file trừ đi tổng kích thước của các section trong file
* **DataDirectory** : là một mảng cấu trúc **IMAGE_DATA_DIRECTORY** gồm 16 phần tử, mỗi phần có liên quan đến một cấu trúc dữ liệu quan trọng trong PE file chẳng hạn như IAT (Import Address Table).
### Section Table
Section Table là thành phần tiếp theo ngay sau PE Header. Nó là một mảng cấu trúc **IMAGE_SECTION_TABLE**, mỗi phần tử chứa thông tin về một section trong PE file.
![image](https://hackmd.io/_uploads/H1VOCZZ10.png)
Thông tin một số trường quan trọng:
* **Name** : tên section, có thể trống.
* **VirtualSize** : kích thước thật sự của dữ liệu trên section tính theo byte, giá trị có thể nhỏ hơn kích thước trên bộ nhớ vật lý (SizeOfRawData).
* **SizeOfRawData** : kích thước data của section trên disk
* **PointerToRawData** : chứa offset tại điểm bắt đầu data của section.
* **Characteristics** : Bao gồm các cờ ví dụ như section này có chứa executable code, initialized data, uninitialized data, có thể được ghi hoặc đọc.

Các section thường gặp nhất:
* **Executable Code Section**: thường được đặt tên **.text** hoặc là **CODE**, thường chứa mã thực thi.
* **Data Sections**
Section **.bss** chứa dữ liệu chưa được khởi tạo.
Sectiion **.data** chứa các dữ liệu đã được khởi tạo (read-only) trên hệ thống.
* **Resource Section**
Section **.rsrc** : chứa các thông tin resource
Section **.edata**: chứa các export directory của application hoặc DLL.
Section **.idata**: chứa các thông tin về import functions, bao gồm import directory và import address table (IAT).
Section **.tls**: trường này chứa các thông tin về Threat Local Storage
### Export Directory section
- Export là các function và giá trị trong một module được khai báo để chia sẻ với các module khác.
- Section này phổ biến trong các tệp DLL. DLL có thể export function trong hai cách: function name hoặc oridinal number.
    - TimeDateStamp: là trường này mô tả thời gian gần nhất mà module được cập nhật hoặc sửa đổi.
    - Name: chứa con trỏ trỏ đến tên của module.
    - Base: chứa base address của module.
    - NumberOfFunctions: là số lượng export function của module.
    - NumberOfNames: chứa số lượng các function có tên trong export function. Giá trị này luôn bé hơn hoặc bằng NumberOfFunctions.
    - AddressOfFunctions: chứa địa chỉ của export address table (EAT). EAT là bảng chứa các RVA của export function. Phải nhớ rằng là số lượng phần tử trong bảng này luôn bằng giá trị của NumberOfFunctions.
    - AddressOfNames: là mảng chứa các RVA của tên hàm. Phải nhớ là số lượng phần tử trong mảng này luôn bằng giá trị của NumberOfNames.
    - AddressOfNamesOrdinals: là mảng chứa index của EAT.
![image](https://hackmd.io/_uploads/r1F8HZ3DR.png)


# Parser PE File

:::spoiler
```cpp=
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>

typedef struct{
    uint16_t e_magic;
    uint16_t e_cblp;
    uint16_t e_cp;
    uint16_t e_crlc;
    uint16_t e_cparhdr;
    uint16_t e_minalloc;
    uint16_t e_maxalloc;
    uint16_t e_ss;
    uint16_t e_sp;
    uint16_t e_csum;
    uint16_t e_ip;
    uint16_t e_cs;
    uint16_t e_lfarlc;
    uint16_t e_ovno;
    uint16_t e_res[4];
    uint16_t e_oemid;
    uint16_t e_oeminfo;
    uint16_t e_res2[10];
    uint32_t e_lfanew;
} IMAGE_DOS_HEADER;

typedef struct {
    uint16_t Machine;
    uint16_t NumberOfSection;
    uint32_t TimeDateStamp;
    uint32_t PointerToSymbols;
    uint32_t NumberOfSymbols;
    uint16_t SizeOfOptionalHeader;
    uint16_t Characteristics;
}IMAGE_FILE_HEADER ;

// optional header 32 bit
typedef struct {
    uint16_t Magic;
    uint8_t MajorLinkerVersion;
    uint8_t MinorLinkerVersion;
    uint32_t SizeOfCode;
    uint32_t SizeOfInitializedData;
    uint32_t SizeOfUninitializedData;
    uint32_t AddressEntryPoint;
    uint32_t BaseOfCode;
    uint32_t BaseOfData;
    uint32_t ImageBase;
    uint32_t SectionAlignment;
    uint32_t FileAlignment;
    uint16_t MajorOperatingSystemVersion;
    uint16_t MinorOperatingSystemVersion;
    uint16_t MajorImageVersion;
    uint16_t MinorImageVersion;
    uint16_t MajorSubsystemVersion;
    uint16_t MinorSubsystemVersion;
    uint32_t Win32VersionValue;
    uint32_t SizeOfImage;
    uint32_t SizeOfHeader;
    uint32_t CheckSum;
    uint16_t Subsystem;
    uint16_t DllCharacteristics;
    uint32_t SizeOfStackReserve;
    uint32_t SizeOfStackCommit;
    uint32_t SizeOfHeapReserve;
    uint32_t SizeOfHeapCommit;
    uint32_t LoaderFlags;
    uint32_t NumberOfRvaAndSize;
    struct {
        uint32_t VirtualAddress;
        uint32_t Size;
    } DataDirectory[16];
} IMAGE_OPTIONAL_HEADER32;

// PE Header Struct 32bit
typedef struct {
    uint32_t Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}IMAGE_NT_HEADERS32;

// optional header 64 bit
typedef struct {
    uint16_t Magic;
    uint8_t MajorLinkerVersion;
    uint8_t MinorLinkerVersion;
    uint32_t SizeOfCode;
    uint32_t SizeOfInitializedData;
    uint32_t SizeOfUninitializedData;
    uint32_t AddressEntryPoint;
    uint32_t BaseOfCode;
    uint32_t ImageBase;
    uint32_t SectionAlignment;
    uint32_t FileAlignment;
    uint16_t MajorOperatingSystemVersion;
    uint16_t MinorOperatingSystemVersion;
    uint16_t MajorImageVersion;
    uint16_t MinorImageVersion;
    uint16_t MajorSubsystemVersion;
    uint16_t MinorSubsystemVersion;
    uint32_t Win32VersionValue;
    uint32_t SizeOfImage;
    uint32_t SizeOfHeader;
    uint32_t CheckSum;
    uint16_t Subsystem;
    uint16_t DllCharacteristics;
    uint32_t SizeOfStackReserve;
    uint32_t SizeOfStackCommit;
    uint32_t SizeOfHeapReserve;
    uint32_t SizeOfHeapCommit;
    uint32_t LoaderFlags;
    uint32_t NumberOfRvaAndSize;
    struct {
        uint32_t VirtualAddress;
        uint32_t Size;
    } DataDirectory[16];
} IMAGE_OPTIONAL_HEADER64;

// PE Header Struct 64 bit
typedef struct {
    uint32_t Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64;

// Section Table
typedef struct {
    uint8_t Name[8];
    union{
        uint32_t PhysicalAddress;
        uint32_t VirtualSize;
    } Misc;
    uint32_t VirtualAddress;
    uint32_t SizeOfRawData;
    uint32_t PointerToRawData;
    uint32_t PointerToRelocations;
    uint32_t PointerToLinenumbers;
    uint16_t NumberOfRelocations;
    uint16_t NumberOfLinenumbers;
    uint32_t Characteristics;
} IMAGE_SECTION_HEADER;

int main(int argc,char* argv[]){
    if (argc != 2) {
        printf("Use: %s <Path file PE>\n", argv[0]);
        return -1;
    }
    FILE *file = fopen(argv[1],"rb");
    if (!file){
        printf("Error Load File");
        return -1;
    }

    // lấy giá trị e_lfanew dể biết PE header bắt đầu ở đâu
    fseek(file, 0x3C, SEEK_SET);
    uint32_t offset;
    fread(&offset, sizeof(offset), 1, file);

    // seek đến magic trong optional Header
    fseek(file, offset + 24, SEEK_SET);
    uint16_t magic;
    fread(&magic, sizeof(magic), 1, file);
    if (magic == 0x10B) {
        printf("This is a PE32 file.\n\n");
    } else if (magic == 0x20B) {
        printf("This is a PE64 file.\n\n");
    } else {
        printf("Wrong :(((");
    }
    fseek(file,0,SEEK_SET);
    IMAGE_DOS_HEADER DosHeader;
    fread(&DosHeader,sizeof(DosHeader),1,file);

    if (DosHeader.e_magic!=0x5A4D){
        printf("This is not PE file\n");
    }
	printf("******* DOS HEADER *******\n");
    printf("\t0x%x\t\tMagic number\n", DosHeader.e_magic);
	printf("\t0x%x\t\tBytes on last page of file\n", DosHeader.e_cblp);
	printf("\t0x%x\t\tPages in file\n", DosHeader.e_cp);
	printf("\t0x%x\t\tRelocations\n", DosHeader.e_crlc);
	printf("\t0x%x\t\tSize of header in paragraphs\n", DosHeader.e_cparhdr);
	printf("\t0x%x\t\tMinimum extra paragraphs needed\n", DosHeader.e_minalloc);
	printf("\t0x%x\t\tMaximum extra paragraphs needed\n", DosHeader.e_maxalloc);
	printf("\t0x%x\t\tInitial (relative) SS value\n", DosHeader.e_ss);
	printf("\t0x%x\t\tInitial SP value\n", DosHeader.e_sp);
	printf("\t0x%x\t\tInitial SP value\n", DosHeader.e_sp);
	printf("\t0x%x\t\tChecksum\n", DosHeader.e_csum);
	printf("\t0x%x\t\tInitial IP value\n", DosHeader.e_ip);
	printf("\t0x%x\t\tInitial (relative) CS value\n", DosHeader.e_cs);
	printf("\t0x%x\t\tFile address of relocation table\n", DosHeader.e_lfarlc);
	printf("\t0x%x\t\tOverlay number\n", DosHeader.e_ovno);
	printf("\t0x%x\t\tOEM identifier (for e_oeminfo)\n", DosHeader.e_oemid);
	printf("\t0x%x\t\tOEM information; e_oemid specific\n", DosHeader.e_oeminfo);
	printf("\t0x%x\t\tFile address of new exe header\n", DosHeader.e_lfanew); 
    
    fseek(file,DosHeader.e_lfanew,SEEK_SET);
    uint16_t NumOfSections;
    if (magic==0x10B){
        IMAGE_NT_HEADERS32 imageNTHeaders;
        fread(&imageNTHeaders,sizeof(IMAGE_NT_HEADERS32),1,file);
        NumOfSections = imageNTHeaders.FileHeader.NumberOfSection;
        printf("\n******* FILE HEADER *******\n");
        printf("\t0x%x\t\tMachine\n", imageNTHeaders.FileHeader.Machine);
        printf("\t0x%x\t\tNumber of Sections\n", imageNTHeaders.FileHeader.NumberOfSection);
        printf("\t0x%x\tTime Stamp\n", imageNTHeaders.FileHeader.TimeDateStamp);
        printf("\t0x%x\t\tPointer to Symbol Table\n", imageNTHeaders.FileHeader.PointerToSymbols);
        printf("\t0x%x\t\tNumber of Symbols\n", imageNTHeaders.FileHeader.NumberOfSymbols);
        printf("\t0x%x\t\tSize of Optional Header\n", imageNTHeaders.FileHeader.SizeOfOptionalHeader);
        printf("\t0x%x\t\tCharacteristics\n", imageNTHeaders.FileHeader.Characteristics);

            // OPTIONAL_HEADER
        printf("\n******* OPTIONAL HEADER *******\n");
        printf("\t0x%x\t\tMagic\n", imageNTHeaders.OptionalHeader.Magic);
        printf("\t0x%x\t\tMajor Linker Version\n", imageNTHeaders.OptionalHeader.MajorLinkerVersion);
        printf("\t0x%x\t\tMinor Linker Version\n", imageNTHeaders.OptionalHeader.MinorLinkerVersion);
        printf("\t0x%x\t\tSize Of Code\n", imageNTHeaders.OptionalHeader.SizeOfCode);
        printf("\t0x%x\t\tSize Of Initialized Data\n", imageNTHeaders.OptionalHeader.SizeOfInitializedData);
        printf("\t0x%x\t\tSize Of UnInitialized Data\n", imageNTHeaders.OptionalHeader.SizeOfUninitializedData);
        printf("\t0x%x\t\tAddress Of Entry Point (.text)\n", imageNTHeaders.OptionalHeader.AddressEntryPoint);
        printf("\t0x%x\t\tBase Of Code\n", imageNTHeaders.OptionalHeader.BaseOfCode);
        printf("\t0x%x\t\tBase Of Data\n", imageNTHeaders.OptionalHeader.BaseOfData);
        printf("\t0x%x\t\tImage Base\n", imageNTHeaders.OptionalHeader.ImageBase);
        printf("\t0x%x\t\tSection Alignment\n", imageNTHeaders.OptionalHeader.SectionAlignment);
        printf("\t0x%x\t\tFile Alignment\n", imageNTHeaders.OptionalHeader.FileAlignment);
        printf("\t0x%x\t\tMajor Operating System Version\n", imageNTHeaders.OptionalHeader.MajorOperatingSystemVersion);
        printf("\t0x%x\t\tMinor Operating System Version\n", imageNTHeaders.OptionalHeader.MinorOperatingSystemVersion);
        printf("\t0x%x\t\tMajor Image Version\n", imageNTHeaders.OptionalHeader.MajorImageVersion);
        printf("\t0x%x\t\tMinor Image Version\n", imageNTHeaders.OptionalHeader.MinorImageVersion);
        printf("\t0x%x\t\tMajor Subsystem Version\n", imageNTHeaders.OptionalHeader.MajorSubsystemVersion);
        printf("\t0x%x\t\tMinor Subsystem Version\n", imageNTHeaders.OptionalHeader.MinorSubsystemVersion);
        printf("\t0x%x\t\tWin32 Version Value\n", imageNTHeaders.OptionalHeader.Win32VersionValue);
        printf("\t0x%x\t\tSize Of Image\n", imageNTHeaders.OptionalHeader.SizeOfImage);
        printf("\t0x%x\t\tSize Of Headers\n", imageNTHeaders.OptionalHeader.SizeOfHeader);
        printf("\t0x%x\t\tCheckSum\n", imageNTHeaders.OptionalHeader.CheckSum);
        printf("\t0x%x\t\tSubsystem\n", imageNTHeaders.OptionalHeader.Subsystem);
        printf("\t0x%x\t\tDllCharacteristics\n", imageNTHeaders.OptionalHeader.DllCharacteristics);
        printf("\t0x%x\t\tSize Of Stack Reserve\n", imageNTHeaders.OptionalHeader.SizeOfStackReserve);
        printf("\t0x%x\t\tSize Of Stack Commit\n", imageNTHeaders.OptionalHeader.SizeOfStackCommit);
        printf("\t0x%x\t\tSize Of Heap Reserve\n", imageNTHeaders.OptionalHeader.SizeOfHeapReserve);
        printf("\t0x%x\t\tSize Of Heap Commit\n", imageNTHeaders.OptionalHeader.SizeOfHeapCommit);
        printf("\t0x%x\t\tLoader Flags\n", imageNTHeaders.OptionalHeader.LoaderFlags);
        printf("\t0x%x\t\tNumber Of Rva And Sizes\n", imageNTHeaders.OptionalHeader.NumberOfRvaAndSize);
        // DATA_DIRECTORIES
        printf("\n******* DATA DIRECTORIES *******\n");
        for (int i=0;i<16;i++){
            	printf("\tExport Directory Address: 0x%x; Size: 0x%x\n", imageNTHeaders.OptionalHeader.DataDirectory[i].VirtualAddress, imageNTHeaders.OptionalHeader.DataDirectory[i].Size);
        }
        //    fseek(file,DosHeader.e_lfanew+sizeof(IMAGE_NT_HEADERS32),SEEK_SET);
    }
    else{
        IMAGE_NT_HEADERS64 imageNTHeaders;
        fread(&imageNTHeaders,sizeof(IMAGE_NT_HEADERS64),1,file);
        NumOfSections = imageNTHeaders.FileHeader.NumberOfSection;
        printf("\n******* FILE HEADER *******\n");
        printf("\t0x%x\t\tMachine\n", imageNTHeaders.FileHeader.Machine);
        printf("\t0x%x\t\tNumber of Sections\n", imageNTHeaders.FileHeader.NumberOfSection);
        printf("\t0x%x\tTime Stamp\n", imageNTHeaders.FileHeader.TimeDateStamp);
        printf("\t0x%x\t\tPointer to Symbol Table\n", imageNTHeaders.FileHeader.PointerToSymbols);
        printf("\t0x%x\t\tNumber of Symbols\n", imageNTHeaders.FileHeader.NumberOfSymbols);
        printf("\t0x%x\t\tSize of Optional Header\n", imageNTHeaders.FileHeader.SizeOfOptionalHeader);
        printf("\t0x%x\t\tCharacteristics\n", imageNTHeaders.FileHeader.Characteristics);

            // OPTIONAL_HEADER
        printf("\n******* OPTIONAL HEADER *******\n");
        printf("\t0x%x\t\tMagic\n", imageNTHeaders.OptionalHeader.Magic);
        printf("\t0x%x\t\tMajor Linker Version\n", imageNTHeaders.OptionalHeader.MajorLinkerVersion);
        printf("\t0x%x\t\tMinor Linker Version\n", imageNTHeaders.OptionalHeader.MinorLinkerVersion);
        printf("\t0x%x\t\tSize Of Code\n", imageNTHeaders.OptionalHeader.SizeOfCode);
        printf("\t0x%x\t\tSize Of Initialized Data\n", imageNTHeaders.OptionalHeader.SizeOfInitializedData);
        printf("\t0x%x\t\tSize Of UnInitialized Data\n", imageNTHeaders.OptionalHeader.SizeOfUninitializedData);
        printf("\t0x%x\t\tAddress Of Entry Point (.text)\n", imageNTHeaders.OptionalHeader.AddressEntryPoint);
        printf("\t0x%x\t\tBase Of Code\n", imageNTHeaders.OptionalHeader.BaseOfCode);
        //printf("\t0x%x\t\tBase Of Data\n", imageNTHeaders.OptionalHeader.BaseOfData);
        printf("\t0x%x\t\tImage Base\n", imageNTHeaders.OptionalHeader.ImageBase);
        printf("\t0x%x\t\tSection Alignment\n", imageNTHeaders.OptionalHeader.SectionAlignment);
        printf("\t0x%x\t\tFile Alignment\n", imageNTHeaders.OptionalHeader.FileAlignment);
        printf("\t0x%x\t\tMajor Operating System Version\n", imageNTHeaders.OptionalHeader.MajorOperatingSystemVersion);
        printf("\t0x%x\t\tMinor Operating System Version\n", imageNTHeaders.OptionalHeader.MinorOperatingSystemVersion);
        printf("\t0x%x\t\tMajor Image Version\n", imageNTHeaders.OptionalHeader.MajorImageVersion);
        printf("\t0x%x\t\tMinor Image Version\n", imageNTHeaders.OptionalHeader.MinorImageVersion);
        printf("\t0x%x\t\tMajor Subsystem Version\n", imageNTHeaders.OptionalHeader.MajorSubsystemVersion);
        printf("\t0x%x\t\tMinor Subsystem Version\n", imageNTHeaders.OptionalHeader.MinorSubsystemVersion);
        printf("\t0x%x\t\tWin32 Version Value\n", imageNTHeaders.OptionalHeader.Win32VersionValue);
        printf("\t0x%x\t\tSize Of Image\n", imageNTHeaders.OptionalHeader.SizeOfImage);
        printf("\t0x%x\t\tSize Of Headers\n", imageNTHeaders.OptionalHeader.SizeOfHeader);
        printf("\t0x%x\t\tCheckSum\n", imageNTHeaders.OptionalHeader.CheckSum);
        printf("\t0x%x\t\tSubsystem\n", imageNTHeaders.OptionalHeader.Subsystem);
        printf("\t0x%x\t\tDllCharacteristics\n", imageNTHeaders.OptionalHeader.DllCharacteristics);
        printf("\t0x%x\t\tSize Of Stack Reserve\n", imageNTHeaders.OptionalHeader.SizeOfStackReserve);
        printf("\t0x%x\t\tSize Of Stack Commit\n", imageNTHeaders.OptionalHeader.SizeOfStackCommit);
        printf("\t0x%x\t\tSize Of Heap Reserve\n", imageNTHeaders.OptionalHeader.SizeOfHeapReserve);
        printf("\t0x%x\t\tSize Of Heap Commit\n", imageNTHeaders.OptionalHeader.SizeOfHeapCommit);
        printf("\t0x%x\t\tLoader Flags\n", imageNTHeaders.OptionalHeader.LoaderFlags);
        printf("\t0x%x\t\tNumber Of Rva And Sizes\n", imageNTHeaders.OptionalHeader.NumberOfRvaAndSize);
        // DATA_DIRECTORIES
        printf("\n******* DATA DIRECTORIES *******\n");
        for (int i=0;i<16;i++){
            	printf("\tExport Directory Address: 0x%x; Size: 0x%x\n", imageNTHeaders.OptionalHeader.DataDirectory[i].VirtualAddress, imageNTHeaders.OptionalHeader.DataDirectory[i].Size);
        }
        // fseek(file,DosHeader.e_lfanew+sizeof(IMAGE_NT_HEADERS64),SEEK_SET);
    }

    // SECTION_HEADERS
	printf("\n******* SECTION HEADERS *******\n");
    IMAGE_SECTION_HEADER sectionHeader;
    for (int i = 0; i < NumOfSections; i++){
        fread(&sectionHeader, sizeof(sectionHeader), 1, file);
        printf("\t%s\n", sectionHeader.Name);
		printf("\t\t0x%x\t\tVirtual Size\n", sectionHeader.Misc.VirtualSize);
		printf("\t\t0x%x\t\tVirtual Address\n", sectionHeader.VirtualAddress);
		printf("\t\t0x%x\t\tSize Of Raw Data\n", sectionHeader.SizeOfRawData);
		printf("\t\t0x%x\t\tPointer To Raw Data\n", sectionHeader.PointerToRawData);
		printf("\t\t0x%x\t\tPointer To Relocations\n", sectionHeader.PointerToRelocations);
		printf("\t\t0x%x\t\tPointer To Line Numbers\n", sectionHeader.PointerToLinenumbers);
		printf("\t\t0x%x\t\tNumber Of Relocations\n", sectionHeader.NumberOfRelocations);
		printf("\t\t0x%x\t\tNumber Of Line Numbers\n", sectionHeader.NumberOfLinenumbers);
		printf("\t\t0x%x\tCharacteristics\n", sectionHeader.Characteristics);
    }
    fclose(file);
    return 0;
}
```
:::