# PE File

### Các thuật ngữ cần lưu ý <a href="#cac-thuat-ngu-can-luu-y" id="cac-thuat-ngu-can-luu-y"></a>

> **VA (Virtual Address)** là địa chỉ ảo khi chương trình được load vào bộ nhớ.\
> Ví dụ như khi 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ơ sở khi chương trình được nạp vào bộ nhớ, được thể hiện trong trường ImageBase của NT additional section.

> **RVA (Relative Virtual Address)** là địa chỉ ảo tương đối của file, giá trị này sẽ đượ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ữ dùng để chỉ vị trí của một trường, hoặc một giá trị nào đó trong raw file (Ví dụ như e\_magic có **file offset** là 0x00), điều này được thể hiện trong các hex editor.\
> Cách tính **file offset**:\
> File\_offset = RVA – (pSect->VirtualAddress + pSect->PointerToRawData)

### Cơ bản về PE file (PORTABLE EXECUTABLE FILE) <a href="#co-ban-ve-pe-file-portable-executable-file" id="co-ban-ve-pe-file-portable-executable-file"></a>

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-8.png?w=278" alt="cấu trúc cơ bản của một PE file"><figcaption></figcaption></figure>

Tất cả các file PE đều được bắt đầu bằng **DOS Header**, chiếm 64 bytes đầu tiên, Vùng được sử dụng trong TH chương trình chạy trên nền DOS, hệ điều hành 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**.

DOS Header là một cấu trúc được định nghĩa trong file windows.inc hoặc winnt.h. Cấu trúc này gồm 19 thành phần.

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-9.png?w=512" alt=""><figcaption></figcaption></figure>

**Trong đó ta quan tâm 2 trường:**

* **e\_magic:** chữ ký của PE file, giá trị 4Dh, 5Ah (ký tự “MZ”, tên nhà sáng lập MS-DOS: Mark Zbikowshy). Giá trị này đánh dấu một DOS Header hợp lệ và được phép thực thi tiếp.
* **e\_lfanew:** là một DWORD nằm ở cuối cùng của DOS Header, là trường chứa offset của PE Header so với vị trí đầu file.

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-10.png?w=781" alt=""><figcaption></figcaption></figure>

**PE Header** thực chất là cấu trúc **IMAGE\_NT\_HEADERS** bao gồm các thông tin cần thiết cho quá trình loader load file lên bộ nhớ. Cấu trúc này gồm 3 phần được định nghĩa trong windows.inc

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-11.png?w=501" alt=""><figcaption></figcaption></figure>

* **Signature**: là 1 DWORD bắt đầu **PE Header** chứa chữ ký PE: 50h, 45h, 00h, 00h
* **FileHeader**: bao gồm 20 bytes tiếp theo của **PE Header**, phần này chứa thông tin về sơ đồ bố trí vật lý và các đặc tính của file. Trong trường này chúng ta cần chú ý tới trường **NumberOfSections** , đây là trường chứa số section của file. Nếu muốn thêm/xoá section trong PE file, ta cần thay đổi tương ứng trường này.

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-12.png?w=437" alt=""><figcaption></figcaption></figure>

* **OptionalHeader**: bao gồm 224 bytes tiếp theo sau **FileHeader**. Cấu trúc này được định nghĩa trong windows.inc, đây là phần chứa thông tin về sơ đồ logic trong PE file. Dưới đây là danh sách các trường trong cấu trúc này, đồng thời sẽ đưa ra một số chỉ dẫn về thông tin của một số trường cần quan tâm khi muốn chỉnh sửa file.

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-14.png?w=533" alt=""><figcaption></figcaption></figure>

* **AddressOfEntryPoint (RVA):** địa chỉ ảo tương đối của câu lệnh đầu tiên sẽ được thực thi. 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.
* **ImageBase**: Địa chỉ được ưu tiên nạp cho PE file.
* **SectionAlignment**: Phần liên kết các section trong bộ nhớ, tức là một section luôn luôn được 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ác section trong file. Tương tự như SectionAlignment nhưng áp dụng với file.
* **SizeOfImage**: Toàn bộ kích thước PE file trong bộ nhớ, là tổng của tất cả các headers và sections được liên kết tới SectionAlignment.
* **SizeOfHeaders**: Kích thước của tất cả headers và section table, bằng 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 gồm 16 cấu trúc **IMAGE\_DATA\_DIRECTORY**, mỗi cấu trúc liên quan tới 1 cấu trúc dữ liệu trong PE file.

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-15.png?w=514" alt=""><figcaption><p>16 cấu trúc <strong>IMAGE_DATA_DIRECTORY</strong> có thể xem được thông qua LordPE</p></figcaption></figure>

