Dissecting REMCOS RAT: An in- depth analysis of a widespread 2024 malware, Part Two

Part two: Diving into REMCOS recording capabilities, launch, and C2 communication

8분 읽기Malware 분석
REMCOS RAT 해부: 널리 퍼진 2024 멀웨어에 대한 심층 분석, 2부

In the previous article in this series on the REMCOS implant, we shared information about execution, persistence, and defense evasion mechanisms. Continuing this series we’ll cover the second half of its execution flow and you’ll learn more about REMCOS recording capabilities and communication with its C2.

Starting watchdog

If the enable_watchdog_flag (index 0x32) is enabled, the REMCOS will activate its watchdog feature.

This feature involves the malware launching a new process, injecting itself into it, and monitoring the main process. The goal of the watchdog is to restart the main process in case it gets terminated. The main process can also restart the watchdog if it gets terminated.

The target binary for watchdog injection is selected from a hardcoded list, choosing the first binary for which the process creation and injection are successful:

  • svchost.exe
  • rmclient.exe
  • fsutil.exe

In this example, the watchdog process is svchost.exe.

The registry value HKCU/SOFTWARE/{MUTEX}/WD is created before starting the watchdog process and contains the main process PID.

Once REMCOS is running in the watchdog process, it takes a "special" execution path by verifying if the WD value exists in the malware registry key. If it does, the value is deleted, and the monitoring procedure function is invoked.

It is worth noting that the watchdog process has a special mutex to differentiate it from the main process mutex. This mutex string is derived from the configuration (index 0xE) and appended with -W.

When the main process is terminated, the watchdog detects it and restarts it using the ShellExecuteW API with the path to the malware binary retrieved from the HKCU/SOFTWARE/{mutex}/exepath registry key

Starting recording threads

Keylogging thread

The offline keylogger has two modes of operation:

  1. Keylog everything
  2. Enable keylogging when specific windows are in the foreground

When the keylogger_mode (index 0xF) field is set to 1 or 2 in the configuration, REMCOS activates its "Offline Keylogger" capability.

Keylogging is accomplished using the SetWindowsHookExA API with the WH_KEYBOARD_LL constant.

The file where the keylogging data is stored is built using the following configuration fields:

  • keylogger_root_directory (index 0x31)
  • keylogger_parent_directory (index 0x10)
  • keylogger_filename (index 0x11)

The keylogger file path is {keylogger_root_directory}/{keylogger_parent_directory}/{keylogger_filename}. In this case, it will be %APPDATA%/keylogger.dat.

The keylogger file can be encrypted by enabling the enable_keylogger_file_encryption_flag (index 0x12) flag in the configuration. It will be encrypted using the RC4 algorithm and the configuration key.

The file can also be made super hidden by enabling the enable_keylogger_file_hiding_flag (index 0x13) flag in the configuration.

When using the second keylogging mode, you need to set the keylogger_specific_window_names (index 0x2A) field with strings that will be searched in the current foreground window title every 5 seconds.

Upon a match, keylogging begins. Subsequently, the current foreground window is checked every second to stop the keylogger if the title no longer contains the specified strings.

Screen recording threads

When the enable_screenshot_flag (index 0x14) is enabled in the configuration, REMCOS will activate its screen recording capability.

To take a screenshot, REMCOS utilizes the CreateCompatibleBitmap and the BitBlt Windows APIs. If the enable_screenshot_mouse_drawing_flag (index 0x35) flag is enabled, the mouse is also drawn on the bitmap using the GetCursorInfo, GetIconInfo, and the DrawIcon API.

The path to the folder where the screenshots are stored is constructed using the following configuration:

  • screenshot_parent_directory (index 0x19)
  • screenshot_folder (index 0x1A)

The final path is {screenshot_parent_directory}/{screenshot_folder}.

REMCOS utilizes the screenshot_interval_in_minutes (index 0x15) field to capture a screenshot every X minutes and save it to disk using the following format string: time_%04i%02i%02i_%02i%02i%02i.

Similarly to keylogging data, when the enable_screenshot_encryption_flag (index 0x1B) is enabled, the screenshots are saved encrypted using the RC4 encryption algorithm and the configuration key.

At the top, REMCOS has a similar "specific window" feature for its screen recording as its keylogging capability. When the enable_screenshot_specific_window_names_flag (index 0x16) is set, a second screen recording thread is initiated.

This time, it utilizes the screenshot_specific_window_names (index 0x17) list of strings to capture a screenshot when the foreground window title contains one of the specified strings. Screenshots are taken every X seconds, as specified by the screenshot_specific_window_names_interval_in_seconds (index 0x18) field.

In this case, the screenshots are saved on the disk using a different format string: wnd_%04i%02i%02i_%02i%02i%02i. Below is an example using ["notepad"] as the list of specific window names and setting the Notepad process window in the foreground.

Audio recording thread

When the enable_audio_recording_flag (index 0x23) is enabled, REMCOS initiates its audio recording capability.

The recording is conducted using the Windows Wave* API. The duration of the recording is specified in minutes by the audio_recording_duration_in_minutes (0x24) configuration field.

After recording for X minutes, the recording file is saved, and a new recording begins. REMCOS uses the following configuration fields to construct the recording folder path:

  • audio_record_parent_directory (index 0x25)
  • audio_record_folder (index 0x26)

The final path is {audio_record_parent_directory}/{audio_record_folder}. In this case, it will be C:\MicRecords. Recordings are saved to disk using the following format: %Y-%m-%d %H.%M.wav.

Communication with the C2

After initialization, REMCOS initiates communication with its C2. It attempts to connect to each domain in its c2_list (index 0x0) until one responds.

According to previous research, communication can be encrypted using TLS if enabled for a specific C2. In such cases, the TLS engine will utilize the tls_raw_certificate (index 0x36), tls_key (index 0x37), and tls_raw_peer_certificate (index 0x38) configuration fields to establish the TLS tunnel.

It's important to note that in this scenario, only one peer certificate can be provided for multiple TLS-enabled C2 domains. As a result, it may be possible to identify other C2s using the same certificate.

Once connected we received our first packet:

As described in depth by Fortinet, the protocol hasn't changed, and all packets follow the same structure:

  • (orange)magic_number: \x24\x04\xff\x00
  • (red)data_size: \x40\x03\x00\x00
  • (green)command_id (number): \0x4b\x00\x00\x00
  • (blue)data fields separated by |\x1e\x1e\1f|

After receiving the first packet from the malware, we can send our own command using the following functions.

MAGIC = 0xFF0424
SEPARATOR = b"\x1e\x1e\x1f|"


def build_command_packet(command_id: int, command_data: bytes) -> bytes:
	return build_packet(command_id.to_bytes(4, byteorder="little") + command_data)


def build_packet(data: bytes) -> bytes:
	packet = MAGIC.to_bytes(4, byteorder="little")
	packet += len(data).to_bytes(4, byteorder="little")
	packet += data
	return packet

Here we are going to change the title of a Notepad window using the command 0x94, passing as parameters its window handle (329064) and the text of our choice.

def main() -> None:
	server_0 = nclib.TCPServer(("192.168.204.1", 8080))

	for client in server_0:
    	print(client.recv_all(5))

    	client.send(build_command_packet(
            			0x94,
            			b"329064" + SEPARATOR + "AM_I_A_JOKE_TO_YOU?".encode("utf-16-le")))

That’s the end of the second article. The third part will cover REMCOS' configuration and its C2 commands.