A new rat in the valley: SAFERAT

Key takeaways

A new rat in the valley: SAFERAT

This article details a new malicious code, SafeRat, which we attribute to the APT group Silver Fox.

First, we will describe this new code, its operation, capabilities and specificities.. We will look at certain interesting functionalities such as the silent deployment of an RMM (Remote Monitoring and Management) solution. We will also cover the elements identified in the wild, and notably the presumed victimology.

We will then focus on a sample that clearly stands out, and analyze a loader that will allow us to establish a link with the group Silver Fox. We will also share code to extract the payload from these at the end of this article.

We will also see a second loader dating from late May 2025 we named UUIDLoader.

Finally, we will provide several detection guidances in order to detect this specific threat.

SAFERAT Malware Analysis

SAFERAT is a trojan, written in C++, which has the particularity of being both very simple and having numerous capabilities. It presents itself as a DLL, loaded by a signed and legitimate executable (side-loading technique), typically embedded in a ZIP file and sent by email.

It does not include code obfuscation mechanisms or string encryption. The name “SafeRat” even comes from the malware itself:

Mutex used by the malware to prevent superinfection

View on exalyze

Once loaded, it will instantiate its network routines and contact its control server via RAW TCP. It does not possess network encapsulation mechanisms nor proxy usage, and uses the CTcpClient ( https://github.com/embeddedmz/socket-cpp ) library.

Its communication protocol is extremely simple; it will simply encapsulate its data as follows:

WORD WORD DWORD DWORD Remaining
Total size -4 \xC0\xFF DATA Compressed size DATA Decompressed size ZLIB compressed DATA

The data sent by the malware is XOR-encrypted with a 16-byte key (hardcoded in the code) before compression. Data received by the control server is not encrypted. DATA will then indicate a command or response ID in its 1st byte.

During the first data transmission, the malware will send the following information about the user:

The following antivirus products are searched for:

The following instant messaging software is searched for:

Subsequently, the malware will send, in real time, all the window titles that gain focus, which suggests very strong interactivity with the user controlling them. It is also noted that a specific message notifies the launch of a Telegram.exe process.

The malware supports several commands:

Opcode Name Parameters C2 Return Notes
0x00 Shutdown/Reboot 1 byte flags ExitWindowsEx Restarts the system
0x02 Kill agent Clean shutdown
0x03 Set Remark string Operator tag, re-exfiltrated in beacon
0x04 Set Group string Campaign group, re-exfiltrated in beacon
0x06–0x0F,0x11,0x12 Load plugin PE binary + context Reflective load, export “base” called, 12 thread slots
0x10 Update config 0x104 bytes XOR-0x46-Base64 Restarts with new C2 config
0x13 Install/Steal Sunlogin path + installer binary opcode 0xD9 + fastcode+password Installs Sunlogin if absent, silent theft
0x14 Drop plugin 32-bit path + PE Creation and execution of %TEMP%\Plugin32.exe with arguments -connect IP:1111
0x15 Kill 360 & persist 0xDA/0xD9 Degrades 360tray token, installs scheduled task
0x16 Run PE in RAM PE binary Execution of exe in RAM

The most interesting commands are the following:

A single root version is present; it is globally the same modified binary. The samples share two elements:

The differences in size or data between the samples are explained by the fact that some of them seem to have been extracted in RAM and then rebuilt. However, it is the same original binary.

Since the code does not encrypt any data, it is quite simple to write a YARA rule identifying critical character strings (see appendix).

We can also search for potentially signing routines such as cryptographic loops:

Cryptographic configuration decryption loop
View on Exalyze

Analysis of the May-June 2026 campaign

All files consist of a DLL (e.g., nvdaHelperRemote.dll) loaded by a legitimate and signed executable (e.g., nvdaHelperRemoteLoader.exe) that has been renamed (e.g., to View.exe). The files were compiled in January 2026, and submissions on VirusTotal were found mainly in January, then starting from the end of May.

We can find the following names for ZIP files, suggesting the victimology:

In these, the signed file was renamed to:

The sideloading DLLs are:

Malicious DLL filename Legitimate executable importing the DLL
jli.dll javaw.exe (JAVA)
libglib-2.0-0.dll gspawn-win64-helper.exe (Inkscape)
libintl-8.dll gspawn-win64-helper.exe (Inkscape)
xii_ecd_api.dll Unknown (VGNLab)
libfabric.dll fi_info.exe (Intel MPI)
OCefClient.dll OCefsubprocess.exe (OriginLab)
gxl_3d_x64.dll GpuTest.exe (Geeks3D.com)
nvdaHelperRemote.dll nvdaHelperRemoteLoader.exe (NonVisualDesktopAccess)

Two interesting elements can be noted here:

The majority of samples uploaded via unique Web type sources come from Asia:

VirusTotal submits by country

The control servers are the following:

DONUTLoader

A binary stands out in this campaign because it was submitted in January, has 2.16.164[.]120 (located in Germany) as C2 server and uses port 80: 6fc82b4e6a944a3f7bce7a39276ed5246a5d78d17a75ba36a7dd39873c852f3a

More importantly, it was not packaged in a ZIP, but in an EXE loader: f5cf6da7fd383b6c6bba599dc9df4d5ea13a0792047dd14b44e94ceba9689f84 . It was submitted from Europe on January 12, 2026, which is, if the compilation timestamp is correct, 7 days after the malware compilation. All these elements differ from the other samples, all submitted in a phishing ZIP from Asian countries.

Using similarity search in our exalyze.io platform, we find another similar loader, 531e61e5376d7e7aff0a33752074fc1914039273545ddbeeb408866ad8889270 which possesses almost exactly the same compilation timestamp (within 1 second). The latter, however, was uploaded in May 2025.

EXALYZE Similarity search

See function matching in Exalyze

In both cases, these are two versions of the same relatively simple loader that installs itself in persistence (identical point), loads a resource, decrypts it, and executes it in memory:

View of the sequences illustrating the actions taken in a synthetic way

The cryptographic loop identified at the end of the installation in persistence is a simple implementation of RC4. The key is present at the beginning of the embedded resource, and flags at its startup indicate in particular whether an anti-sandbox mechanism (at least 40 processes must be present) must be used, and whether persistence must be established.

If the first payload is extracted from the sample, we find a shellcode, followed by a SafeRAT binary. The shellcode used to load the binary is DONUT: https://github.com/TheWover/donut. In our case, no persistence and no anti-sandbox mechanism are used.

Our second payload uses the same shellcode. After extraction, the extracted binary e194ff05fc8d0dc2faabb74171509f10b2426de734664da0a1a109b8ce7c2c77 turns out to be ValleyRat malware. This behavior is also described in the article https://www.cloudsek.com/blog/silver-fox-targeting-india-using-tax-themed-phishing-lures#stage-3-donutloader .

UUIDLoader

By analyzing similar phishings, we have also identified a second loader 253f5d49f3a3a9709bde100be46d5f526823b336a9ff2a35b096fabaefd3fb57 used to embed SafeRAT, which we named UUIDLoader. The code is also a DLL sideload here, which will:

We note a large number of mechanisms aimed at preventing emulation:

The compilation of the 8 loaders is much more recent: it is between May 25, 2026 and June 12, 2026. The main differences between the codes lie mainly in the presence or absence of more advanced obfuscation mechanisms (imports resolved thanks to a checksum, opaque predicates, the routine used to trigger code execution, and the XOR key used).

Regarding statistics in terms of legitimate sideload executable usage, control server, and phishing filename, we find the same elements as for SafeRat:

If we examine these samples, we obviously find that they share similarities (sometimes complex to identify given the fairly rapid evolution of the code on anti-emulation mechanisms), but another sample appears, which we did not already know:

Matches by similarity

Try it in Exalyze

The shared code is the XOR decryption routine of the payload embedded in the UUIDLoaders:

Payload decryption routine

Try it in Exalyze

The sample c904cdac849fdbb49274a3c075db8845791e923250d08d558a4115936ef44405 is ultimately indeed a UUIDLoader, however the latter does not load a SafeRat and is a version visibly earlier than those identified in June. The latter was compiled on May 7 and then submitted on May 13, 2026 in RBI.zip and Laporan Rekening Bulan Mei.zip archives. This is a UUIDLoader loader that executes another type of shellcode, and which does not embed a DONUT to load a SafeRat, the payload being particularly small, which explains why we had not already identified it.

ValleyRat loader executed

This is a stager for ValleyRat, as described in the article https://www.zscaler.com/blogs/security-research/technical-analysis-latest-variant-valleyrat.

Links with ValleyRat and Silver Fox

We have therefore seen links with ValleyRat, since DONUTLoader and UUIDLoader have visibly served to load the latter as well as SafeRat.

ValleyRat has been documented several times in the past:

We can find links with ValleyRat samples via similarity search in Exalyze, even if this similarity is based on public libraries such as CTcpClient:

Similarity search showing ValleyRat samples

We find an inheritance between the three codes Gh0st, ValleyRat and SafeRat: ValleyRat is strongly inspired by Gh0st, and we find code from ValleyRat in SafeRat and therefore code inherited from Gh0st.

The victimology and the modus operandi are also similar to those described in attacks involving SilverFox and their tools such as ValleyRat or AtlasRat, notably in the following articles:

Remarks

Detection Leads

SafeRat is relatively simple to detect with YARA rules. The detection of executables launched from a .zip file is also implementable.

Some specific elements can be searched for:

Since the malware does not encrypt its downstream communications and uses a fixed encryption key, it is possible to sign them.

Conclusion

In view of the identified elements, we estimate it is very likely that:

The Chinese cyber ecosystem where certain developments are used by several groups of attackers and where several groups can target identical entities in a similar way complicates this analysis.

SafeRat distinguishes itself from other tools by the fact that it contains comparatively less code than them. Its inability to use a proxy, protocol encapsulation, strong encryption, an absence of code concealment, and the specific targeting of instant messaging means seem to point to a tool aimed at individuals or less-protected entities. Particular attention is paid to antivirus products. We will note a native capacity to deploy and install an RMM of Chinese origin, SunLogin. From a development point of view, its code is simple, but effective. However, it will be noted that the majority of these codes are detected by antivirus products.

Regarding the version packaged in a loader, in view of the temporality (use 5 days after compilation in a different packaging, and phishing campaign 5 months later) we estimate it possible that it is a test version, although it could also be a deployment made hastily for a specific need.

Remark a TLP AMBER version of this blog post has been shared with selected ExaTrack partners. More information can be provided upon request.

appendix A : system IOCs

Value Description
%systemroot%\System32\Tasks\systm64 Scheduled task
Global\SafeRatOnlineMutex Mutex
HKCU\SOFTWARE\<computername>:Group RegistryValue Group
HKCU\SOFTWARE\<computername>:Time RegistryValue indicating first infection date and time
HKCU\SOFTWARE\<computername>:Remark RegistryValue Remark
-connect %s:1111 Parameter given to plugins
jli.dll libglib-2.0-0.dll libintl-8.dll xii_ecd_api.dll libfabric.dll OCefClient.dll gxl_3d_x64.dll nvdaHelperRemote.dll Malicious DLL filename. Legitimate filename but can be searched in non common paths
SunLogin Chinese RMM used by the operator. Not malicious but uncommon outside of several countries
\SOFTWARE\Microsoft\Windows\CurrentVersion\Run:Windows Security RegistryValue Windows Security

appendix B : C2 servers

appendix C : SHA256 hashes

SafeRat

Remark A lot of other samples can be identified in online analysis platforms, however most of them consist in the same files, extracted in RAM.

Phishing ZIP files

DonutLoader

This list is not exhaustive as this blogpost does not cover this specific threat.

UUIDLoader

appendix D : YARA rules

rule SafeRatStrings
{
	meta:
  	  description = "SafeRat specific strings"
 	   author = "ExaTrack"
    // this rule will not resist light modifications, but with careful selection it might be
	// split into different rules which can target specific features :)
	strings:
    	$proc1 = "Telegram.exe" ascii
    	$proc2 = "WeChatApp.exe" ascii
    	$proc3 = "360tray.exe" ascii
    	$proc4 = "multitip.exe" ascii
    	$proc5 = "xrk.exe" ascii
    	$dbg1 = "%s --> Error: %d, EC: %d" ascii
    	$dbg2 = "---------------> Client Worker Thread 0x%08X stoped <---------------" ascii
    	$dbg3 = "<C-CNNID: %Iu> OnSend() event should not return 'HR_ERROR' !!" ascii
    	$str1 = "SunloginClient" wide
    	$str2 = "-connect %s:1111" ascii
    	$str3 = "sysmt64" ascii
    	$str4 = "SOFTWARE\\%s\\" ascii
    	$str5_1 = "Plug" ascii
    	$str5_2 = "in32" ascii
    	$str5_3 = ".exe" ascii
    	$str6 = "Global\\SafeRatOnlineMutex" ascii
    	$lib1 = "AVCTcpClientListener" ascii
    	$lib2 = "deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler" ascii
    	$lib3 = "CTcpPackClientT" ascii
	condition:
    	uint16(0) == 0x5A4D and all of them
}

rule SilverFoxDonutLoaderStrings {
	meta:
  	  description = "SilverFox DonutLoader specific strings"
 	   author = "ExaTrack"
	strings:
    	$str1 = "Software\\Microsoft\\Windows\\CurrentVersion\\Run" ascii
    	$str2 = "CreateToolhelp32Snapshot" ascii
    	$str3 = "Windows Security" ascii
    	$str5 = "mscoree.dll" wide
    condition:
    	uint16(0) == 0x5A4D and all of them
}

rule SilverFoxDonutLoader {
	meta:
  	  description = "SilverFox DonutLoader code"
 	   author = "ExaTrack"
    strings:
    	$rc4_1 = {8BC1884C142083E07F488D5201FFC10FB604288884141F0100003BCE7CE2}
    	$rc4_2 = {8D470125FF0000807D09FFC80D00FFFFFFFFC0}
    	$rc4_3 = {4C8D442420450FB60C384103D181E2FF000080}
    	$rc4_4 = {4863C2488D4C24204803C80FB60141880438448809410FB60C384903C90FB6C10FB64C042041300E49FFC64983EA01}
    	$proc_1 = {33D248899C248002000041B834020000C744242038020000}
    	$resrc_1 = {0F1040100F1048200F10100F294424300F1040300F294C244066480F7ED30F10484048C1EB200F294424500F1040500F294C24600F1048600F294424700F1040700F298C2480000000F20F108880000000660F7ED00F295424200F29842490000000F20F118C24A0000000}
	condition:
    	uint16(0) == 0x5A4D and all of them
}

Appendix E: SURICATA rules

alert tcp any any -> any any (
	msg:"SAFERAT keepalive header generic";
	flow:established;
	content:"|11 00 C0 FF 11 00 00 00 01 00 00 00|";
	dsize:21;
	sid:1000001;
	rev:1;
)

alert tcp any any -> any any (
	msg:"SAFERAT keepalive key 8FA24DC719E36B5E923AF17CB845D621";
	flow:established;
	content:"|11 00 C0 FF 11 00 00 00 01 00 00 00 78 9C EB 03 00 00 8F 00 8F|";
	dsize:21;
	sid:1000002;
	rev:1;
)

alert tcp any any -> any any (
	msg:"SAFERAT HELLO header";
	flow:established;
	content:"|C0 FF|";
    offset:2;
	content:"|00 00 48 03 00 00|";
	distance:2;
	sid:1000003;
	rev:1;
)

Appendix F : SIGMA rules

title: SafeRat HKCU SOFTWARE Group/Remark
status: experimental
description: >
  SafeRat HKCU SOFTWARE Group/Remark registry key
author: "ExaTrack"
date: 2026-06-30
logsource:
  category: registry_event
  product: windows
detection:
  selection:
	EventType: SetValue
	TargetObject|re: '^HKU\\.*\\SOFTWARE\\[^\\]+\\(Group|Remark|Time)$'
  condition: selection
level: high

title: SafeRat systm64 scheduled task
status: experimental
description: >
  SafeRat systm64 scheduled task, runs at logon
author: "ExaTrack"
date: 2026-06-30
logsource:
  product: windows
  service: security
detection:
  selection:
	EventID: 4698
	TaskName|contains: 'systm64'
  condition: selection
level: high

title: SunLogin RMM presence
status: experimental
description: >
  Detects execution of SunLogin RMM, used with saferat
author: "ExaTrack"
date: 2026-06-30
logsource:
  category: process_creation
  product: windows
detection:
  selection_process:
	- Image|endswith: '\xrk.exe'
	- ParentImage|endswith: '\xrk.exe'
	- CommandLine|contains: 'xrk.exe'
  condition: selection_process
falsepositives:
  - Legitimate usage of SunLogin RMM by IT
level: medium

title: SunLogin RMM install
status: experimental
description: >
  Detects SunLogin RMM installation, might be done by SafeRat operators. Matches on VersionInfo as the filename is custom
author: "ExaTrack"
date: 2026-06-30logsource:
  category: process_creation
  product: windows
  definition: 'Requires Sysmon EventID 1 with VersionInfo fields enabled, or equivalent EDR telemetry'
detection:
  selection_company:
	Copyright|contains:
  	- 'Oray Information Technology'
  selection_product:
	Product|contains:
  	- 'SunLoginClient'
  selection_description:
	Description|contains:
  	- 'SunLoginClient'
  condition: 1 of selection_*

title: DONUTLoader Windows Security Persistance Run Key
status: experimental
description: >
  Detects Windows Security Run key creation, used by DONUTLoader
author: "ExaTrack"
date: 2026-06-30
logsource:
  category: registry_event
  product: windows
detection:
  selection:
	EventType: SetValue
	TargetObject|contains:
  	- '\Software\Microsoft\Windows\CurrentVersion\Run\'
	TargetObject|endswith: 'Windows Security'
  condition: selection
level: high

title: SafeRat Plugin32 temporary file
status: experimental
description: >
  Detects SafeRat's Plugin32.exe temporary file creation
author: "ExaTrack"
date: 2026-06-30
logsource:
  category: file_event
  product: windows
detection:
  selection:
	TargetFilename|contains: '\AppData\Local\Temp\Plugin32.exe'
  condition: selection
level: high

title: SafeRat plugin32.exe commandline -connect IP:1111
status: experimental
description: >
  Detects the commandline provided to plugins dropped by SafeRat. Plugin name is likely to be plugin32.exe or plugin32<tick>.exe.
author: "ExaTrack"
date: 2026-06-30
logsource:
  category: process_creation
  product: windows
detection:
  selection:
	CommandLine|contains: '-connect '
  selection_port:
	CommandLine|re: '-connect\s+\d{1,3}(\.\d{1,3}){3}:1111\b'
  condition: selection and selection_port
level: high

Appendix G : DONUTLoader extraction payload Script

import sys
import struct
import pefile

RESOURCE_NAME = 100   # RCDATA/100
HEADER_SIZE   = 0x88
KEY_SIZE  	= 128


def rc4(key: bytes, data: bytes) -> bytes:
	S = list(range(256))
	j = 0
	for i in range(256):
    	j = (j + S[i] + key[i % len(key)]) & 0xFF
    	S[i], S[j] = S[j], S[i]

	out = bytearray(len(data))
	i = j = 0
	for n, byte in enumerate(data):
    	i = (i + 1) & 0xFF
    	j = (j + S[i]) & 0xFF
    	S[i], S[j] = S[j], S[i]
    	out[n] = byte ^ S[(S[i] + S[j]) & 0xFF]
	return bytes(out)


def get_rcdata_100(pe: pefile.PE) -> bytes:
	rt_rcdata = pefile.RESOURCE_TYPE['RT_RCDATA']
	for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries:
    	if entry.id != rt_rcdata:
        	continue
    	for res_id in entry.directory.entries:
        	if res_id.id != RESOURCE_NAME:
            	continue
        	data_entry = res_id.directory.entries[0].data
        	rva, size = data_entry.struct.OffsetToData, data_entry.struct.Size
        	return pe.get_memory_mapped_image()[rva:rva + size]
	raise ValueError("RCDATA/100 not found")


def extract(path: str):
	pe = pefile.PE(path)
	res = get_rcdata_100(pe)
	anti_sandbox_flag, persist_flag = struct.unpack_from("<II", res, 0)
	key = res[8:8 + KEY_SIZE]
	encrypted_payload = res[HEADER_SIZE:]
	decrypted = rc4(key, encrypted_payload)
	print(f"[*] anti_sandbox_flag = {anti_sandbox_flag}")
	print(f"[*] persist_flag  	= {persist_flag}")
	print(f"[*] RC4 key       	= {key.hex()}")
	print(f"[*] payload size  	= {len(decrypted)} bytes")

	out_path = path + ".decrypted.bin"
	with open(out_path, "wb") as f:
    	f.write(decrypted)
	print(f"[+] decrypted shellcode written to {out_path}")

if __name__ == "__main__":
	if len(sys.argv) != 2:
    	print(f"usage: {sys.argv[0]} <saferat_loader.exe>")
    	sys.exit(1)
	extract(sys.argv[1])