#### Section Table <a href="#section-table" id="section-table"></a>

**Section Table** là thành phần ngày sau PE Header, bao gồm một mảng những cấu trúc **IMAGE\_SECTION\_HEADER**, mỗi phần tử chứa thông tin về một section trong PE file. Cấu trúc này được định nghĩa trong file windows.inc như hình dưới đây:

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-16.png?w=692" alt=""><figcaption><p>Cơ bản về cấu trúc PE file – section_table</p></figcaption></figure>

**Thông tin về một số trường quan trọng:**

* **VirtualSize**: Kích thước thật sự của dữ liệu trên section tính theo byte, giá trị này có thể nhỏ hơn kích thước trên ổ đĩa (SizeOfRawData)
* **VirtualAddress**: RVA của section, là giá trị để ánh xạ khi section được load lên bộ nhớ
* **SizeOfRawData**: Kích thước section data trên ổ đĩa
* **PointerToRawData**: là offset từ vị trí đầu file tới section data.
* **Characteristics**: đặc tính của section: thực thi, dữ liệu khởi tạo …

Section chứa các nội dung chính của file, bao gồm code, data, resources, và các thông tin thực thi khác. Mỗi section sẽ 40 bytes và được chia thành hai phần: header, data.

* **Name**: tên section, có thể trống.
* **PhysicalAddress / Virtual Size:** kích thước data thực tế của section (bytes). Nó có thể nhỏ hơn kích thước của section trên disk.
* **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.

Các section thường gặp nhất như:

* .**text section:** chứa mã thực thi, IAT của chương trình. Vì Windows NT sử dụng hệ thống quản lý bộ nhớ ảo dựa trên trang (page), do đó sẽ rất khó quản lý nếu như tách các đoạn mã thành từng phần riêng biệt.
* **.bss section:** chứa các dữ liệu chưa được khởi tạo.
* **.data section:** chứa các dữ liệu đã được khởi tạo (read-only) trên hệ thống.
* **.rsrc section:** chứa các thông tin resource.
* **.edata section:** chứa các export directory của application hoặc DLL.
* **.idata section:** chứa các thông tin về import functions, bao gồm import directory và import address table (IAT).
* **.tls section:** trường này chứa các thông tin về Threat Local Storage (đây là một section rất quan trọng trong phân tích mã độc sẽ được đề cập sau).

#### Export directory section <a href="#export-directory-section" id="export-directory-section"></a>

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.

* **Name**: chứa địa chỉ RVA trỏ đến internal name của module.
* **Base**: Chứa số thứ tự sẽ bắt đầu.
* **NumberOfFunctions**: tổng số function được export bởi module.
* **NumberOfNames**: Số function được export bằng tên.
* **AddressOfFunctions**: chứa địa chỉ ảo (RVA) trỏ đến một mảng RVA của funtion trong module (EAT).
* **AddressOfNames**: chứa địa chỉ RVA trỏ đến một mảng RVA của tên các function trong module (ENT).
* **AddressOfNameOrdinals**: chứa địa chỉ RVA trỏ đến mảng 16 bit chứa thứ tự của các function được đặt tên (EOT).

<figure><img src="https://vietzettt.files.wordpress.com/2022/07/image-17.png?w=880" alt=""><figcaption></figcaption></figure>

#### Import directory <a href="#import-directory" id="import-directory"></a>

Đây là section quan trọng nhất trong quá trình sửa lại PE file, chứa các thông tin về tất cả các funtion được import vào file.

Mỗi cấu trúc của nó là 20 bytes, được mô tả như sau:

* **OriginalFirstThunk**: chứa địa chỉ RVA của Import Lookup Table (ILT) hoặc Import Name Table (INT). ILT chứa thông tin cách mà import sẽ được xử lý bằng Name hoặc Ordinal.
* **Name**: chứa địa chỉ RVA đến tên của module (DLL).
* **FirstThunk**: chứa địa chỉ RVA đến một cấu trúc IMAGE\_THUNK\_DATA, còn được gọi là Import Address Table (IAT).

<figure><img src="https://vietzettt.files.wordpress.com/2023/01/image-3.png?w=1024" alt=""><figcaption></figcaption></figure>

***

### References <a href="#references" id="references"></a>

1. <https://blog.vincss.net/2020/04/re013-cach-dump-pe-file-tu-bo-nho-bang-IDA.html>
2. <https://kid0604.wordpress.com/2020/10/15/phan-tich-ma-doc-day-1-static-analysis-co-ban/>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://viettaliii.gitbook.io/home/education/window-pe-.net/pe-file.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
