Executive Summary
This report presents a static analysis of a macOS malware sample distributed under the guise of a Homebrew package. The sample was identified as AMOS (Atomic macOS Stealer), a commercial infostealer sold as a Malware-as-a-Service (MaaS) offering targeting macOS users.
The binary is a Mach-O universal executable supporting both Intel (x86_64) and Apple Silicon (arm64) architectures. It is not packed, and its entropy profile is consistent with a standard compiled binary. String obfuscation is achieved through a rolling XOR cipher applied to all sensitive strings, using a hardcoded 27-byte key. Full recovery of the decryption routine via Ghidra enabled bulk decryption of all obfuscated strings.
Key findings:
http://85.217.222.185 (two endpoints: /static.php, /index.php)launchctl load -wosascript for Finder file manipulationsystem_profiler, screencapture, and ps auxxattr -d com.apple.quarantineru_RU, uk_UA, kk_KZ, be_BY, hy_AM), consistent with Russian-aligned threat actor conventionsSample Metadata
| Analysis Attribute | Value |
|---|---|
| MD5 | cad2cd91df26c92ecf246c01276f6c2f |
| SHA-1 | 2fb3802d419afaf7a883134271dcd4deee5957ea |
| SHA-256 | ce6dc065752cb46437ce6a200e29d5dbd96473daa72dcce07aa493b821a99ba9 |
| Vhash | 4e195dde1dbe61025733bcfa4a44b0ca |
| SSDEEP | 6144:Y0M1UpbCzubRTQ/o5U4sqDNpOOJWGVWoFI/IY:IIuiRTQ/o5U4sypHkoFI/I |
| TLSH | T160749E06EF1C9C16D0C4803C9F8FD662D116F4B42626A33B3F02566DBE69AD47A1DB27 |
| Symhash | ad0a33bb3a714a339242a81c8ecce41d |
| File Type | Mach-O executable (mac, macho) |
| Magic | Mach-O universal binary with 2 architectures: • x86_64: Mach-O 64-bit x86_64 executable, flags: <NOUNDEFS, DYLDLINK, TWOLEVEL, PIE> • arm64: Mach-O 64-bit arm64 executable, flags: <NOUNDEFS, DYLDLINK, TWOLEVEL, PIE> |
| TrID | • Mac OS X Mach-O universal Dynamically linked shared Library (82.2%) • Mac OS X Universal Binary (generic) (17.7%) |
| Magika | MACHO |
| File Size | 361.53 KB (370,208 bytes) |
DIE
The sample binary uses the Mach-O universal format to achieve cross-architecture compatibility on macOS, packaging two distinct slices within a single payload: a 64-bit Intel (x86_64) slice and a 64-bit Apple Silicon (arm64) slice.
Entropy
The sample is not packed.
A heuristic scan confirms the binary was signed using Apple's codesign utility.
Segments
| Segment Name | Virtual Address | Virtual Size | Offset | Size | Sections |
|---|---|---|---|---|---|
__PAGEZERO | 0x0 | 0x100000000 | 0x0 | 0x0 | 0 |
__TEXT | 0x100000000 | 0x20000 | 0x0 | 0x20000 | 7 |
__DATA | 0x100020000 | 0x4000 | 0x20000 | 0x4000 | 6 |
__LINKEDIT | 0x100024000 | 0x8000 | 0x24000 | 0x66a0 | 0 |
Shared Libraries
| Library / Framework | Full System Path | Purpose / Relevance to Analysis |
|---|---|---|
| CoreFoundation | /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation | Standard macOS framework providing low-level data management, system object handling, and core hardware/OS interaction. |
| CoreServices | /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices | Provides essential system identity, file management, and core security functions (often used for process handling and OS interaction). |
| libSystem.B.dylib | /usr/lib/libSystem.B.dylib | The fundamental system library for macOS. Handles core APIs, kernel system calls (libc, libpthread), and basic process execution. |
| libc++.1.dylib | /usr/lib/libc++.1.dylib | Standard C++ library. Indicates that parts of the binary were compiled using C++ features rather than strict C or Objective-C. |
| libcurl.4.dylib | /usr/lib/libcurl.4.dylib | High Relevance: Multiprotocol file transfer library. Indicates network capabilities (HTTP/HTTPS), strongly suggesting C2 communication, data exfiltration, or payload delivery. |
Strings
Extraction
The Mach-O universal format contains both the Intel and ARM slices within a single file. The x86_64 slice was extracted using DIE's built-in unpack functionality: after importing the sample, selecting Unpack produces the individual architecture binaries for independent analysis.
Ghidra Analysis
The x86_64 slice was loaded into Ghidra for static analysis.
Within the defined strings view, the string 7M43mJx9I0GwjslSA2oKSgkqsUo was identified.
Cross-referencing this string reveals usage across multiple functions.
s_M43mJx9I0GwjslSA2oKSgkqsUo_10001d6c5 XREF[5,16]: FUN_10001a189:10001a19e(*),
s_43mJx9I0GwjslSA2oKSgkqsUo_10001d6c6 FUN_10001a189:10001a1b6(R),
s_3mJx9I0GwjslSA2oKSgkqsUo_10001d6c7 FUN_10001a66c:10001a71b(*),
s_7M43mJx9I0GwjslSA2oKSgkqsUo_10001d6c4 FUN_10001a780:10001a7cc(*),
FUN_10001a8fd:10001a9a8(*),
FUN_10001a08c:10001a0ca(*),
FUN_10001a262:10001a2fa(*),
FUN_10001a405:10001a463(*),
FUN_10001a405:10001a4c3(*),
FUN_10001a405:10001a57a(*),
FUN_10001a66c:10001a6a8(*),
FUN_10001a66c:10001a722(R),
FUN_10001a66c:10001a722(R),
FUN_10001a780:10001a7d3(R),
FUN_10001a780:10001a7d3(R),
FUN_10001a8fd:10001a945(*),
FUN_10001a8fd:10001a9af(R),
FUN_10001a8fd:10001a9af(R),
FUN_10001a8fd:10001a9fa(R),
FUN_10001a8fd:10001a9fa(R)
10001d6c4 37 4d 34 ds "7M43mJx9I0GwjslSA2oKSgkqsUo"
33 6d 4a
78 39 49
Examining the first cross-reference leads to FUN_10001a189.
FUN10001a189
The string is used as the key in a XOR operation, evidenced by the ^ operator and modulus cycling:
*(byte *)(param_1 + uVar1) ^ "7M43mJx9I0GwjslSA2oKSgkqsUo"[uVar1 % 0x1b];
void FUN_10001a189(long param_1,ulong param_2)
{
ulong uVar1;
long lVar2;
if (param_2 == 0) {
lVar2 = -1;
}
else {
uVar1 = 0;
do {
*(byte *)(param_1 + uVar1) =
*(byte *)(param_1 + uVar1) ^ "7M43mJx9I0GwjslSA2oKSgkqsUo"[uVar1 % 0x1b];
uVar1 = uVar1 + 1;
} while (param_2 != uVar1);
lVar2 = param_2 - 1;
}
*(undefined1 *)(param_1 + lVar2) = 0;
return;
}
param_1 & param_2: param_1 is a pointer to the encrypted buffer in memory; param_2 is the buffer length."7M43mJx9I0GwjslSA2oKSgkqsUo", exactly 27 bytes (hex 0x1b).do...while): The routine steps through the encrypted buffer byte-by-byte. Each byte is XOR'd against the key at position uVar1 % 0x1b, cycling back to the start of the key once its length is exceeded.The function graph confirms the looping nature of the operation:
LAB_10001a1a5
a1a5 MOV RAX,RCX
a1a8 MUL R8
a1ab SHR RDX,0x4
a1af IMUL RAX,RDX,-0x1b
a1b3 ADD RAX,R9
a1b6 MOV AL,byte ptr [RCX + RAX*0x1
a1b9 XOR byte ptr [RDI + RCX*0x1],AL
a1bc INC RCX
a1bf CMP RSI,RCX
a1c2 JNZ LAB_10001a1a5
The assembly confirms an iterative byte transformation consistent with the rolling XOR cipher identified in the decompilation.
To determine what data is passed to this function, the call graph was examined.
A Python script was written to emulate the decryption routine and recover plaintext strings. Encrypted byte sequences were extracted from the binary using Ghidra's "Copy Special → Python Byte String" feature.
Examining the first caller, FUN_10000386c, shows that local_470 is passed as the target buffer:
FUN_10001a189(local_470,5);
pcVar3 = _getenv(local_470);
| Reference / Variable | Value / Code Implementation | Analysis / Triage Purpose |
|---|---|---|
| Target Buffer | local_470 | 5-byte stack frame allocated for dynamic key generation. |
| Obfuscated Key Data | "\x7f\x02yv" | Hardcoded encrypted payload copied via builtin_strncpy. |
| Deobfuscation Routine | FUN_10001a189(local_470, 5); | Invokes the multi-byte rolling XOR stream cipher over the target boundary. |
| Downstream Subsystem API | _getenv(local_470); | Queries the host OS context using the dynamically restored memory buffer. |
The buffer local_470 was exported from Ghidra as a Python byte string: \x76\x79\x02\x7f
Python Script
The following script emulates the rolling XOR decryption loop from FUN_10001a189:
# --- Malicious String Decryption Script Implementation ---
# This script emulates the rolling XOR deobfuscation loop found in FUN_10001a189.
# It reverses the static obfuscation layer protecting runtime system indicators.
enc_key = "7M43mJx9I0GwjslSA2oKSgkqsUo"
# Memory positioning array extracted from the binary.
# Reordered sequentially to match the stack layout structure: \x7f, \x02, \x79, \x76
enc_bytes = b'\x7f\x02\x79\x76'
# Pre-allocated memory space to simulate the local destination buffer frame
dec_bytes = bytearray(len(enc_bytes))
def decrypt(target_bytes):
key_len = 0x1b # Rolling cipher loop boundary restriction (27-byte key length)
for i in range(len(target_bytes)):
# Replicates the Ghidra decompilation bitwise XOR instruction:
# *(byte *)(param_1 + uVar1) ^ "7M43mJx9I0GwjslSA2oKSgkqsUo"[uVar1 % 0x1b]
dec_bytes[i] = target_bytes[i] ^ ord(enc_key[i % key_len])
return dec_bytes
print(decrypt(enc_bytes))
Output:
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample [1]> python3 dec.py
bytearray(b'A46L')
The result A46L reflects the byte reordering in the stack layout; the resolved value passed to _getenv is HOME, confirming the malware queries the user's home directory path at runtime.
Examining the full list of incoming references to FUN_10001a189 reveals that a large number of functions pass data through this decryption routine, indicating that string obfuscation is applied broadly throughout the binary.
Each of these functions is a candidate for string extraction and decryption.
FUN100003a37
void FUN_100003a37(undefined8 param_1,undefined8 param_2)
{
char local_8a8 [2048];
char local_a8 [120];
long local_30;
local_30 = *(long *)PTR____stack_chk_guard_100020030;
_memcpy(local_a8,&DAT_10001b080,0x6e);
FUN_10001a189(local_a8,0x6e);
_snprintf(local_8a8,0x800,local_a8,param_1,param_2);
FUN_100019f6a(local_8a8,0);
if (*(long *)PTR____stack_chk_guard_100020030 == local_30) {
return;
}
/* WARNING: Subroutine does not return */
___stack_chk_fail();
}
The local buffer local_a8 is the decryption target, with the data at DAT_10001b080 copied into it immediately before the decryption call.
Examining DAT_10001b080 confirms it is an obfuscated data string. The bytes were extracted as a Python byte string:
b'\x58\x3e\x55\x40\x0e\x38\x11\x49\x3d\x0c\x7b\x32\x25\x37\x66\x27\x24\x5e\x03\x6b\x32\x17\x1b\x1d\x1a\x36\x0e\x43\x24\x5b\x5d\x4d\x68\x3e\x50\x27\x54\x22\x05\x48\x79\x01\x3c\x37\x57\x4f\x1b\x1c\x34\x22\x29\x53\x33\x06\x5b\x28\x14\x11\x48\x39\x5a\x19\x3d\x5f\x67\x27\x25\x20\x25\x0b\x61\x54\x06\x27\x36\x47\x49\x54\x00\x77\x4f\x40\x24\x40\x5b\x4d\x38\x1d\x49\x25\x51\x24\x1e\x04\x14\x66\x36\x2f\x56\x4f\x3f\x36\x0b\x07\x7b\x36\x1a\x29\x3d\x00'
Decryption produces:
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample> python3 dec.py
osascript<<EOD
tell application "Finder"
move POSIX file "%s" to POSIX file "%s" with replacing
end tell
EOF
M
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample>
This reveals an AppleScript template that instructs the Finder application to move one file to a specified destination with replacement. This is the file relocation primitive used by the malware's file management subsystem.
FUN100003ad3
void FUN_100003ad3(undefined8 param_1)
{
char local_478 [1024];
char local_78 [80];
long local_28;
local_28 = *(long *)PTR____stack_chk_guard_100020030;
_memcpy(local_78,
"X>U@\x0e8\x11I=\f{2%7f\'$^\x03k2\x17\x1b\x1d\x1a6\x0eC$[]Mh>P\'T\"\x05Hy\b6-W\x1b.s7$\":\ rOQ$XVMh]Jk:\"\x19\x0eS\x186-^e\x0e\x1c#a"
,0x4e);
FUN_10001a189(local_78,0x4e);
_snprintf(local_478,0x400,local_78,param_1);
FUN_100019f6a(local_478,0);
if (*(long *)PTR____stack_chk_guard_100020030 == local_28) {
return;
}
/* WARNING: Subroutine does not return */
___stack_chk_fail();
}
The string defined in local_78 is passed to FUN_10001a189 as the decryption target. The bytes were extracted as a Python byte string:
b'\x58\x3e\x55\x40\x0e\x38\x11\x49\x3d\x0c\x7b\x32\x25\x37\x66\x27\x24\x5e\x03\x6b\x32\x17\x1b\x1d\x1a\x36\x0e\x43\x24\x5b\x5d\x4d\x68\x3e\x50\x27\x54\x22\x05\x48\x79\x08\x36\x2d\x57\x1b\x2e\x73\x37\x24\x22\x3a\x0d\x4f\x51\x24\x58\x56\x4d\x68\x5d\x4a\x6b\x3a\x22\x19\x0e\x53\x18\x36\x2d\x5e\x65\x0e\x1c\x23\x61\x00\x51\x22\x58\x57\x08\x38\x00\x17\x22\x52\x13\x0b\x25\x14\x5d\x2c\x42\x00\x56\x21\x5d\x52\x1e\x6a\x1e\x50\x25\x55\x00\x17\x22\x52\x13\x1e\x3e\x19\x4b\x3d\x45\x37\x57\x0e\x1a\x1f\x38\x6d\x00\x17\x22\x52\x13\x0c\x3a\x08\x55\x20\x53\x26\x03\x03\x1c\x02\x73\x27\x5b\x03\x2e\x00\x64\x04\x6e\x76\x41\x6a\x00'
Decryption produces:
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample> python3 dec.py
osascript<<EOD
tell application "Finder"
delete POSIX file "%s"
end tell
EOD
q"w7`E
3zh**BS*F1l`o=U9y;T&Ux'-SS3
yplT>A%M@kQy&u<N7/o9_bJGn+2
A second AppleScript template was recovered, instructing the Finder application to delete a specified file. This is the file deletion primitive, likely used to remove staging files or evidence after exfiltration.
At this stage, FUN_10001a189 was renamed to FUN_DECRYPT to reflect its confirmed role.
Notable in this AMOS variant is the placement of the decryption key within the binary. Adjacent strings in the __cstring section appear similarly obfuscated.
These obfuscated strings can be systematically decrypted using the recovered key. Taking the first candidate:
b'\x44\x34\x47\x47\x08\x27\x56\x4d\x31\x44\x00'
Decryption produces:
system.txtG
Additional strings decrypted from the __cstring section include BASECFG|%s|%ss and related format strings. Further candidates reside in the __const section.
Continuing the decryption process, a string beginning with _9@CWeW was identified in the binary:
s_HOME_10001cd72 XREF[1]: FUN_1000043f3:100004541(*)
10001cd72 48 4f 4d ds "HOME"
45 00
10001cd77 18 29 51 ds 18h,")QEB?\\nX'T(",1Ah
45 42 3f
0a 58 27
10001cd84 74 22 5a ds "t\\"ZG\\b$\\f",14h,"\\f^$",18h,0Eh,1Ah,02h,"4{",1
47 08 24
0c 14 0c
10001cd9d 5f 39 40 ds "_9@CWeW",01h,"|",1Eh,"uF]]^as",1Ch,"^sfH",18h
43 57 65
57 01 7c
Extracting as a Python byte string:
b'\x5f\x39\x40\x43\x57\x65\x57\x01\x7c\x1e\x75\x46\x5d\x5d\x5e\x61\x73\x1c\x5e\x73\x66\x48\x18\x05\x12\x21\x06\x54\x63\x44\x5b\x1d\x00'
Decryption yields the C2 server address:
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample> python3 dec.py
http://85.217.222.185/static.php
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample>
C2 Server
http://85.217.222.185/static.php
The decryption script was extended to process all identified encrypted string references in bulk:
KEY = b"7M43mJx9I0GwjslSA2oKSgkqsUo"
strings = [ (0x10001cc2e, b'\x7f\x02yv'), (0x10001cc39, b'\x58\x3e\x55\x40\x0e\x38\x11\x49\x3d\x0c\x7b\x32\x25\x37\x66\x27\x24\x5e\x03\x6b\x32\x17\x1b\x1d\x1a\x36\x0e\x43\x24\x5b\x5d\x4d\x68\x3e\x50\x27\x54\x22\x05\x48\x79\x08\x36\x2d\x57\x1b\x2e\x73\x37\x24\x22\x3a\x0d\x4f\x51\x24\x58\x56\x4d\x68\x5d\x4a\x6b\x3a\x22\x19\x0e\x53\x18\x36\x2d\x5e\x65\x0e\x1c\x23\x61'), (0x10001cc87, b'\x51\x22\x58\x57\x08\x38'), (0x10001cc8e, b'\x17\x22\x52\x13\x0b\x25\x14\x5d\x2c\x42'), (0x10001cc99, b'\x56\x21\x5d\x52\x1e\x6a\x1e\x50\x25\x55'), (0x10001cca4, b'\x17\x22\x52\x13\x1e\x3e\x19\x4b\x3d\x45\x37\x57\x0e\x1a\x1f\x38\x6d'), (0x10001ccb6, b'\x17\x22\x52\x13\x0c\x3a\x08\x55\x20\x53\x26\x03\x03\x1c\x02\x73\x27\x5b\x03\x2e'), (0x10001cccb, b'\x64\x04\x6e\x76\x41\x6a'), (0x10001ccd7, b'\x7b\x24\x56\x41\x0c\x38\x01\x16\x05\x51\x32\x19\x09\x1b\x2d\x34\x24\x5c\x1b\x38'), (0x10001ccec, b'\x12\x3e\x1b\x1d\x01\x25\x1b\x58\x25\x1d\x62\x04'), (0x10001cd0d, b'\x5b\x2c\x41\x5d\x0e\x22\x1b\x4d\x25\x10\x2b\x18\x0b\x17\x4c\x7e\x36\x12\x4d\x6e\x20\x45'), (0x10001cd24, b'\x12\x3e\x1b\x7f\x04\x28\x0a\x58\x3b\x49\x68\x3b\x0b\x06\x02\x30\x29\x73\x08\x2e\x3d\x13\x18\x5e\x56\x26'), (0x10001cd3f, b'\x58\x3d\x51\x5d\x4d\x67\x19\x19\x66\x52\x2e\x19\x45\x11\x0d\x20\x29\x12\x42\x66\x32\x15\x0c\x02\x53\x78\x0c\x17\x6f\x47\x5f\x08\x2f\x08\x19\x7a\x0b\x67\x05\x07\x53\x41\x21\x27\x12\x48\x6e\x20\x40\x49'), (0x10001cd77, b'\x18\x29\x51\x45\x42\x3f\x0a\x58\x27\x54\x28\x1a'), (0x10001cd84, b'\x74\x22\x5a\x47\x08\x24\x0c\x14\x0c\x5e\x24\x18\x0e\x1a\x02\x34\x7b\x12\x0d\x22\x3d\x06\x19\x08'), (0x10001cd9d, b'\x5f\x39\x40\x43\x57\x65\x57\x01\x7c\x1e\x75\x46\x5d\x5d\x5e\x61\x73\x1c\x5e\x73\x66\x48\x18\x05\x12\x21\x06\x54\x63\x44\x5b\x1d'), (0x10001cdc0, b'\x79\x0b\x60\x58\x19\x18\x35\x6e'), (0x10001cdd5, b'\x67\x3f\x5b\x57\x18\x29\x0c\x6f\x2c\x42\x34\x1e\x05\x1d\x56'), (0x10001ce02, b'\x58\x3e\x55\x40\x0e\x38\x11\x49\x3d\x10\x6a\x12\x4a\x54\x1f\x36\x35\x12\x19\x24\x3f\x12\x06\x14\x53\x3a\x1a\x43\x3d\x41\x47\x4d\x27\x0d\x4d\x2c\x54\x67\x03\x18\x06\x09\x74'), (0x10001ce2e, b'\x58\x3e\x55\x40\x0e\x38\x11\x49\x3d\x10\x6a\x12\x4a\x54\x1f\x36\x35\x12\x19\x24\x3f\x12\x06\x14\x53\x3a\x1a\x43\x3d\x41\x47\x4d\x27\x0d\x4d\x2c\x54\x67\x11\x0b\x1f\x1f\x36\x66'), (0x10001ce7c, b'\x12\x3e\x1b\x43\x1a\x64\x1c\x58\x3d'), (0x10001ce86, b'\x7e\x03\x7d\x67'), (0x10001ce91, b'\x45\x28\x56\x5c\x02\x3e\x58\x14\x25'), (0x10001ce9b, b'\x5f\x34\x6b\x72\x20\x71\x1a\x5c\x16\x72\x1e\x4c\x01\x18\x33\x18\x1b\x09\x1d\x3e\x0c\x35\x3e\x4a\x06\x3e\x30\x62\x0c\x0f'), (0x10001ceba, b'\x4f\x2c\x40\x47\x1f\x6a\x55\x5d\x69\x53\x28\x1a\x44\x12\x1c\x23\x2d\x57\x41\x3a\x26\x06\x19\x10\x1d\x21\x06\x59\x28\x14\x11\x48\x39\x5a'), (0x10001cee8, b'\x5f\x39\x40\x43\x57\x65\x57\x01\x7c\x1e\x75\x46\x5d\x5d\x5e\x61\x73\x1c\x5e\x73\x66\x48\x02\x1f\x17\x30\x17\x19\x3d\x5c\x43'), (0x10001cf26, b'\x01\x7d\x51\x51\x08\x7f\x1a\x0f\x64\x55\x7f\x14\x58\x5e\x58\x32\x73\x03\x42\x29\x36\x06\x0a\x5c\x47\x67\x0b\x0e\x2c\x05\x51\x58\x7f\x4b\x0f\x7a'), (0x10001cf56, b'\x44\x2e\x46\x56\x08\x24\x1b\x58\x39\x44\x32\x05\x0f\x53\x41\x2b\x61\x1f\x1b\x6b\x76\x14\x4b\x53\x56\x26\x4d'), (0x10001cf72, b'\x44\x34\x47\x47\x08\x27\x27\x49\x3b\x5f\x21\x1e\x06\x16\x1e\x73\x12\x62\x27\x2a\x21\x03\x1c\x10\x01\x30\x2b\x56\x39\x55\x67\x14\x3a\x1d'), (0x10001cf95, b'\x7f\x2c\x46\x57\x1a\x2b\x0a\x5c\x73'), (0x10001cf9f, b'\x7f\x2c\x46\x57\x1a\x2b\x0a\x5c\x69\x7f\x31\x12\x18\x05\x05\x36\x36\x08'), (0x10001cfb2, b'\x47\x3e\x14\x52\x18\x32'), (0x10001cffb, b'\x19\x09\x67\x6c\x3e\x3e\x17\x4b\x2c'), (0x10001d015, b'\x60\x28\x56\x13\x29\x2b\x0c\x58'), (0x10001d01e, b'\x7b\x22\x57\x52\x01\x6a\x3d\x41\x3d\x55\x29\x04\x03\x1c\x02\x73\x12\x57\x1b\x3f\x3a\x09\x0c\x02'), (0x10001d037, b'\x7e\x23\x50\x56\x15\x2f\x1c\x7d\x0b'), (0x10001d041, b'\x63\x02\x60\x63'), (0x10001d069, b'\x54\x22\x5b\x58\x04\x2f\x0b\x17\x3a\x41\x2b\x1e\x1e\x16'), (0x10001d078, b'\x47\x21\x55\x50\x08\x39\x56\x4a\x38\x5c\x2e\x03\x0f'), (0x10001d086, b'\x12\x3e\x1b\x40\x19\x25\x0a\x58\x2e\x55\x68\x13\x0f\x15\x0d\x26\x2d\x46\x40\x26\x3c\x1d\x46\x14\x0b\x21\x0a\x59\x3e\x5d\x5c\x03\x61\x53\x12\x6c\x43\x19\x02\x19\x16\x1e\x10\x2e\x5c\x1b\x2e\x2b\x13\x22\x15\x4e\x61\x5d\x0e\x79\x0d\x05\x5a\x78\x41\x0c'), (0x10001d0c5, b'\x12\x3e\x1b\x43\x1f\x2f\x1e\x4a\x67\x5a\x34'), (0x10001d16c, b'\x71\x24\x58\x56\x1e'), (0x10001d172, b'\x45\x28\x57\x56\x03\x3e\x0b\x5c\x3b\x46\x22\x05\x19\x5d\x14\x3e\x2d'), (0x10001d184, b'\x12\x3e\x1b\x1d\x0e\x25\x16\x5f\x20\x57\x68\x11\x03\x1f\x09\x29\x28\x5e\x03\x2a\x7c\x42\x18'), (0x10001d19c, b'\x71\x19\x64\x1c\x2b\x23\x14\x5c\x13\x59\x2b\x1b\x0b\x5c\x49\x20'), (0x10001d1ad, b'\x5b\x22\x53\x5a\x03\x3f\x0b\x5c\x3b\x43\x69\x01\x0e\x15'), (0x10001d1d3, b'\x44\x2e\x46\x56\x08\x24\x0b\x51\x26\x44\x69\x1d\x1a\x14'), (0x10001d1e2, b'\x74\x22\x5b\x58\x04\x2f\x0b\x17\x2b\x59\x29\x16\x18\x0a\x0f\x3c\x2e\x59\x06\x2e\x20'), (0x10001d1f8, b'\x74\x22\x5b\x58\x04\x2f\x0b\x17\x39\x5c\x2e\x04\x1e'), (0x10001d206, b'\x71\x22\x46\x5e\x4d\x1c\x19\x55\x3c\x55\x34'), (0x10001d212, b'\x7f\x24\x47\x47\x02\x38\x01\x17\x2d\x52'), (0x10001d21d, b'\x12\x3e\x1b\x7f\x04\x28\x0a\x58\x3b\x49\x68\x34\x05\x1c\x07\x3a\x24\x41\x40\x6e\x20'), (0x10001d233, b'\x75\x3f\x5b\x44\x1e\x2f\x0a\x4a\x66\x63\x26\x11\x0b\x01\x05'), (0x10001d243, b'\x7b\x24\x56\x41\x0c\x38\x01\x16\x1a\x51\x21\x16\x18\x1a'), (0x10001d252, b'\x7c\x28\x4d\x50\x05\x2b\x11\x57\x3a'), (0x10001d25c, b'\x12\x3e\x1b\x7f\x04\x28\x0a\x58\x3b\x49\x68\x34\x05\x1d\x18\x32\x28\x5c\x0a\x39\x20\x48\x08\x1e\x1e\x7b\x0e\x47\x3d\x58\x56\x43\x04\x17\x4d\x2c\x43\x68\x33\x0b\x07\x0d\x7c\x0d\x5b\x0d\x39\x32\x15\x12\x5e\x3d\x3a\x1b\x52\x3e'), (0x10001d295, b'\x79\x22\x40\x56\x1e'), (0x10001d29b, b'\x73\x24\x47\x50\x02\x38\x1c\x16\x05\x5f\x24\x16\x06\x53\x3f\x27\x2e\x40\x0e\x2c\x36'), (0x10001d2b1, b'\x5c\x28\x4d\x6c\x09\x2b\x0c\x58\x3a'), (0x10001d2bb, b'\x63\x28\x58\x56\x0a\x38\x19\x54'), (0x10001d2c4, b'\x12\x3e\x1b\x1d\x17\x39\x10\x66\x21\x59\x34\x03\x05\x01\x15'), (0x10001d2d4, b'\x4d\x3e\x5c\x6c\x05\x23\x0b\x4d\x26\x42\x3e'), (0x10001d2e0, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0c\x44\x2f\x12\x18\x16\x19\x3e'), (0x10001d2f1, b'\x12\x3e\x1b\x7f\x04\x28\x0a\x58\x3b\x49\x68\x32\x1e\x1b\x09\x21\x24\x47\x02\x64\x38\x02\x12\x02\x07\x3a\x1d\x52'), (0x10001d30e, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0c\x5c\x22\x14\x1e\x01\x19\x3e'), (0x10001d31f, b'\x12\x3e\x1b\x1d\x08\x26\x1d\x5a\x3d\x42\x32\x1a\x45\x04\x0d\x3f\x2d\x57\x1b\x38'), (0x10001d334, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0c\x5c\x22\x14\x1e\x01\x19\x3e\x6c\x7e\x3b\x08'), (0x10001d349, b'\x12\x3e\x1b\x1d\x08\x26\x1d\x5a\x3d\x42\x32\x1a\x47\x1f\x18\x30\x6e\x45\x0e\x27\x3f\x02\x1f\x02'), (0x10001d362, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0c\x5c\x22\x14\x1e\x01\x03\x3d\x02\x53\x1c\x23'), (0x10001d377, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x04\x5f\x29\x12\x18\x1c'), (0x10001d386, b'\x12\x3e\x1b\x7e\x02\x24\x1d\x4b\x26\x1f\x30\x16\x06\x1f\x09\x27\x32'), (0x10001d398, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x03\x51\x3f\x0f\x45\x3f\x03\x30\x20\x5e\x4f\x18\x27\x08\x19\x10\x14\x30'), (0x10001d3b3, b'\x12\x3e\x1b\x16\x1e\x65\x32\x58\x31\x48\x68\x3b\x05\x10\x0d\x3f\x61\x61\x1b\x24\x21\x06\x0c\x14'), (0x10001d3cc, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0e\x45\x26\x05\x0e\x12\x43\x1f\x2e\x51\x0e\x27\x73\x34\x1f\x1e\x01\x34\x08\x52'), (0x10001d3e9, b'\x12\x3e\x1b\x16\x1e\x65\x3f\x4c\x28\x42\x23\x16\x45\x3f\x03\x30\x20\x5e\x4f\x18\x27\x08\x19\x10\x14\x30'), (0x10001d404, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x28\x44\x28\x1a\x03\x10\x43\x1f\x2e\x51\x0e\x27\x73\x34\x1f\x1e\x01\x34\x08\x52'), (0x10001d421, b'\x12\x3e\x1b\x16\x1e\x65\x19\x4d\x26\x5d\x2e\x14\x45\x3f\x03\x30\x20\x5e\x4f\x18\x27\x08\x19\x10\x14\x30'), (0x10001d43c, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0b\x59\x33\x27\x0b\x0a\x43\x1f\x2e\x51\x0e\x27\x73\x34\x1f\x1e\x01\x34\x08\x52'), (0x10001d459, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x04\x49\x0a\x18\x04\x16\x1e\x3c'), (0x10001d46a, b'\x12\x3e\x1b\x16\x1e\x65\x35\x40\x04\x5f\x29\x12\x18\x1c'), (0x10001d479, b'\x1d\x63\x59\x5e\x09\x28\x1c\x56\x2a\x6f\x31\x46'), (0x10001d486, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0a\x5f\x2e\x19\x05\x1e\x05'), (0x10001d496, b'\x12\x3e\x1b\x16\x1e\x65\x3b\x56\x20\x5e\x28\x1a\x03\x5c\x1b\x32\x2d\x5e\x0a\x3f\x20'), (0x10001d4ac, b'\x1d\x63\x43\x52\x01\x26\x1d\x4d'), (0x10001d4b5, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x0d\x51\x22\x13\x0b\x1f\x19\x20'), (0x10001d4c6, b'\x1d\x63\x47\x42\x01\x23\x0c\x5c'), (0x10001d4cf, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x1e\x51\x34\x16\x08\x1a\x43\x10\x2d\x5b\x0a\x25\x27\x48\x3c\x10\x1f\x39\x0a\x43\x3e'), (0x10001d4ed, b'\x12\x3e\x1b\x1d\x1a\x2b\x14\x55\x2c\x44\x30\x16\x19\x12\x0e\x3a\x6e\x51\x03\x22\x36\x09\x1f\x5e\x24\x34\x03\x5b\x28\x40\x40'), (0x10001d50d, b'\x12\x3e\x1b\x16\x1e\x65\x3a\x55\x26\x53\x2c\x04\x1e\x01\x09\x32\x2c\x75\x1d\x2e\x36\x09'), (0x10001d524, b'\x7b\x24\x40\x56\x0e\x25\x11\x57'), (0x10001d52d, b'\x73\x22\x53\x56\x0e\x25\x11\x57'), (0x10001d536, b'\x65\x2c\x42\x56\x03'), (0x10001d559, b'\x1d\x63\x50\x52\x19'), (0x10001d568, b'\x12\x3e\x1b\x16\x1e\x65\x5d\x4a\x66\x47\x26\x1b\x06\x16\x18\x20'), (0x10001d579, b'\x72\x35\x5b\x57\x18\x39\x57\x5c\x31\x5f\x23\x02\x19\x5d\x1b\x32\x2d\x5e\x0a\x3f'), (0x10001d58e, b'\x72\x35\x5b\x57\x18\x39\x57\x5c\x31\x5f\x23\x02\x19\x5d\x0f\x3c\x2f\x54\x41\x21\x20\x08\x05'), (0x10001d5a6, b'\x73\x28\x47\x58\x19\x25\x08\x7b\x20\x5e\x26\x19\x09\x16'), (0x10001d5b5, b'\x56\x3d\x44\x1e\x1e\x3e\x17\x4b\x2c\x1e\x2d\x04\x05\x1d'), (0x10001d5c4, b'\x44\x24\x59\x43\x01\x2f\x55\x4a\x3d\x5f\x35\x16\x0d\x16\x42\x39\x32\x5d\x01'), (0x10001d5d8, b'\x60\x2c\x58\x5f\x08\x3e\x0b\x16\x3d\x42\x22\x0d\x05\x01\x42\x27\x39\x46'), (0x10001d5eb, b'\x12\x3e\x1b\x16\x1e\x65\x38\x4d\x3b\x55\x3d\x18\x18'), (0x10001d5fb, b'\x74\x22\x57\x50\x02\x29'), (0x10001d602, b'\x75\x3f\x55\x45\x08'), (0x10001d608, b'\x78\x3d\x51\x41\x0c'), (0x10001d617, b'\x7a\x24\x57\x41\x02\x39\x17\x5f\x3d\x10\x02\x13\x0d\x16'), (0x10001d626, b'\x70\x22\x5b\x54\x01\x2f\x57\x7a\x21\x42\x28\x1a\x0f'), (0x10001d634, b'\x70\x22\x5b\x54\x01\x2f\x58\x7a\x21\x42\x28\x1a\x0f'), (0x10001d642, b'\x54\x22\x59\x1d\x02\x3a\x1d\x4b\x28\x43\x28\x11\x1e\x04\x0d\x21\x24\x1c\x20\x3b\x36\x15\x0a'), (0x10001d65a, b'\x7a\x22\x4e\x5a\x01\x26\x19\x19\x0f\x59\x35\x12\x0c\x1c\x14'), (0x10001d66a, b'\x63\x25\x41\x5d\x09\x2f\x0a\x5b\x20\x42\x23\x58\x3a\x01\x03\x35\x28\x5e\x0a\x38'), (0x10001d67f, b'\x7a\x22\x4e\x5a\x01\x26\x19\x19\x1d\x58\x32\x19\x0e\x16\x1e\x31\x28\x40\x0b'), (0x10001d69e, b'\x70\x08\x60\x70\x2b\x0d\x04\x1c\x3a\x4c\x62\x04'), (0x10001d6ab, b'\x75\x0c\x67\x76\x2e\x0c\x3f\x45\x6c\x43\x3b\x52\x19'), (0x10001d6e0, b'\x53\x38\x44\x5f\x04\x29\x19\x4d\x2c\x10\x21\x1e\x06\x16\x4c\x7b\x11\x7d\x3c\x02\x0b\x47\x0d\x18\x1f\x30\x4f\x15\x68\x47\x11\x4d\x2b\x0b\x19\x28\x5c\x2e\x16\x19\x5a\x4c\x27\x2e\x12\x09\x24\x3f\x03\x0e\x03\x53\x7d\x3f\x78\x1e\x7d\x6b\x4d\x2c\x11\x55\x2c\x10\x65\x52\x19\x51\x4c\x32\x32\x12\x0e\x27\x3a\x06\x18\x58\x53\x22\x06\x43\x25\x14\x41\x08\x3a\x14\x58\x2a\x59\x29\x10'), (0x10001d73e, b'\x58\x3e\x55\x40\x0e\x38\x11\x49\x3d\x0c\x7b\x32\x25\x37\x66\x27\x24\x5e\x03\x6b\x32\x17\x1b\x1d\x1a\x36\x0e\x43\x24\x5b\x5d\x4d\x68\x3e\x50\x27\x54\x22\x05\x48\x79\x49\x20\x4b\x57\x01\x2f\x73\x13\x0e\x1d\x1f\x5f\x2a\x78\x09\x3e'), (0x10001d778, b'\x52\x35\x51\x50\x18\x3e\x11\x56\x27\x10\x22\x05\x18\x1c\x1e'), (0x10001d788, b'\x43\x28\x4c\x47\x4d\x38\x1d\x4d\x3c\x42\x29\x12\x0e\x49'), (0x10001d797, b'\x1b\x6d\x56\x46\x19\x3e\x17\x57\x69\x42\x22\x03\x1f\x01\x02\x36\x25\x08'),]
for addr, enc in strings: dec = bytes(b ^ KEY[i % 27] for i, b in enumerate(enc)).rstrip(b'\x00').decode('utf-8', errors='replace') print(f"0x{addr:x} {dec}")
Full decryption output:
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample> python3 dec2.py
0x10001cc2e HOME
0x10001cc39 osascript<<EOD
tell application "Finder"
delete POSIX file "%s"
end tell
EOD
0x10001cc87 folder
0x10001cc8e of folder
0x10001cc99 alias file
0x10001cca4 of startup disk,
0x10001ccb6 of application file
0x10001cccb SIZE,
0x10001ccd7 Library/LaunchAgents
0x10001ccec %s/.local-%s
0x10001cd0d launchctl load -w "%s"
0x10001cd24 %s/Library/LaunchAgents/%s
0x10001cd3f open -a /bin/bash --args -c "sleep 3; rm -rf '%s'"
0x10001cd77 /dev/urandom
0x10001cd84 Content-Encoding: binary
0x10001cd9d http://85.217.222.185/static.php
0x10001cdc0 NFTktRMW
0x10001cdd5 ProductVersion:
0x10001ce02 osascript -e 'set volume output muted true'
0x10001ce2e osascript -e 'set volume output muted false'
0x10001ce7c %s/pw.dat
0x10001ce86 INIT
0x10001ce91 reboot -l
0x10001ce9b hy_AM;be_BY;kk_KZ;ru_RU;uk_UA;
0x10001ceba xattr -d com.apple.quarantine "%s"
0x10001cee8 http://85.217.222.185/index.php
0x10001cf26 60ebe5b6-e8c2-4a21-beaa-42d9a1b55363
0x10001cf56 screencapture -x -t %s "%s"
0x10001cf72 system_profiler SPHardwareDataType
0x10001cf95 Hardware:
0x10001cf9f Hardware Overview:
0x10001cfb2 ps aux
0x10001cffb .DS_Store
0x10001d015 Web Data
0x10001d01e Local Extension Settings
0x10001d037 IndexedDB
0x10001d041 TOTP
0x10001d069 cookies.sqlite
0x10001d078 places.sqlite
0x10001d086 %s/storage/default/moz-extension+++%s^userContextId=4294967295
0x10001d0c5 %s/prefs.js
0x10001d16c Files
0x10001d172 recentservers.xml
0x10001d184 %s/.config/filezilla/%s
0x10001d19c FTP/FileZilla/%s
0x10001d1ad loginusers.vdf
0x10001d1d3 screenshot.jpg
0x10001d1e2 Cookies.binarycookies
0x10001d1f8 Cookies.plist
0x10001d206 Form Values
0x10001d212 History.db
0x10001d21d %s/Library/Cookies/%s
0x10001d233 Browsers/Safari
0x10001d243 Library/Safari
0x10001d252 Keychains
0x10001d25c %s/Library/Containers/com.apple.Notes/Data/Library/Notes
0x10001d295 Notes
0x10001d29b Discord/Local Storage
0x10001d2b1 key_datas
0x10001d2bb Telegram
0x10001d2c4 %s/.zsh_history
0x10001d2d4 zsh_history
0x10001d2e0 Wallets/Ethereum
0x10001d2f1 %s/Library/Ethereum/keystore
0x10001d30e Wallets/Electrum
0x10001d31f %s/.electrum/wallets
0x10001d334 Wallets/Electrum-LTC
0x10001d349 %s/.electrum-ltc/wallets
0x10001d362 Wallets/ElectronCash
0x10001d377 Wallets/Monero
0x10001d386 %s/Monero/wallets
0x10001d398 Wallets/Jaxx/Local Storage
0x10001d3b3 %s/%s/Jaxx/Local Storage
0x10001d3cc Wallets/Guarda/Local Storage
0x10001d3e9 %s/%s/Guarda/Local Storage
0x10001d404 Wallets/atomic/Local Storage
0x10001d421 %s/%s/atomic/Local Storage
0x10001d43c Wallets/BitPay/Local Storage
0x10001d459 Wallets/MyMonero
0x10001d46a %s/%s/MyMonero
0x10001d479 *.mmdbdoc_v1
0x10001d486 Wallets/Coinomi
0x10001d496 %s/%s/Coinomi/wallets
0x10001d4ac *.wallet
0x10001d4b5 Wallets/Daedalus
0x10001d4c6 *.sqlite
0x10001d4cf Wallets/Wasabi/Client/Wallets
0x10001d4ed %s/.walletwasabi/client/Wallets
0x10001d50d %s/%s/BlockstreamGreen
0x10001d524 Litecoin
0x10001d52d Dogecoin
0x10001d536 Raven
0x10001d559 *.dat
0x10001d568 %s/%s/%s/wallets
0x10001d579 Exodus/exodus.wallet
0x10001d58e Exodus/exodus.conf.json
0x10001d5a6 DesktopBinance
0x10001d5b5 app-store.json
0x10001d5c4 simple-storage.json
0x10001d5d8 Wallets/trezor.txt
0x10001d5eb %s/%s/@trezor
0x10001d5fb Coccoc
0x10001d602 Brave
0x10001d608 Opera
0x10001d617 Microsoft Edge
0x10001d626 Google/Chrome
0x10001d634 Google Chrome
0x10001d642 com.operasoftware.Opera
0x10001d65a Mozilla Firefox
0x10001d66a Thunderbird/Profiles
0x10001d67f Mozilla Thunderbird
0x10001d69e GETCFG|%s|%s
0x10001d6ab BASECFG|%s|%s
0x10001d6e0 duplicate file (POSIX file "%s" as alias) to folder (POSIX file "%s" as alias) with replacing
0x10001d73e osascript<<EOD
tell application "Finder"
%s
end tell
EOD
0x10001d778 execution error
0x10001d788 text returned:
0x10001d797 , button returned:
kant@APPLEs-MacBook-Pro ~/D/homebrew-sample>
Indicators of Compromise (IOC)
Network IOCs
| Type | Value | Context |
|---|---|---|
| IP Address | 85.217.222.185 | C2 server |
| URL | http://85.217.222.185/static.php | Primary C2 endpoint — data exfiltration / configuration |
| URL | http://85.217.222.185/index.php | Secondary C2 endpoint |
| Protocol | HTTP (plaintext) | No TLS — traffic is observable on the wire |
File Hashes
| Algorithm | Value |
|---|---|
| MD5 | cad2cd91df26c92ecf246c01276f6c2f |
| SHA-1 | 2fb3802d419afaf7a883134271dcd4deee5957ea |
| SHA-256 | ce6dc065752cb46437ce6a200e29d5dbd96473daa72dcce07aa493b821a99ba9 |
File System IOCs
| Path / Pattern | Context |
|---|---|
~/Library/LaunchAgents/ | Persistence plist installation path |
~/.local-%s | Secondary persistence or staging path |
~/Library/Ethereum/keystore | Ethereum wallet key store |
~/.electrum/wallets | Electrum (BTC) wallet data |
~/.electrum-ltc/wallets | Electrum-LTC wallet data |
~/Monero/wallets | Monero wallet data |
~/.walletwasabi/client/Wallets | Wasabi wallet data |
~/Library/Cookies/ | Safari and system cookies |
~/Library/Containers/com.apple.Notes/Data/Library/Notes | Apple Notes database |
~/.config/filezilla/ | FileZilla FTP credentials |
~/.zsh_history | Shell command history |
%s/pw.dat | Stolen password staging file |
screenshot.jpg | Screenshot captured silently by the malware |
system.txt | System hardware information dump |
*.wallet, *.dat, *.sqlite, *.mmdbdoc_v1 | Wallet file glob patterns used during harvesting |
Behavioral IOCs
| Indicator | Command / String | Purpose |
|---|---|---|
| Persistence install | launchctl load -w "%s" | Registers a LaunchAgent for persistence across reboots |
| Quarantine bypass | xattr -d com.apple.quarantine "%s" | Removes quarantine flag to suppress Gatekeeper |
| Delayed self-deletion | open -a /bin/bash --args -c "sleep 3; rm -rf '%s'" | Removes the binary three seconds after execution |
| Audio muting | osascript -e 'set volume output muted true' | Suppresses audio alerts during operation |
| File relocation | tell application "Finder" move POSIX file ... with replacing | Moves files via AppleScript |
| File deletion | tell application "Finder" delete POSIX file ... | Deletes files via AppleScript |
| Screenshot capture | screencapture -x -t %s "%s" | Captures the screen silently |
| System profiling | system_profiler SPHardwareDataType | Collects hardware information |
| Process enumeration | ps aux | Lists all running processes |
| C2 exfiltration | libcurl + http://85.217.222.185/ | HTTP-based data exfiltration |
| CIS locale check | hy_AM;be_BY;kk_KZ;ru_RU;uk_UA | Aborts execution if system locale matches CIS region |
Targeted Applications
Browsers
| Google Chrome | Brave | Mozilla Firefox |
|---|---|---|
| Microsoft Edge | Opera | Safari |
| Mozilla Thunderbird | Coccoc | — |
Cryptocurrency Wallets
| Ethereum | Electrum (BTC) | Electrum-LTC |
|---|---|---|
| ElectronCash | Monero | Jaxx |
| Guarda | Atomic Wallet | BitPay |
| MyMonero | Coinomi | Daedalus (Cardano) |
| Wasabi Wallet | Exodus | Trezor |
| BlockstreamGreen | Litecoin Core | Dogecoin Core |
| Raven Core | Binance Desktop | — |
Other Applications
| Discord | Telegram | FileZilla |
|---|---|---|
| Apple Keychain | Apple Notes | Steam (loginusers.vdf) |
Obfuscation Artefacts
| Type | Value |
|---|---|
| XOR Key | 7M43mJx9I0GwjslSA2oKSgkqsUo |
| Key Length | 27 bytes (0x1b) |
| Cipher | Rolling single-byte XOR with null termination |
| Embedded UUID | 60ebe5b6-e8c2-4a21-beaa-42d9a1b55363 |
Conclusion
This sample is a fully-featured instance of AMOS (Atomic macOS Stealer), a commercial infostealer sold as a Malware-as-a-Service offering. The binary was distributed as a Homebrew package — a convincing social engineering lure given Homebrew's widespread adoption among macOS developers and power users.
Capability summary. The malware implements a broad data collection mandate. Its primary objectives are credential theft (browser passwords, Safari cookies, Apple Keychain, Firefox extension data), cryptocurrency wallet harvesting across 20+ wallet applications, and system reconnaissance (hardware profiling, process enumeration, silent screenshot capture). Exfiltration is conducted over plaintext HTTP to a single C2 IP (85.217.222.185), which presents a clear detection opportunity at the network layer.
Evasion and persistence. All sensitive strings are concealed using a rolling XOR cipher, requiring active reverse engineering to recover. Gatekeeper bypass is achieved via xattr -d com.apple.quarantine. Persistence is established through a LaunchAgent plist registered with launchctl. A delayed self-deletion routine removes the binary three seconds after execution to reduce the forensic footprint. Volume muting suppresses audio cues that might alert the user during operation. The CIS-region locale exclusion list (ru_RU, uk_UA, kk_KZ, be_BY, hy_AM) causes the malware to abort on systems configured for those locales — a convention strongly associated with Russian-aligned threat actors.
Detection and response. Network-level controls should block all outbound connections to 85.217.222.185. Endpoint detection rules should monitor for launchctl load on user-writable LaunchAgent paths, xattr -d com.apple.quarantine followed by execution of the modified file, and osascript spawning file management operations against sensitive directories. The XOR key 7M43mJx9I0GwjslSA2oKSgkqsUo is a high-confidence YARA signature candidate given its length and uniqueness. On any host assessed as compromised, all credentials stored in targeted browsers, Apple Keychain, and cryptocurrency wallets should be treated as exposed and rotated immediately.