# Chapter 1: Windows Foundational Concepts

## 1.1 User mode và Kernel mode

Kiến trúc windows gồm 2 chế độ: user và kernel là các thành phần của HĐH. Một chế độ là một ngữ cảnh trong đó mã chạy trên hệ thống.

User mode là những gì hầu hết mọi người nghĩ đến khi sử dụng máy tính, nó bao gồm các chương trình hằng ngày, chẳng hạn như MS Office và trình duyệt web.

Ngược lại, Kernel mode được dành riêng cho các chức năng cốt lỗi của HĐH: những chức năng chịu trách nhiệm cho các tác vụ quan trọng, cấp thấp như *quản lý bộ nhớ* và *tương tác phần cứng*.

* Mã chạy ở User mode không thể truy cập hoặc can thiệp vào mã chạy ở kernel mode. Đây là cơ chế bảo vệ có chủ ý để ngăn chặn các ứng dụng được cấu hình sai hoặc độc hại làm thay đổi HĐH.
* Sự phân tách này là rất quan trọng vì tất cả mã và chương trình chạy ở kernel mode đều chia sẻ cùng một không gian địa chỉ bộ nhớ, có nghĩa là một chương trình hoạt động sai có thể gây ra sự cố không mong muốn cho toàn bộ HĐH. Điều này có nghĩa là nếu một chương trình độc hại có thể thực thi mã ở kernel mode, nó có thể ảnh hưởng trực tiếp đến HĐH.

<figure><img src="/files/ORmJrXXq1UE4q8h4P0E8" alt=""><figcaption></figcaption></figure>

* Applications: đây là phần mềm và các chương trình mà người dùng chạy.
* Windows application programming interface (WinAPI) là những gì các ứng dụng dựa vào để hoạt động.&#x20;
* Drivers: chúng điều khiển các thiết bị khác nhau trên hệ thống và cung cấp một lớp trừu tượng giữa các thiết bị và các chương trình muốn tương tác với chúng. Có 2 loại drivers. Hardware device drivers diễn giải các yêu cầu đầu vào/đầu ra (IO) và chuyển đổi chúng thành các yêu cầu IO phần cứng, chẳng hạn như cho chuột và bàn phím. Nonhardware device drivers điều khiển các thành phần hệ thống như giao diện mạng và hệ thống tệp. Một số drivers hoạt động ở user mode và một số hoạt động ở kernel mode.
* Hardware abstraction layer: nó cung cấp một giao diện mà các drivers thiết bị có thể sử dụng để giao tiếp với phần cứng hệ thống cơ bản. Nó cho phép kernel và các ứng dụng cấp cao hơn hoạt động độc lập với phần cứng hệ thống.

## 1.2 Processes và Threads

Khi một ứng dụng như Excel.exe hoặc Calculator.exe được chạy, Trình tải thực thi di động Windows (Windows Portable Executable loader) tạo một process cho chương trình đó; process chứa mã gốc có thể thực thi và tất cả các thư viện và mã hỗ trợ. Mỗi process được gán không gian địa chỉ bộ nhớ ảo riêng của nó, là riêng tư và được cách ly với process đó. Điều này có nghĩa là nếu một process gặp sự cố, nó sẽ không ảnh hưởng đến các process khác hoặc HĐH.

Mỗi process đang chạy có thể có một hoặc nhiều thread (luồng). Bộ xử lý có thể chạy một luồng tại bất kỳ thời điểm nào. Điều này có nghĩa là nếu Process B muốn thực thi một số mã, nó phải đợi luồng hiện tại của Process A hoàn thành. Nếu Windows cho rằng Process B quan trọng hơn, nó có thể đưa ra lệnh ngắt đến luồng hiện tại của Process A và thực thi luồng của Process B thay thế. Đó gọi là chuyển đổi ngữ xảnh.. Windows thực thi chuyển đổi ngữ cảnh nhanh chóng và hiệu quả đến mức người dùng cuối thậm chí không nhận ra rằng nó liên tục xảy ra.

## 1.3 Objects và Handles

Các Process và Thread tương tác với các đối tượng, là các thể hiển của một loại tài nguyên nhất định, chẳng hạn như một tệp, một quy trình khác hoặc một luồng, token bảo mật (đối với quyền truy cập của người dùng), hoặc thậm chí một phần của bộ nhớ. Trình quản lý đối tượng tập trung chịu trách nhiệm theo dõi tất cả các đối tượng Windows, chia sẻ chúng giữa các process và bảo vệ chúng khỏi truy cập trái phép.

