Analyzing a Fully Undetectable (FUD) macOS Backdoor
macOS backdoor using process name spoofing, DYLD injection, & C2 commands

With macOS becoming a more attractive target for cyber threats, malware authors are constantly innovating to evade detection. In this blog, we analyze a macOS malware—Tiny FUD, a trojan leveraging process name manipulation, DYLD injection, and C2-based command execution. The blog reverse-engineers the binary, extract IOCs, and understand its capabilities.
The term FUD (Fully Undetectable) indicates that the malware is designed to bypass antivirus and security tools, making it particularly dangerous.
Tiny FUD #trojan for #macOS
— Bruce Ketta (@bruce_k3tta) January 17, 2025
I love how it changes its process name to some legit stuff (taken from an hardcoded list) to hide
At first sight, it might use DYLD_INSERT_LIBRARIES injection technique to load ShoveService.framework and exploit CVE-2022-26712
MD5 + C2 ⏬ pic.twitter.com/TnOCOvieez
Static Analysis with DIE
To better understand the binary's properties, Detect It Easy (DIE) was used for static analysis. These details confirm that the malware was built using modern macOS development tools, likely with Apple's Xcode environment. The presence of codesign
suggests that the binary was signed, possibly to evade macOS's built-in security mechanisms such as Gatekeeper and System Integrity Protection (SIP). Understanding these attributes helps in identifying the malware’s origin and possible evasion techniques.

Dissecting the Functions
Each function below has been examined to understand its role in the malware's execution and stealth mechanisms.
main()
Within the main function, we find the hardcoded C2 IP address and port 9999, which the binary uses to establish a connection.
69[.]197[.]175[.]10:9999

mask_process_name()
To blend in with legitimate system processes, the FUD binary randomly selects one of the following names, found in the self_sign()
function:
com.apple.Webkit.Networking
com.apple.Safari.helper
com.apple.security.agent
com.apple.system.events
The name change is done using osascript, making it difficult to spot in Activity Monitor. This is handled within the _mask_process_name()
function, which ensures the malware remains unnoticeable.
osascript -e 'tell application "System Events" to set name of first process whose unix id is %d to "%s"' 2>/dev/null

self_sign()
The binary starts execution by accepting two command-line arguments: an IP address and port. If none are provided, it defaults to 69[.]197[.]175[.]10:9999
. After setting these values, it resigns itself with added runtime entitlements by calling _self_sign()
, enabling:
- DYLD environment variables (for dynamic library injection)
- Executable page protection disablement (to modify memory protections)
The _self_sign()
function not only generates this XML-based entitlements file but also pulls a random process name from the list identified in mask_process_name()
. This ensures that when the malware resigns itself, it simultaneously adopts a legitimate-sounding Apple service name, further enhancing its stealth capabilities.

The code sign entitlements are saved temporarily as .ent.plist
in /tmp/
.
codesign --entitlements /tmp/.ent.plist --force --deep --sign - "%s" 2>/dev/null

The _self_sign()
function generates this XML-based entitlements file, which defines the security permissions the malware grants itself. Additionally, _self_sign()
pulls a predefined process name from this entitlements list, ensuring that the malware resigns itself with a legitimate-looking process name. This allows it to blend in with system processes more effectively, further improving its stealth capabilities.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.get-task-allow</key>
<true/>
<key>com.apple.security.cs.debugger</key>
<true/>
</dict>
/plist>

hide_file()
The FUD binary employs a stealth mechanism to remove itself from Finder view, although the file remains accessible via Terminal. The function _hide_file()
executes the following command:
SetFile -a V "%s"
This prevents the malware from being easily discovered by users. The -a
flag is used to set file attributes, and V
specifically marks the file as invisible in Finder

send_heartbeat()
Every 5 minutes, the malware captures a screenshot and sends it to the C2 server. This behavior is likely part of data enrichment for beaconing, enabling operators to gather additional context from infected machines. The heartbeat mechanism is controlled by _send_heartbeat()
, which tracks timestamps using _time(nullptr)
.

The screenshot is temporarily stored as a PNG file at /tmp/.cache_%d.png
before being transmitted.

execute_command()
The malware receives commands from the C2 server and executes them. However, it contains a hardcoded "exit" command that, when received, terminates the connection.

send_stealth_beacon()
The send_stealth_beacon()
function in the FUD binary is responsible for covertly establishing communication with the C2 server while avoiding detection. It begins by generating a unique UUID for tracking infected machines and selects a randomized User-Agent string to blend into normal web traffic. The beacon message is then formatted and sent using chunked transfer encoding, making network traffic harder to detect. To evade rate-based anomaly detection, the function includes a small execution delay (_usleep(0x186a0)
) before collecting additional system information such as username, hostname, and kernel version.
Finally, a stack canary check ensures no buffer overflows have tampered with execution. These techniques help the malware remain stealthy while maintaining persistent C2 communication.


cleanup_and_exit()
The _cleanup_and_exit()
function in the FUD binary is designed to remove traces of the malware before shutting down. First, it retrieves its process ID (PID) using _getpid()
and its process group ID (PGID) with _getpgid()
. If the malware is running as part of an XPC service (a macOS interprocess communication feature), it removes the XPC_SERVICE_NAME
environment variable to hide its presence. It also calls _unsetenv("DYLD_INSERT_LIBRARIES")
to eliminate injected dynamic libraries, ensuring that no traces remain after termination.
To forcefully shut itself down, the malware sends SIGKILL (signal 9) to its own process using _kill(rax, 9)
, where rax
holds its PID. This ensures instant and irreversible termination, preventing security tools from analyzing its memory. Additionally, _kill(0 - rax_1, 9)
is used to terminate all child processes, ensuring no remnants of the malware remain active.
Before fully exiting, it calls _mask_process()
one last time, likely to obfuscate any remaining traces. Finally, _exit(1)
is executed, completing the malware’s stealthy self-destruction.

C2 IP: OSINT Analysis
Using Validin, we found that the IP is rated as malicious and has been linked to recent domains related to this campaign.


IOC
SHA256: d64e2688344c685c4156819156bdb15630d1168314b21c919eee5540b1beb54a=====================================================
Domain Name:
xxobox.com
equitymarket.uk
movie.aspisdata.com
Yara
rule TinyFUD_MacOS_Backdoor
{
meta:
description = "Detects FUD macOS backdoor using process names, file paths, and network indicators"
author = "Tonmoy Jitu"
date = "2024-01-30"
strings:
$process_names = "com.apple.Webkit.Networking" nocase
$process_names2 = "com.apple.Safari.helper" nocase
$process_names3 = "com.apple.security.agent" nocase
$process_names4 = "com.apple.system.events" nocase
$osascript_command = "osascript -e 'tell application \"System Events\" to set name of first process" nocase
$codesign_command = "codesign --entitlements /tmp/.ent.plist --force --deep --sign -" nocase
$setfile_command = "SetFile -a V " nocase
$dyld_insert = "DYLD_INSERT_LIBRARIES" nocase
$c2_ip = "69.197.175.10"
$temp_cache = "/tmp/.cache_" nocase
condition:
any of ($process_names*) or
any of ($osascript_command, $codesign_command, $setfile_command, $dyld_insert) or
$c2_ip or
$temp_cache
}
Reference:
1/11: Another day, another #backdoor! Our team started digging deep into the #macOS #malware sample (yet undetected on VirusTotal) shared by @bruce_k3tta, and surprisingly found out that it has the ability to execute arbitrary commands sent from C2 and capture screenshots. pic.twitter.com/Rru6zwgSEO
— Moonlock Lab (@moonlock_lab) January 23, 2025