Virtual Memory & Paging
Bộ nhớ trong các hệ điều hành hiện đại không được ánh xạ trực tiếp vào bộ nhớ vật lý (mà cụ thể là RAM). Thay vào đó, các tiến trình sử dụng các địa chỉ vùng nhớ ảo để ánh xạ vào các địa chỉ vùng nhớ vật lý. Mục đích của việc này là để tiết kiệm tối đa bộ nhớ vật lý được sử dụng. Ngoài ra, bộ nhớ ảo cũng có thể được ánh xạ vào đĩa cứng (chẳng hạn như HDD hoặc SSD). Bộ nhớ ảo hoạt động dựa vào việc chia bộ nhớ thành nhiều phần, mỗi phần có kích thước là 4KB và được gọi là “trang bộ nhớ” (page).
Minh họa tham khảo từ Windows Internals Book - Sysinternals | Microsoft Learn:
Bằng cách này, hai tiến trình có thể sử dụng cùng 1 địa chỉ vùng nhớ vật lý nhưng lại có hai địa chỉ vùng nhớ ảo khác nhau.
Page State
Các page trong không gian địa chỉ ảo của một tiến trình có thể có 1 trong 3 trạng thái dưới đây:
- Free: chưa được sử dụng. Nó có thể được để dành (reserved) hoặc cấp phát (committed) hoặc đồng thời cả 2. Việc cố gắng đọc hoặc ghi dữ liệu vào một free page có thể dẫn đến ngoại lệ vi phạm quyền truy cập (access violation exception).
- Reserved: được để dành cho việc sử dụng trong tương lai. Dãy địa chỉ của reserved page không thể được chiếm dụng bởi các hàm cấp phát khác. Ngoài ra, nó sẽ không có không gian bộ nhớ vật lý tương ứng và không thể được truy cập cho đến khi được cấp phát.
- Committed: đã được cấp phát bộ nhớ vật lý tương ứng ở trên RAM hoặc trên disk và có thể được truy cập bởi tiến trình với tùy chọn bảo vệ (protection option - liên quan đến quyền đọc, ghi và thực thi) đã được thiết lập. Hệ thống chỉ khởi tạo và nạp từng page đã được cấp phát vào bộ nhớ vật lý khi tiến trình thực hiện truy cập vào page lần đầu tiên. Khi tiến trình kết thúc, hệ thống sẽ giải phóng bộ nhớ vật lý của các page.
Page Protection Options
Một số protection option ở trên các committed page:
PAGE_NOACCESS
: không cho truy cập.PAGE_EXECUTE_READWRITE
: cho phép đọc, ghi và thực thi. Không nên sử dụng và có thể được dùng như là một IoC vì việc một vùng nhớ vừa có quyền ghi và thực thi là bất thường.PAGE_READONLY
: chỉ cho phép đọc.
Memory Protection
Một số hệ điều hành hiện đại có các cơ chế bảo vệ bộ nhớ mà ta sẽ gặp phải trong quá trình xây dựng malware:
- Data Execution Prevention (DEP) giúp ngăn chặn việc thực thi code ở trên vùng nhớ nếu protection option
PAGE_NOACCESS
được bật. - Address Space Layout Randomization (ASLR) sắp xếp ngẫu nhiên các không gian bộ nhớ quan trọng trong tiến trình chẳng hạn như địa chỉ cơ sở của file thực thi (base address) và các vùng nhớ stack, heap hoặc các thư viện.
X86 Vs X64 Memory Space
Các tiến trình x86 có không gian bộ nhớ là 4GB (0xFFFFFFFF
) còn các tiến trình x64 có không gian bộ nhớ là 128TB (0xFFFFFFFFFFFFFFFF
).
Allocating Memory Example
Để cấp phát bộ nhớ, ngoài các hàm của C thì ta còn có thể dùng các hàm của Windows API:
// Allocating a memory buffer of *100* bytes
// Method 1 - Using malloc()
PVOID pAddress = malloc(100);
// Method 2 - Using HeapAlloc()
PVOID pAddress = HeapAlloc(GetProcessHeap(), 0, 100);
// Method 3 - Using LocalAlloc()
PVOID pAddress = LocalAlloc(LPTR, 100);
Giá trị trả về là địa chỉ cơ sở (base address) của vùng nhớ đã được cấp phát.
Ví dụ về base address:
#include <Windows.h>
#include <stdio.h>
int main() {
PVOID pAddress = HeapAlloc(GetProcessHeap(), 0, 100);
printf("[+] Base Address Of Allocated Memory: 0x%p \n", pAddress);
printf("[#] Press <Enter> To Quit ... ");
getchar();
return 0;
}
Kết quả:
[+] Base Address Of Allocated Memory: 0x000002371FE649B0
[#] Press <Enter> To Quit ...
Khi được cấp phát, vùng nhớ có thể chứa những giá trị ngẫu nhiên như sau:
Một vài hàm cấp phát có tùy chọn cho phép xóa sạch giá trị của vùng nhớ (gán tất cả các byte bằng 0).
Writing To Memory Example
Một trong số những hàm giúp ghi giá trị vào vùng nhớ là memcpy()
:
PVOID pAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
CHAR* cString = "MalDev Academy Is The Best";
memcpy(pAddress, cString, strlen(cString));
Hàm HeapAlloc()
sử dụng cờ HEAP_ZERO_MEMORY
để khởi tạo giá trị ban đầu cho các byte trong vùng nhớ là 0. Tham số cuối cùng của memcpy()
là kích thước dữ liệu cần sao chép vào vùng nhớ.
Kiểm tra bằng cách debug:
Freeing Allocated Memory
Nên giải phóng vùng nhớ khi kết thúc chương trình để hạn chế rò rỉ bộ nhớ (memory leak).
Tùy thuộc vào hàm cấp phát mà sẽ có hàm giải phóng vùng nhớ tương ứng:
malloc
-free
HeapAlloc
-HeapFree
LocalAlloc
-LocalFree
Các hình bên dưới minh họa cho quá trình giải phóng vùng nhớ có base address là 0000023ADE449900
:
Có thể thấy, dữ liệu trong vùng nhớ đã bị ghi đè bởi các giá trị ngẫu nhiên bởi hệ điều hành.
Related
list
from outgoing([[MalDev - Windows Memory Management]])
sort file.ctime asc