Post

Windows Malware: Mutexes

A mutex, short for mutual exclusion, is an object that controls access to a shared resource by multiple processes or threads. It ensures that a resource cannot be accessed simultaneously by multiple processes or threads.

Mutexes are used for several legitimate purposes in operating systems, such as inter-process communication, synchronization of threads and resource management.

Context

Oftentimes when developing malware, maintaining stealth is a top priority, and for this it may be necessary to ensure that only one instance of our program is running at any point in time.

Given the role of mutexes in preventing simultaneous resource access by multiple entities, we can leverage it in our malware to prevent several instances from running simultaneously on the same system. This can be achieved by implementing the following steps in the malware:

  • Have a name for our mutex, one that is unique to our malware.
  • Try to create a mutex with the above name.
  • If the operating system responds that the mutex exists, then another instance is running, and we therefore terminate execution.
  • If the mutex does not already exist, then our current instance is the only one running, and we proceed with execution.

Implementation

Code

Time for actual implementation of the above in C++. Create a new file with the .cpp extension eg. static_mutex.cpp

1
2
#include <iostream>
#include <windows.h>

We first import the necessary header files. iostream is needed as we will print a message to the console to confirm the result of our program. windows.h on the other hand allows us to work with Windows API functions.

1
2
3
void payload() {
    MessageBoxW(NULL, L"Payload executed", L"Alert", MB_OK);
}

The payload refers to the primary objective of our malware. For illustration purposes, our program will just pop up a message box indicating successful execution of the payload.

1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {
    HANDLE hMutex = CreateMutexW(NULL, FALSE, L"UniqueMutexName");

    if(hMutex && GetLastError() == ERROR_ALREADY_EXISTS) {
        std::cout << "Another instance is already running. Quitting ..." << std::endl;
        CloseHandle(hMutex);
        return 0;
    }

    payload();
    CloseHandle(hMutex);
    return 0;
}

Let's break this down:
First we try to create a mutex using the CreateMutexW Windows API function. From the MSDN
documentation
, if the mutex already exists, the function returns a handle to the mutex, and an error indicating that the mutex already exists is also raised.
We check for this in the if statement, and if it is the case, then we just return from the program (after printing out a message in the console). Otherwise, our payload gets executed.

Compilation

Compile the file using the following command:

1
g++ static_mutex.cpp -o static_mutex.exe

Execution

On one command line window (or tab), execute the program using the command:

1
./static_mutex.exe

Now open another window (or tab) and execute the same command to start another instance of the program.

Result

Upon executing the program for the first time, a message box pops up indicating successful execution of our payload:

img

In the second time, our program prints a message to the console and terminates without executing the payload:

img

Dynamically-generated mutexes

In the spirit of evasion and stealth comes dynamically-generated mutexes. In the above example, we used a hardcoded mutex name. We sure get the benefit of not having multiple instances of our program running simultaneously, but then this hardcoded name presents a problem. Defenders can simply add an antivirus rule that checks for the creation or existence of a mutex with that name, and our malware will be flagged.

To beat this, we can simply resort to dynamic generation of the mutex name. The rule for this is pretty simple: Use values that are consistent between different processes but different or varying between different systems. For instance, different processes on the same system will all get the same username value when queried, but this value is not necessarily consistent across different systems.

We can therefore modify our previous example to have a function that dynamically generates the mutex name. In our case, we will use the username and computer name values.

Add header file required for the constants UNLEN and MAX_COMPUTERNAME_LENGTH, which are part of the LAN manager API:

1
#include <lmcons.h>

Define function to dynamically generate the mutex name:

1
2
3
4
5
6
7
8
9
10
11
12
13
std::wstring generateMutexName() {
    // get the username
    wchar_t username[UNLEN + 1];
    DWORD usernameLen = UNLEN + 1;
    GetUserNameW(username, &usernameLen);

    // get machine name
    wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
    DWORD computerNameLen = MAX_COMPUTERNAME_LENGTH + 1;
    GetComputerNameW(computerName, &computerNameLen);

    return std::wstring(username) + L"_" + std::wstring(computerName);
}

The next and final modification is to substitute the hardcoded name with a dynamically generated one:

1
HANDLE hMutex = CreateMutexW(NULL, FALSE, generateMutexName().c_str());

Note that we are not limited to just the username and computer name values! Others like the MAC address, IP address and volume serial number can also be used.

Conclusion

I hope you learnt something from the article. If so, please consider sharing it with others whom you believe can also benefit from this content.

This post is licensed under CC BY 4.0 by the author.