Introduction

Trong thực tế, ta sẽ cần phải giới hạn lại những hành động mà malware sẽ thực hiện do hành động càng nhiều thì càng dễ bị phát hiện bởi các hệ thống giám sát.

Để triển khai điều, chúng ta sẽ sử dụng các đối tượng đồng bộ hóa của Windows chẳng hạn như mutex, semaphore và event. Các đối tượng này giúp điều phối việc truy cập vào các tài nguyên dùng chung giữa các thread hoặc process nhằm ngăn chặn xung đột hoặc race condition.

Semaphore

Là một cơ chế đồng bộ hóa sử dụng một giá trị trong bộ nhớ để kiểm soát quyền truy cập vào tài nguyên chia sẻ. Có 2 loại semaphore:

  • Binary: có hai giá trị là 1 và 0, lần lượt tương ứng với trạng thái khả dụng và không khả dụng của tài nguyên.
  • Counting: có giá trị n lớn hơn 1, đại diện cho số lượng tài nguyên khả dụng cho n tiến trình cùng truy cập.

Để kiểm soát quá trình thực thi, mỗi khi payload được chạy, ta sẽ tạo một named semaphore (semaphore có tên). Nếu đây là lần đầu tiên malware được thực thi, named semaphore sẽ được tạo và payload sẽ tiếp tục chạy. Ngược lại, nếu một tiến trình khác của malware khởi chạy, semaphore sẽ không được tạo do đã tồn tại một semaphore cùng tên. Điều này cho thấy payload đang hoạt động và việc thực thi sẽ được ngăn chặn nhằm tránh sự trùng lặp.

Để tạo ra semaphore có tên, ta sẽ dùng hàm CreateSemaphoreA. Nếu semaphore có cùng tên đã được tạo ra, CreateSemaphoreA sẽ trả về handle đến semaphore đó và GetLastError sẽ trả về ERROR_ALREADY_EXISTS.

HANDLE hSemaphore = CreateSemaphoreA(NULL, 10, 10, "ControlString");
 
if (hSemaphore != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
	// Payload is already running
else
	// Payload is not running

Mutexes

Cũng là một cơ chế đồng bộ giống như semaphore. Mutex có 2 trạng thái là khóa và bị khóa.

Khi một thread cố gắng truy cập vào một tài nguyên chia sẻ, nó sẽ cần phải kiểm tra trạng thái của mutex. Nếu như mutex bị khóa, thread đó cần phải chờ cho đến khi mutex được mở khóa. Trong trường hợp mutex không bị khóa, thread cần khóa mutex rồi thực hiện những tác vụ cần thiết ở trên tài nguyên chia sẻ và mở khóa mutex khi hoàn tất.

Về sự khác biệt giữa mutex và binary semaphore

Một cách tổng quát, mutex có khái niệm sở hữu: chỉ có thread nào lock mutex thì mới có thể unlock mutex. Đối với semaphore thì ngược lại: bất kỳ thread nào cũng có thể signal (release hoặc up) hoặc wait (acquire hoặc down). Do không có tính sở hữu, semaphore (kể cả counting semaphore) thường được dùng cho việc giao tiếp giữa các thread.

Xem thêm: Mutex vs Semaphore - GeeksforGeeks

Để tạo ra một mutex có tên, ta có thể dùng hàm CreateMutexA của Windows API:

HANDLE hMutex = CreateMutexA(NULL, FALSE, "ControlString");
 
if (hMutex != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
	// Payload is already running
else
	// Payload is not running

Events

Tương tự, event là một cơ chế đồng bộ giúp điều phối việc thực thi giữa các thread và tiến trình. Event có 2 loại là tự động và thủ công. Event tự động xảy ra khi bị trigger bởi các điều kiện cụ thể chẳng hạn như khi bộ đếm thời gian kết thúc. Trong khi đó, event thủ công cần phải được set hoặc reset một cách tường minh.

Để tạo ra event, ta có thể dùng hàm CreateEventA như sau:

HANDLE hEvent = CreateEventA(NULL, FALSE, FALSE, "ControlString");
 
if (hEvent != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
	// Payload is already running
else
	// Payload is not running

Demo

Dưới đây là các minh họa cho việc sử dụng các cơ chế đồng bộ khác nhau để đảm bảo payload của malware chỉ được thực hiện 1 lần duy nhất mặc cho có nhiều tiến trình được chạy.

Sử dụng semaphore:

Sử dụng mutex:

Sử dụng event:

Resources