Tất cả các đối tượng trong windows đều là cấu trúc dữ liệu đơn giản, thường được lưu trữ trong bộ nhớ kernel. Hầu hết các ứng dụng trên windows chạy trong không gian người dùng, một process sử dụng một mã định danh duy nhất được gọi là handle để truuy cập một đối tượng. Mỗi process có thể có nhiều handles cho các đối tượng khác nhau. Handles được quản lý trong bảng handle của quy trình, chứa các con trỏ đến các đối tượng trong bộ nhớ kernel, như minh họa hình dưới đây:

<figure><img src="/files/dbdCKjgMoNjXCS8L3KQm" alt=""><figcaption></figcaption></figure>

Mutual exclusions hoặc mutexes (loại trừ lẫn nhau) là một phương pháp kiểm soát quyền truy cập vào các đối tượng để ngăn chặn các sự cố tiềm ẩn như các điều kiện tranh chấp. Một điều kiện tranh chấp xảy ra khi cả Process A và Process B đều cố gắng truy cập và sửa đổi một tệp chính xác cùng một lúc, khiến cho dữ liệu có thể bị trộn lẫn, ghi đè lên nhau và gây hỏng file.

Race condition: xảy ra khi 2 hoặc nhiều tiến trình cố gắng truy cập và sửa đổi cùng một đối tượng (ví dụ: tệp) cùng một lúc. Điều này dẫn đến kết quả khoogn mong muốn, dữ liệu không nhất quán, hoặc thậm chí gây sập tiến trình hoặc hệ điều hành.

Giải pháp (Mutex): để tránh race condition, Process A có thể tạo đối tượng mutex cho file đó. Việc này giống như khóa file lại chỉ cho Process A sử dụng. Khi file bị khóa, Process B sẽ không thể truy cập hoặc ghi vào file cho đến khi Process A mở khóa (unlock) nó.

Các chương trình tương tác với mutexes và hệ điều hành thông qua Windows API. Vì Windows API cung cấp các hàm và thủ tục để tạo, khóa, mở khóa mutexes, và quản lý quyền truy cập vào tài nguyên.

## 1.4 Windows API

Windows API là một thư viện mã dùng chung được cung cấp cho các ứng dụng user mode.

Khi một chương trình chạy, WinAPI gọi các hàm Windows cho phép chương trình hoạt động như dự định trong HĐH Windows.

WinAPI bao trùm hầu hết tất cả các chức năng mà một nhà phát triển có thể muốn triển khai mã của họ: từ mọi thứ như giao diện người dùng và khả năng mang đến các khả năng đầu vào/đầu ra (IO) và quản lý bộ nhớ. Ví dụ, nếu một nhà phát triển muốn tạo một cửa sổ cho ứng dụng của mình, họ có thể gọi hàm `CreateWindowEx.` Nếu một chương trình cần truy cập vào một đĩa cứng, nó có thể gọi `GetLogicalDrives` để lấy danh sách các đĩa cứng khả dụng.

Cũng có một API cấp thấp hơn được gọi là Windows Native API, hoặc đơn giảm Native API. Trong khi WinAPI được tài liệu hóa đầy đủ và được thiết kế để các nhà phát triển sử dụng, Native API thì phần lớn không được tài liệu hóa, ít nhát là bởi Microsoft.

> **Lưu ý:** May mắn thay, cộng đồng kỹ thuật đảo ngược đã nỗ lực rất nhiều để tài liệu hóa Native API. Hai ví dụ tốt về điều này là dự án “*internals*” ([link](https://undocumented.ntinternals.net)) và nghiên cứu của Geoff Chappell ([link](https://www.geoffchappell.com/studies/windows/win32/ntdll/api/native.htm)).

Native API được thiết kế là API nội bộ của HĐH, nhưng các chương trình có thể gọi các hàm Native API trực tiếp nếu họ chọn. Ngược lại, các hàm Native API có thể gọi vào các hàm API cấp thấp hơn nữa được lưu trữ trong file `ntoskrnl.exe` vốn là lõi của HĐH.

Việc gọi vào kernel (tức là gọi một hàm trong kernel API) được gọi là `syscall` hoặc `sysenter`. Mặc dù có một vài khác biệt nhỏ về mặt kỹ thuật giữa 2 thuật ngữ này, nhưng mục tiêu của chúng là giống nhau: cho phép các ứng dụng đang chạy ở chế độ người dùng truy cập vào các dịch vụ do kernel cung cấp (ví dụ: quản lý bộ nhớ, quản lý tiến trình, truy cập phần cứng.)

<figure><img src="/files/qhxtrbnY0AtkjsB8h1o6" alt=""><figcaption></figcaption></figure>

Như trên hình, ta có thể thấy một chương trình gọi hàm `VirtualAlloc` của WinAPI, hàm này đến lượt nó lại gọi hàm `VirtualAllocEx` của WindAPI (không hiển thị trong sơ đồ trên). Tiếp theo là một lệnh gọi đến hàm `NtAllocateVirtualMemory` của NativeAPI. Cuối cùng, chương trình kích hoạt hàm NtAllocateVirtualMemory bên trong `ntoskrnl.exe`. Chuỗi lệnh gọi API phức tạp này rất phổ biến trong Windows và cho phép code được phát triển mà không cần nhà phát triển phải hiểu hết tất cả các chi tiết bên trong của Windows và các API cấp thấp hơn.

Như bạn có thể đã nhận thấy, các hàm WinAPI thường có một hoặc nhiều hậu tố, chẳng hạn như `Ex`, `A`, hoặc `W`. Nói chung, hậu tố `Ex` là cách Microsoft chỉ định một phiên bản mới hơn, mở rộng (với nhiều tính năng hơn) của một hàm cũ hơn. Ví dụ hàm `CreateWindowExA` là phiên bản mới hơn, mở rộng hơn của hàm `CreateWindowA`. Hậu tố `A` chỉ ra rằng hàm sử dụng các đầu vào và đầu ra định dạng ANSI, trong khi các hàm có hậu tố `W` sử dụng các đầu vào và đầu ra Unicode.

Các hàm Window Native API thường cso tiền tố `Nt` hoặc `Zw`; ví dụ bao gồm `NtCreateProcess` và `ZwNotifyChangeKey`. Mỗi hàm trong API thường có cả phiên bản `Nt` và `Zw`. Các hàm `Zw` thường được sử dụng bởi drivers và phần mềm cấp thấp khác nhưng phần lớn có thể hoán đổi cho nhau với các hàm `Nt`.

Bạn cũng có thể nhận thấy các tên tệp kernel32.dll và ntdll.dll như hình trên. Chúng đề cập đến các thư viện liên kết động (DLL), một tập hợp các tài nguyên mà các nhà phát triển có thể nhập vào chương trình của họ để sử dụng mã hiện có từ Microsoft hoặc các nhà phát triển bên thứ ba. Mặc dù các chương trình Windows có thể nhập các thư viện này, nhưng các tệp DLL tự xuất các hàm cho chương trình đã nhập chúng. Ví dụ: nếu một nhà phát triển muốn truy cập ổ cứng trên hệ thống Windows, họ có thể nhập thư viện `kernel32.dll`, thư viện này xuất (cung cấp) hàm `GetLogicalDrives` mà họ cần.

Một số DLL thường được sử dụng tròng các chương trình Windows như sau:

* **`kernel32.dll`**: đây là một trong những DLL chính cần thiết để các chương trình Windows chạy và nó chứa nhiều hàm chế độ người dùng cơ bản.
* **`user32.dll`**: DLL này cung cấp các hàm giao diện người dùng đồ họa (GUI) cần thiết cho các chương trình Windows.
* **`Winhttp.dll`**: còn được gọi là giao diện HTTP của Windows, DLL này cung cấp các chức năng kết nối internet cho các chương trình Windows.
* **`ntdll.dll`**: DLL quan trọng này chứa các hàm để đồ bộ hóa, tạo luồng và các tác vụ hệ thống khác; nó cũng giao tiếp với kernel.

## 1.5 Process Internals

Các Process là các cấu trúc dữ liệu phức tạp trỏ đến các cấu trúc dữ liệu bổ sung. Mạng lưới này cung cấp thông tin cơ bản mà Windows dựa vào để quản lý và điều phối hiệu quả nhiều process đang chạy trên một hệ thống tại bất kỳ thời điểm nào.

### 1.5.1 EPROCESS structures

Mặc dù hầu hết các tiến trình hiển thị cho người dùng cuối chạy ở chế độ người dùng, chúng được biểu diễn trong không gian địa chỉ kernel như các đối tượng được gọi là cấu trúc EPROCESS. Mỗi tiến trình có cấu trúc EPROCESS riêng chứa các con trỏ đến các phần tử như danh sách các handle mà process đã mở, cũng như PEB (Process Environment Block - khối môi trường tiến trình) của nó, đây là một cấu trúc chứa thông tin quan trọng về tiến trình. Cấu trúc EPROCESS bao gồm một danh sách liên kết đôi; nghĩa là, chúng tạo thành một chuỗi trong đó mỗi cấu trúc liên kết đến các cấu trúc liên kết trước và sau. Các thành viên cấu trúc EPROCESS được gọi là *forward links (flinks)* là các con trỏ đến cấu trúc EPROCESS tiếp theo trong chuỗi, trong khi *backward links (blinks)* trỏ đến cấu trúc trước đó. Dưới là hình minh họa một phiên bản đơn giản hóa của chuỗi này.

<figure><img src="/files/ehRblpz0vhsPBdWoWn2S" alt=""><figcaption></figcaption></figure>

Cấu trúc EPROCESS chứa nhiều thành phần dữ liệu và con trỏ khác. Điểm quan trọng cần ghi nhớ ở đây là **mỗi tiến trình chế độ người dùng trong Windows được liên kết với một cấu trúc EPROCESS chạy ở chế độ kernel**.

### 1.5.2 Process Environment Blocks (PEB)

Cấu trúc bộ nhớ PEB chứa thông tin về một tiến trình đang chạy mà kernel cần để giao tiếp với tiến trình đó, cũng như thông tin để giao tiếp giữa các tiến trình. Mỗi tiến trình đang chạy có PEB riêng được lưu trữ trong không gian địa chỉ chế độ người dùng bên trong bộ nhớ tiến trình đó. Bảng sau đây liệt kê một số dữ liệu quan trọng mà cấu trúc PEB chứa. Offset của mỗi thành viên cấu trúc được hiển thị cho cả kiến trúc x86 và x64.

<table><thead><tr><th width="110.19998168945312">Offset (x86)</th><th width="109">Offset (x64)</th><th>Dữ liệu</th></tr></thead><tbody><tr><td>0x002</td><td>0x002</td><td>Lưu trữ giá trị <code>BeingDebugged</code>, giá trị này cho biết liệu tiến trình có đang chạy trong ngữ cảnh của trình gỡ lỗi hay không.</td></tr><tr><td>0x008</td><td>0x10</td><td>Lưu trữ địa chỉ cơ sở của tệp thực thi của tiến trình trong bộ nhớ.</td></tr><tr><td>0x00C</td><td>0x18</td><td>Lưu trữ thông tin về các module và thư viện mà tiến trình đã tải.</td></tr><tr><td>0x018</td><td>0x30</td><td>Lưu trữ thông tin về vùng nhớ heap của tiến trình.</td></tr><tr><td>0x064</td><td>0xB8</td><td>Lưu trữ giá trị <code>NumberOfProcessors</code>, giá trị này cho biết số lượng bộ xử lý mà hệ thống có.</td></tr></tbody></table>

Bạn không cần phải nhớ tất cả các thành phần của PEB, nhưng điều quan trọng là phải có hiểu biết cơ bản về nó.

### 1.5.3 Thread Environment Blocks (TEB)

TEB đôi khi được gọi là TIB (Thread Informaation Block) chứa thông tin cho các luồng đang chạy của một tiến trình. Tương tự như PEB, nó chỉ đơn giản là một cấu trúc dữ liệu thông tin quan trọng cho mỗi luồng và được lưu trữ trong không gian địa chỉ bộ nhớ của tiến trình sở hữu luồng đó. Bảng sau liệt kê một số thành phần thú vị trong TEB:

<table><thead><tr><th width="115">Offset (x86)</th><th width="118.79998779296875">Offset (x64)</th><th>Dữ liệu</th></tr></thead><tbody><tr><td>FS:[0x00]</td><td>GS:[0x00]</td><td>Lưu trữ khung trình xử lý ngoại lệ có cấu trúc (SEH) hiện tại.</td></tr><tr><td>FS:[0x04]</td><td>GS:[0x08]</td><td>Trỏ đến cơ sở của stack luồng.</td></tr><tr><td>FS:[0x18]</td><td>GS:[0x30]</td><td>Trỏ đến chính TEB.</td></tr><tr><td>FS:[0x20]</td><td>GS:[0x40]</td><td>Lưu trữ ID tiến trình (PID) của tiến trình sở hữu luồng.</td></tr><tr><td>FS:[0x24]</td><td>GS:[0x48]</td><td>Lưu trữ ID luồng (TID) của luồng hiện tại.</td></tr><tr><td>FS:[0x30]</td><td>GS:[0x60]</td><td>Trỏ đến PEB của tiến trình sở hữu luồng.</td></tr><tr><td>FS:[0xE10]</td><td>GS:[0x1480]</td><td>Trỏ đến thông tin lưu trữ cục bộ luồng (TLS).</td></tr></tbody></table>

> Thread-local storage (TLS) được sử dụng để lưu trữ các biến và thông tin khác trên các luồng khác nhau. Các phần mềm độc hại có thể lạm dụng TLS để bí mật thực thi mã độc.

### 1.5.4 Stacks và Heaps

Một tiến trình có thể có nhiều luồng hoạt động, mỗi luồng có bộ nhớ stack riêng. Stack là nơi luông lưu trữ dữ liệu tạm thời như biến, con trỏ và các đối tượng khác mà chắc chắn sẽ bị phá hủy khi luồng hoàn thành thực thi và bị kết thúc. Vì stack rất dễ bay hơi và tạm thời, các chương trình đôi khi cần một giải pháp "vĩnh viễn" hơn để lưu trữ dữ liệu. Đây là nơi Heaps phát huy tác dụng.

Heap là một vùng bộ nhớ có kích thước thay đổi mà một chương trình cấp phát động trong thời gian chạy. Heaps thường được sử dụng để lưu trữ các đối tượng và cấu trúc dữ liệu quá lớn đối với stack. Chúng cũng được sử dụng để lưu trữ các biến và dữ liệu toàn cục tồn tại và có thể được sử dụng bởi nhiều hàm trong cùng một chương trình. Điều quan trọng cần lưu ý là trong khi stack phần lớn được quản lý bởi hệ điều hành, thì heaps được quản lý bởi chính chương trình. Nếu một chương trình không triển khai tốt các kỹ thuật quản lý bộ nhớ heap, nó có thể gây ra các vấn đề về tính ổn định.

### 1.5.5 Virtual Memory

Mỗi tiến trình chạy trong Windows có một số vùng bộ nhớ ảo được gán cho nó và được ánh xạ tới bộ nhớ vật lý (hoặc RAM). Điều quan trọng là phải hiểu sự khác biệt giữa bộ nhớ ảo và bộ nhớ vật lý. Bộ nhớ vật lý là bộ nhớ phần cứng hữu hình, thực tế được cài đặt trong hệ thống của bạn. Nếu có một máy tính có 8GB RAM, thì bạn có 8GB bộ nhớ vật lý mà tất cả các tiến trình đang chạy trên hệ thống của bạn chia sẻ. Điều này gây ra một vấn đề là bất kỳ tiến trình nào cũng có thể can thệp vào bất kỳ tiến trình nào khác trên hệ thống (một cách vô tình, chẳng hạn như trong trường hợp sự cố hoặc một cách có chủ ý), với các tác dụng phụ không mong muốn. Đây là nơi bộ nhớ ảo phát huy tác dụng.

Bộ nhớ ảo là một loại rào cản giữa bộ nhớ vật lý và không gian địa chỉ bộ nhớ tiến trình. Khi một tiến trình được khởi động, nó được gán một phần bộ nhớ ảo được ánh xạ tới bộ nhớ vật lý thông qua *page table (bảng trang)* Page table theo dõi vị trí vật lý của các phân đoạn bộ nhớ ảo khác nhau trong RAM. Hình sau đây minh họa mối quan hệ giữa bộ nhớ ảo, page table và bộ nhớ vật lý.

<figure><img src="/files/tA2q0kFHfgfRnOZ6AhRJ" alt=""><figcaption></figcaption></figure>

Mỗi khối chứa dấu chấm lửng (...) đại diện cho một phạm vị địa chỉ bộ nhớ, hoặc vùng. Mỗi vùng bộ nhơ được ánh xạ tới Page table.

Một hệ thống hoàn toàn có thể có ít RAM hơn so với yêu cầu của tất cả các tiến trình đang chạy. Để giúp quản lý điều này, bộ nhớ bảo có thể được *paged out (chuyển trang ra),* có nghĩa là nó sẽ được lưu trữ tạm thời trên đĩa cứng khi không sử dụng. Nếu một tiến trình yêu cầu truy cập lại vào vùng bộ nhớ ảo đó, bộ nhớ có thể được đọc từ đĩa và ánh xạ lại vào bộ nhớ vật lý.

Bạn có thể xem bộ nhớ ảo của một tiến trình bằng công cụ phân tích tiến trình như Process Hacker (link). Để thực hiện việc này, hãy khởi động một chương trình (chẳng hạn Calculator.exe), mở Process Hacker và nhấp đúp vào tiến trình bạn muốn khám phá. Hình sau hiển thị tab Memory của một tiến trình trong Process Hacker.

<figure><img src="/files/x1an0oBDHKhEaNN4HYlT" alt=""><figcaption></figcaption></figure>

* Cột Base address (địa chỉ cơ sở) chứa địa chỉ bộ nhớ cơ sở của mỗi vùng bộ nhớ ảo được gán cho Calculator.exe.&#x20;
* Cột Type (Loại) chứa loại bộ nhớ cho mỗi vùng
* Cột Size (kích thước) cho biết kích thước cấp phát của mỗi vùng&#x20;
* Cột Protection (bảo vệ) liệt kê trạng thái bảo vệ của vùng.

Mỗi vùng bộ nhớ ảo thường được gán một trong ba loại bộ nhớ phổ biến:

* *Bộ nhớ Image (IMG)* thường chứa các tệp thực thi hoặc thư viện đã được ánh xạ vào bộ nhớ thông qua cơ chế trình tải Windows tiêu chuẩn.
* *Bộ nhớ Mapped (MAP)* thường chứa các tệp đã được ánh xạ vào bộ nhớ từ đĩa hoặc các dữ liệu khác được sử dụng bởi ứng dụng đang chạy bên trong tiến trình.
* *Bộ nhớ Private (PRV)* thường được cấp phát thông qua `VirtualAlloc` và các hàm cấp phát bộ nhớ tương tự.

Hơn nữa mỗi vùng bộ nhớ có thể là committed (đã cam kết) hoặc reserved (đã dự trữ). Các vùng committed đang được sử dụng tích cực và đã được ánh xạ tới bộ nhớ vật lý. Các vùng reserved được dự trữ cho tiến trình nhưng không được sử dụng tích cực và chưa được ánh xạ tới RAM.

## 1.6 PE file format

Microsoft đã tạo định dạng tệp PE (Portable Executable) cho các tệp thực thi chạy bên trong hệ điều hành Windows. Định dạng tệp PE chứa mọi thứ mà trình tải Windows PE cần để thực thi mã được nhúng. Hiểu định dạng PE là rất quan trọng để hiểu cách thức hoạt động của phần mềm độc hại.

### 1.6.1 Headers và Sections

Định dạng tệp PE chứa một số tiêu đề: metadata hoặc thông tin khác ở đầu tệp, cho hệ điều hành và phần mềm khác biết phải làm gì với nội dung của nó. DOS header chứa thông tin cần thiết cho MS-DOS và các phiên bản Windows rất sớm, và chủ yếu tồn tại vì lý do kế thừa.&#x20;

Tiêu đề PE chứa thông tin được sử dụng bởi trình tải Windows PE, chẳng hạn như kiến trúc CPU mà tệp thực thi được biên dịch để chạy và metadata như dấu thời gian biên dịch của tệp.

Tiêu đề PE cũng bao gồm *optional header*, cho biết thông tin quan trọng như địa chỉ bộ nhớ cơ sở của PE (địa chỉ bộ nhớ mà PE sẽ được ánh xạ vào bộ nhớ), kích thước của mã bên trong tệp thực thi và hệ điều hành mục tiêu mà tệp thực thi sẽ chạy trên đó. Tiêu đề "optional" trên thực tế không còn là tùy chọn trong các hệ thống Windows hiện đại.

Tệp PE cũng bao gồm *section header* (tiêu đề phần), chứa metadata liên quan đến từng phần của tệp (nơi lưu trữ nội dung tệp thực tế), chẳng hạn như kích thước, địa chỉ và các đặc điểm khác của phần. Cuối cùng hầu hết các tệp PE chứa ít nhất một vài phần sau:

* .**`text`**      Mã thực thi chính của tệp
* **`.rdata`**   Dữ liệu chỉ đọc, chẳng hạn như các biến và hằng số tĩnh
* **`.bss`**       Dữ liệu chưa khởi tạo, chẳng hạn như các biến chưa được gán giá trị.
* **`.data`**    Các biến không được nhúng trong các phần .rdata và .bss chẳng hạn như các biến toàn cục.
* .rsrc      Tài sản sẽ được tải bởi tệp thực thi tại thời điểm chạy, chẳng hạn như hình ảnh, phông chữ và các tệp hỗ trợ khác.
* .idata:  Bảng địa chỉ nhập
* .edata: Bảng địa chỉ xuất

### 1.6.2 Imports và Exports

Các phần **.idata** và **`.edata`** là hai trong số những thành phần quan trọng nhất của một tệp PE.&#x20;

Phần **`.idata`** chứa thoogn tin về các hàm mà tệp PE sẽ nhập tại thời gian chạy. Khi tệp PE được thực thi chương trình sẽ tải các thư vienj và hàm được tham chiếu ở đây vào bộ nhớ và xây dựng bảng địa chỉ nhập (IAT - *import address table*), ánh xạ các hàm Windows API đã nhập đến địa chỉ của chúng trong bộ nhớ.

Phần **`.edata`** chứa thoogn tin về các hàm mà tệp PE xuất sang các chương trình khác, sau đó chúng có thể nhập và tải vào bộ nhớ để sử dụng riêng. Ví dụ: các tệp thực thi DLL thường chứa danh sách các hàm được xuất. Giống như nhập, xuất có bảng riêng gọi là *export address table*.

> Lưu ý: Tuy nghiên, trên thực tế, cả 2 phần **`.edata`** và **`.idata`** thường được chứa trong phần .rdata

## 1.7 The Windows PE Loading Process

Khi bạn khởi chạy một tệp thực thi như Firefox trong Windows, đây là những gì sẽ xảy ra:

1. Windows tạo một cấu trúc dữ liệu EPROCESS mới cho chương trình Firefox và gán một ID tiến trình mới.
2. Windows khởi tạo bộ nhớ ảo cần thiết cho tiến trình, tạo cấu trúc PEB và tải 2 thư viện mà hầu hết tất cả các tiến trình Windows đều yêu cầu: **`ntdll.dll`** và **`kernel32.dll`**. Sau đó, nó chuẩn bị tải tệp PE của Firefox bằng cách khởi tạo trình tải PE.
3. Trình PE loader phân tích cú pháp các tiêu đề *DOS*, *PE* và *optional headers* của têp PE để thu thập tất cả thông tin cần thiết để thực thi thành công tệp.
4. Trình PE loader phân tích cú pháp *section headers* để chuẩn bị cho việc ánh xạ các phần này vào bộ nhớ. Trình PE loader ánh xạ từng phần vào bộ nhớ ảo bên trong tiến trình mới.
5. Trình PE loader tải tất cả các thư viện được tham chiếu trong phần nhập (thường là ***.idata*** hoặc ***.rdata***) và giải quyết tất cả các địa chỉ cho các hàm được yêu cầu. Tất cả các địa chỉ sau đó được lưu trữ trong IAT bên trong tiến trình.
6. Một luồng mới được tạo bên trong tiến trình hiện tại và trình loader thực thi các byte mã đầu tiên trong tệp thực thi (thương là trong phần .text).

<figure><img src="/files/hc3RpWTa1fZbNi6rc5eX" alt=""><figcaption></figcaption></figure>

Trên là hình minh họa một tệp PE đang được tải và ánh xạ vào bộ nhớ ảo.

Mỗi section trong tệp PE được ánh xạ riêng lẻ vào bộ nhớ, nhưng nó xuất hiện được mở rộng bộ nhớ ảo vì thường có các vùng bộ nhớ giữa mỗi phần.

{% hint style="success" %}
**KHÔNG GIAN ĐỊA CHỈ BỘ NHỚ SẮP XẾP NGẪU NHIÊN**

Sắp xếp ngẫu nhiên không gian địa chỉ (ASLR - Address space layout randomization) là một kỹ thuật được sử dụng để ngăn chặn các cuộc tấn công như làm hỏng bộ nhớ. Làm hỏng bộ nhớ (Memory corruption) có thể xảy ra khi một chương trình do kẻ tấn công kiểm soát ghi mã độc hại vào một vùng nhớ mà bình thường sẽ nằm ngoài phạm vi của chương trình (chẳng hạn như một tiến trình khác. Điều này có thể gây ra chương trình hoặc hệ điều hành gặp sự cố, hoặc tệ hơn, trao cho kẻ tấn công quyền kiểm soát hệ thống.

Các cuộc tấn công làm hỏng bộ nhớ tận dụng thực tế là Windows tải các tệp thực thi và thư viện vào bộ nhớ tại các địa chỉ có thể dự đoán được; tức là, kẻ tấn công đã biết nơi trình Windows loader sẽ ánh xạ các tệp thực thi và thư viện vào bộ nhớ và sẽ cố gắng làm hỏng bộ nhớ này để chạy mã độc hại.

ASLR ngẫu nhiên hóa các vị trí trong bộ nhớ nơi các tệp thực thi và thư viện này được tải, khiến cho cuộc sống của kẻ tán công trở nên khó khăn hơn rất nhiều. ASLR là một chủ đề chuyên sâu và nhiều nghiên cứ đã được dành để vừa triển khai vừa bỏ qua nó.
{% endhint %}

## 1.8 The Registry

Khái niệm Windows cuối cùng cần thảo luận là registry, đây chỉ đơn giản là một cơ sở dữ liệu mà hệ điều hành và các ứng dụng đẫ cài đặt khác sử dụng để lưu trữ các cấu hình và cài đặt. Registry lưu trữ dữ liệu theo thứ bậc, với một số root keys hoặc hives chính, mỗi khóa chứa khóa bổ sung (bạn co thể coi chúng như các thư mục), mỗi khóa lần lượt lưu trữ nhiều khóa hoặc giá trị hơn.

Values (giá trị) là cấu hình thực tế cho các cài đặt. Ví dụ the root key `HKEY_CURRENT_USER` chứa một kháo con có tên là `Control Panel`, bản thân nó chứa một khóa con có tên là `Mouse`. `Mouse` chứa nhiều giá trị, chẳng hạn như `MouseSpeed`, lưu trữ cấu hình tốc độ chuột cho người dùng hiện đang đăng nhập. Đường dẫn khóa registry này có thể được biểu thị giống như một đường dẫn tệp hoặc thư mục trong Windows: `HKEY_CURRENT_USER\Control Panel\Mouse\MouseSpeed`

Dưới đây sẽ là 5 hives quan trọng nhất trong registry:

1. **HKEY\_LOCAL\_MACHINE (HKLM):** các giá trị dành riêng cho hệ thống, chẳng hạn như cấu hình phần cứng và hệ điều hành cấp thấp, chính sách bảo mật và cài đặt tài khoản và cài đặt cho các phần mềm đã cài đặt khác nhau.
2. **HKEY\_CURRENT\_USER (HKCU):** các giá trị liên quan đến cài đặt người dùng và cấu hình hệ thống, như cài đặt âm thanh, chuột, bàn phím, mạng và máy in.
3. **HKEY\_USERS (HKU):** các giá trị liên quan đến cài đặt người dùng cho mỗi người dùng có tài khoản trên hệ thống. Dưới khóa gốc này, có một số khóa con khác bắt đầu bằng S (ví dụ: S-1-5-20). Mỗi khóa con đại diện cho mã định danh cho một tài khoản người dùng trên hệ thống và lưu trữ thông tin cấu hình cho mỗi người dùng.
4. **HKEY\_CURRENT\_CONFIG (HKCC):** con trỏ đến khóa HHKEY\_LOCAL\_MACHINE cho hồ sơ phần cứng hiện đang được sử dụng bởi người dùng đã đăng nhập. Khóa này ít quan trọng hơn cho mục đích của chúng ta, vì mọi thứ có giá trị đều được lưu trữ trong khóa HKEY\_LOCAL\_MACHINE.
5. **HKEY\_CLASSES\_ROOT (HKCR):** thông tin liên quan đến các ứng dụng đã đăng ký, chẳng hạn như liên kết tệp, ánh xạ các loại tệp với ứng dụng có thể xử lý chúng. (Ví dụ: các tệp .doc sẽ mở trong Microsoft Word.)

Các registry hives được lưu trữ trên đĩa cứng dưới dạng các tệp. Khi Windows khởi động, các tệp này sẽ được tải vào bộ nhớ và registry được xây dựng. Bất kỳ thay đổi nào với registry sau khi hệ thống khởi động đều được lưu trữ trong bộ nhớ và không trực tiếp trên đĩa. Đây là lý do tại sao một số phần mềm độc hại có thể lưu trữ mã và cấu hình độc hại trong registry mà không nhất thiết phải chạm vào đĩa.

Cuối cùng, Windows có một tiện ích tích hợp được gọi là Registry Editor (Regedit), nó cho phép bạn kiểm tra và sửa đổi từng khóa và giá trị registry trên hệ thống, điều này hữu ích để hiểu cách registry hoạt động.


---

# 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/mal/evasive-malware/chapter-1-windows-foundational-concepts.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.
