{
	"id": "b88185f4-11f5-4a5c-bd80-5d1c4f01b30d",
	"created_at": "2026-04-06T00:12:50.678822Z",
	"updated_at": "2026-04-12T02:21:47.188157Z",
	"deleted_at": null,
	"sha1_hash": "1436a8ea269cba1a82e72f72af783703100d2a3f",
	"title": "Rhadamanthys v0.5.0 - a deep dive into the stealer’s components - Check Point Research",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1606146,
	"plain_text": "Rhadamanthys v0.5.0 - a deep dive into the stealer’s components - Check\r\nPoint Research\r\nBy shlomoo@checkpoint.com\r\nPublished: 2023-12-14 · Archived: 2026-04-02 12:42:39 UTC\r\nResearch by: hasherezade\r\nHighlights\r\nThe Rhadamanthys stealer is a multi-layer malware, sold on the black market, and frequently updated. Recently\r\nthe author released a new major version, 0.5.0.\r\nIn the new version, the malware expands its stealing capabilities and also introduces some general-purpose spying\r\nfunctions.\r\nA new plugin system makes the malware expandable for specific distributor needs.\r\nThe custom executable formats, used for modules, are unchanged since our last publication (XS1 and XS2\r\nformats are still in distribution).\r\nCheck Point Research (CPR) provides a comprehensive review of the agent modules, presenting their capabilities\r\nand implementation, with a focus on how the stealer components are loaded and how they work.\r\nIntroduction\r\nRhadamanthys is an information stealer with a diverse set of modules and an interesting multilayered design.\r\nIn our last article on Rhadamanthys [1], we focused on the custom executable formats used by this malware and their\r\nsimilarity to a different family, Hidden Bee, which is most likely its predecessor.\r\nIn this article we do a deep dive into the functionality and cooperation between the modules. The first part of the article\r\ndescribes the loading chain that is used to retrieve the package with the stealer components. In the second part, we take a\r\ncloser look at those components, their structure, abilities, and implementation.\r\nChanges in version 0.5.0\r\nSince we published our previous reports [1][2], Rhadamanthys keeps evolving. At the beginning of October, the author\r\nannounced version 0.5.0 which comes with many changes, and interesting features.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 1 of 55\n\nFigure 1 – Telegram status of the author, announcing version 0.5.0.\r\nThe full list of changes, as described by the author:\r\nFigure 2 – Fragment of the changelog published on the author’s Telegram channel (full version below).\r\n02. Diversify the construction of stubs and provide x86 x32 native Exe Shellcode Dotnet4 Dotnet2 to better adapt to various\r\nusage scenarios and crypt service needs.\r\n03. The client execution process is completely rewritten, and the BUG in the syscall unhook code that caused the crash in\r\nthe old version is fixed. The execution success rate is very high, and the runtime status is better.\r\n04. Fixed the wallet upgrade support for several wallets where the cracking algorithm fails. Currently supported\r\n) Online real-time brute force cracking\r\n05. Fixed Discord token acquisition, the correct encrypted token can now be decoded.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 2 of 55\n\n06. Break through the browser data acquisition when the browser is protected by third-party programs, and add the login\r\ndata decryption algorithm of 360 Secure Browser\r\n07. The panel search condition settings have been upgraded. You can now select conditions in batches and select categories\r\nwith one click.\r\n08. Add a quick setting search filter menu to directly menu the search conditions you need to check frequently.\r\n09. Modify some changes required by users in the Telegram notification module and add new templates for use\r\n10. When building a page, the traffic source tag can directly set the previously used tag, and the URL address will be\r\nupdated simultaneously.\r\n11. If permissions permit, data collection under other user accounts used on the same machine is supported.\r\n12. The file collection module adds browser extension collection settings. For the Chrome kernel browser, you only need to\r\nprovide the extension directory name and whether to collect Local Storage data at the same time. Firefox kernel browser can\r\nprovide extension ID\r\n13. Fix the issue of using the browser to use the online password library after logging in to a Google account in Chrome, and\r\nobtaining the login password.\r\n14. The task module has been greatly upgraded, and a new plug-in module has been introduced to support users in secondary\r\ndevelopment of their own plug-ins.\r\nSupports multiple task execution modes:\r\nIn Memory LoadPE Execution\r\nDotNet Reflection Execution\r\nDotNet Extension Execution\r\nDotNet Extension with Zip Execution\r\n15. Keylogger: supports recording all keyboard input, process details, file name, window title, supports setting process\r\nfiltering, sending time, buffer size\r\n16. Data spy plug-in: currently supports correct login access and IP username and password for remote RDP access. The\r\ncorrect certificate file and password imported by the user.\r\n17. Plug-ins and loader modules support secondary development and provide SDK support.\r\nV0.5.0 Change List 01. Added observer mode 02. Diversify the construction of stubs and provide x86 x32 native Exe\r\nShellcode Dotnet4 Dotnet2 to better adapt to various usage scenarios and crypt service needs. 03. The client execution\r\nprocess is completely rewritten, and the BUG in the syscall unhook code that caused the crash in the old version is fixed.\r\nThe execution success rate is very high, and the runtime status is better. 04. Fixed the wallet upgrade support for several\r\nwallets where the cracking algorithm fails. Currently supported (UniSat Wallet Tronlink Trust Terra Station TokenPocket\r\nPhantom Metamask KardiaChain Exodus Desktop Exodus Web3 Binance ) Online real-time brute force cracking 05. Fixed\r\nDiscord token acquisition, the correct encrypted token can now be decoded. 06. Break through the browser data acquisition\r\nwhen the browser is protected by third-party programs, and add the login data decryption algorithm of 360 Secure Browser\r\n07. The panel search condition settings have been upgraded. You can now select conditions in batches and select categories\r\nwith one click. 08. Add a quick setting search filter menu to directly menu the search conditions you need to check\r\nfrequently. 09. Modify some changes required by users in the Telegram notification module and add new templates for use\r\n10. When building a page, the traffic source tag can directly set the previously used tag, and the URL address will be\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 3 of 55\n\nupdated simultaneously. 11. If permissions permit, data collection under other user accounts used on the same machine is\r\nsupported. 12. The file collection module adds browser extension collection settings. For the Chrome kernel browser, you\r\nonly need to provide the extension directory name and whether to collect Local Storage data at the same time. Firefox kernel\r\nbrowser can provide extension ID 13. Fix the issue of using the browser to use the online password library after logging in\r\nto a Google account in Chrome, and obtaining the login password. 14. The task module has been greatly upgraded, and a\r\nnew plug-in module has been introduced to support users in secondary development of their own plug-ins. Supports multiple\r\ntask execution modes: Normal execution In Memory LoadPE Execution Powershell Execution DotNet Reflection Execution\r\nDotNet Extension Execution DotNet Extension with Zip Execution VbScript Execution JScript Execution X86 shellcode\r\nexecution X64 shellcode execution Native Plugin Loader 15. Keylogger: supports recording all keyboard input, process\r\ndetails, file name, window title, supports setting process filtering, sending time, buffer size 16. Data spy plug-in: currently\r\nsupports correct login access and IP username and password for remote RDP access. The correct certificate file and\r\npassword imported by the user. 17. Plug-ins and loader modules support secondary development and provide SDK support.\r\nV0.5.0 Change List\r\n01. Added observer mode\r\n02. Diversify the construction of stubs and provide x86 x32 native Exe Shellcode Dotnet4 Dotnet2 to better ada\r\n03. The client execution process is completely rewritten, and the BUG in the syscall unhook code that caused t\r\n04. Fixed the wallet upgrade support for several wallets where the cracking algorithm fails. Currently support\r\n(UniSat Wallet\r\nTronlink\r\nTrust\r\nTerra Station\r\nTokenPocket\r\nPhantom\r\nMetamask\r\nKardiaChain\r\nExodus Desktop\r\nExodus Web3\r\nBinance\r\n) Online real-time brute force cracking\r\n05. Fixed Discord token acquisition, the correct encrypted token can now be decoded.\r\n06. Break through the browser data acquisition when the browser is protected by third-party programs, and add\r\n07. The panel search condition settings have been upgraded. You can now select conditions in batches and selec\r\n08. Add a quick setting search filter menu to directly menu the search conditions you need to check frequently\r\n09. Modify some changes required by users in the Telegram notification module and add new templates for use\r\n10. When building a page, the traffic source tag can directly set the previously used tag, and the URL address\r\n11. If permissions permit, data collection under other user accounts used on the same machine is supported.\r\n12. The file collection module adds browser extension collection settings. For the Chrome kernel browser, you\r\n13. Fix the issue of using the browser to use the online password library after logging in to a Google account\r\n14. The task module has been greatly upgraded, and a new plug-in module has been introduced to support users i\r\nSupports multiple task execution modes:\r\nNormal execution\r\nIn Memory LoadPE Execution\r\nPowershell Execution\r\nDotNet Reflection Execution\r\nDotNet Extension Execution\r\nDotNet Extension with Zip Execution\r\nVbScript Execution\r\nJScript Execution\r\nX86 shellcode execution\r\nX64 shellcode execution\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 4 of 55\n\nNative Plugin Loader\r\n15. Keylogger: supports recording all keyboard input, process details, file name, window title, supports setti\r\n16. Data spy plug-in: currently supports correct login access and IP username and password for remote RDP acce\r\n17. Plug-ins and loader modules support secondary development and provide SDK support.\r\nIn this blog, we present a walkthrough a sample that belongs to this release.\r\nThe initial loader\r\nThe initial loader is a 32-bit Windows executable (PE). It was in large part rewritten, but still contains artifacts that make it\r\nsimilar to the previous edition (0.4.9).\r\nThe author added a check of the executable’s name. When the samples are uploaded to sandboxes for automated analysis,\r\nthey are often renamed as hashes. Therefore, if the name consists of characters from a hexadeciamal charset [0-9, a-f, A-F],\r\nand its length is 16, 32, 40, or 64, the malware assumes that it is being analyzed, and exits immediately.\r\nSimilarly as we saw in the earlier releases, the initial executable contains the configuration (embedded by the builder) as\r\nwell as the package with additional modules, that constitutes the next stage. As the execution progresses, these later\r\ncomponents are unpacked, and the configuration is passed to them.\r\nFigure 3 – Overview of the relationship between the components used at this stage.\r\nThe first change that we can observe during the initial triage is a new section:  .textbss . This section is empty in the raw\r\nbinary (raw size = 0). However, will be filled at runtime with an unpacked content: a shellcode similar to the one used by the\r\nprevious versions. The difference is that in the past versions the analogous code was loaded into a newly allocated memory\r\nregion. Regardless of location, its role didn’t change: it is meant for unpacking and loading the first module from the\r\npackage.\r\nBelow is a fragment of the tracelog (created with TinyTracer) that illustrates the loading of the shellcode, and the calls\r\nexecuted from it (v.0.5.0):\r\n1e91;kernel32.WaitForSingleObject\r\n1e99;kernel32.CloseHandle\r\n1eb7;[.text] -\u003e [.textbss] ; \u003c- redirection to the code that unpacks the XS module\r\n27000;section: [.textbss]**\r\n27311;kernel32.VirtualAlloc\r\n270c1;kernel32.VirtualAlloc\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 5 of 55\n\n2726d;kernel32.VirtualFree\r\n27363;kernel32.VirtualAlloc\r\n273bd;kernel32.VirtualProtect\r\n273f0;kernel32.VirtualFree\r\n27052;called: ?? [12081000+8a] ; \u003c- redirection to the new module (XS)\r\n1e91;kernel32.WaitForSingleObject 1e99;kernel32.CloseHandle 1eb7;[.text] -\u003e [.textbss] ; \u003c- redirection to the code that\r\nunpacks the XS module 27000;section: [.textbss]** 27311;kernel32.VirtualAlloc 270c1;kernel32.VirtualAlloc\r\n2726d;kernel32.VirtualFree 27363;kernel32.VirtualAlloc 273bd;kernel32.VirtualProtect 273f0;kernel32.VirtualFree\r\n27052;called: ?? [12081000+8a] ; \u003c- redirection to the new module (XS)\r\n1e91;kernel32.WaitForSingleObject\r\n1e99;kernel32.CloseHandle\r\n1eb7;[.text] -\u003e [.textbss] ; \u003c- redirection to the code that unpacks the XS module\r\n27000;section: [.textbss]**\r\n27311;kernel32.VirtualAlloc\r\n270c1;kernel32.VirtualAlloc\r\n2726d;kernel32.VirtualFree\r\n27363;kernel32.VirtualAlloc\r\n273bd;kernel32.VirtualProtect\r\n273f0;kernel32.VirtualFree\r\n27052;called: ?? [12081000+8a] ; \u003c- redirection to the new module (XS)\r\nFor comparison, this is the corresponding tracelog fragment from version 0.4.9:\r\n18b43;kernel32.HeapDestroy\r\n184dc;ntdll.ZwProtectVirtualMemory\r\n184e6;called: ?? [a7a0000+0] \u003c- redirection to the shellcode that unpacks the XS module\r\n\u003e a7a0000+2fe;kernel32.LocalAlloc\r\n\u003e a7a0000+ba;kernel32.LocalAlloc\r\n\u003e a7a0000+260;kernel32.LocalFree\r\n\u003e a7a0000+34c;kernel32.VirtualAlloc\r\n\u003e a7a0000+3a4;kernel32.VirtualProtect\r\n\u003e a7a0000+3bb;kernel32.LocalFree\r\n\u003e a7a0000+52;called: ?? [10641000+88] \u003c- redirection to the new module (XS)\r\n18b3a;kernel32.HeapFree 18b43;kernel32.HeapDestroy 184dc;ntdll.ZwProtectVirtualMemory 184e6;called: ?? [a7a0000+0]\r\n\u003c- redirection to the shellcode that unpacks the XS module \u003e a7a0000+2fe;kernel32.LocalAlloc \u003e\r\na7a0000+ba;kernel32.LocalAlloc \u003e a7a0000+260;kernel32.LocalFree \u003e a7a0000+34c;kernel32.VirtualAlloc \u003e\r\na7a0000+3a4;kernel32.VirtualProtect \u003e a7a0000+3bb;kernel32.LocalFree \u003e a7a0000+52;called: ?? [10641000+88] \u003c-\r\nredirection to the new module (XS)\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 6 of 55\n\n18b3a;kernel32.HeapFree\r\n18b43;kernel32.HeapDestroy\r\n184dc;ntdll.ZwProtectVirtualMemory\r\n184e6;called: ?? [a7a0000+0] \u003c- redirection to the shellcode that unpacks the XS module\r\n\u003e a7a0000+2fe;kernel32.LocalAlloc\r\n\u003e a7a0000+ba;kernel32.LocalAlloc\r\n\u003e a7a0000+260;kernel32.LocalFree\r\n\u003e a7a0000+34c;kernel32.VirtualAlloc\r\n\u003e a7a0000+3a4;kernel32.VirtualProtect\r\n\u003e a7a0000+3bb;kernel32.LocalFree\r\n\u003e a7a0000+52;called: ?? [10641000+88] \u003c- redirection to the new module (XS)\r\nThe next stage, as before, is in a custom executable format. The format itself hasn’t changed since the release of 0.4.9. Once\r\nmore we are dealing with XS1 (as described in our article [1]) which can be converted into a PE with the help of our tools.\r\nThe 2nd stage loader (XS1)\r\nThe component revealed (in the XS1 format) is part of the second stage of the loading process. Looking at this module we\r\ncan see many similarities to the one described in [1]. Yet, clearly some parts are enhanced and improved.\r\nOne of the changes shows up in the initial triage, at the attempt to dump strings from the binary. In the past, we could obtain\r\na lot of hints about the module functionality by dumping the strings i.e. with the help of the Flare FLOSS tool. This is no\r\nlonger possible as the author decided to obfuscate them (more details in “String deobfuscation and the use of TLS”).\r\nAfter converting the module to PE, and opening it in IDA, we can follow up with a more detailed assessment. Looking at the\r\noutline of the start function, we see a slightly different, refined design.\r\nFigure 4 – The main_func is now passed as a callback to the function that initializes the XS module (loads\r\nimports, allocates storage, etc)\r\nAs before, the module uses the configuration passed from the previous layer. The decoded buffer starts with\r\nthe  !RHY  marker, and contains, among others, the URL of the C2 to be contacted. This is the reconstructed structure:\r\nstruct rhy_config { DWORD magic; BYTE flags1; DWORD flags2; _BYTE iv[16]; _BYTE key[32]; char C2_URL[128];\r\n};\r\nstruct rhy_config\r\n{\r\n DWORD magic;\r\n BYTE flags1;\r\n DWORD flags2;\r\n _BYTE iv[16];\r\n _BYTE key[32];\r\n char C2_URL[128];\r\n};\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 7 of 55\n\nJust like in the previous version, the connection with the C2 is established by the  netclient  module which is loaded from\r\npackage #1 (see Figure 3).\r\nIn addition, the current component unpacks and uses multiple modules that are shipped in package #1. We already saw some\r\nof them in the previously described versions. The full list is below.\r\nName Format Description\r\nNew in\r\n0.5.0?\r\nstage.x86\r\nshellcode\r\n(32-bit)\r\nShellcode used in the injection of the main module of the\r\nStage 2 into another process; responsible for accessing the\r\nnamed mapping, copying its content, and reloading the main\r\nmodule in the context of the new process\r\n✓\r\nearly.x86 XS Process injector (using raw syscalls) ✓\r\nearly.x64 XS Process injector (using raw syscalls) ✓\r\nphexec.bin XS Injects from a 32-bit process into a 64-bit –\r\nprepare.bin\r\nshellcode\r\n(64-bit)\r\n–\r\nunhook.bin XS Checks DLLs against hooks, and does unhooking if needed –\r\nstrategy.x86 XS Checks if any of the forbidden processes is running (evasion) ✓\r\nprocess.x TXT List of forbidden processes (evasion) ✓\r\nua.txt TXT\r\nA list of user-agents (a random user-agent from the list will be\r\nselected and used for the internet connection)\r\n–\r\ndt.x86 XS Evasion checks based on Al-Khaser –\r\nproto.x86 shellcode\r\nEncrypts and decrypts netclient module with the help of RC4\r\nand a random key\r\n–\r\nnetclient.x86 XS\r\nResponsible for the connection with the C2 and downloading\r\nof further modules\r\n–\r\nA simplified flow:\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 8 of 55\n\nFigure 5 – A high-level overview of the relationships between the components at this stage.\r\nMore details about the execution flow, and possible diversions from the presented path, are explained later in this report.\r\nString deobfuscation and the use of TLS\r\nOne of the new features in this release is the introduction of TLS (Thread Local Storage) for temporary buffers. They are\r\nused, among others, for decoding obfuscated strings.\r\nTLS is first allocated in the initialization function (denoted as  init_xs_module  in Figure 4). The value received from\r\nTlsAlloc is stored in a global variable. The malware then allocates a custom structure with a buffer and attaches it to the\r\nTLS.\r\nLater on, that saved buffer is retrieved and used multiple times, as a workspace for deobfuscating data, such as strings.\r\nFigure 6 – The string deobfuscation function is applied on a hardcoded value (pointing to the encrypted\r\nstring).\r\nThe string decryption function is passed as a callback to the function retrieving a buffer attached to the TLS storage.\r\nFigure 7 – The string decryption function is set as a callback to the function fetching the buffer from TLS.\r\nAfter the string is used, the buffer is cleared (see Figure 6).\r\nThe use of TLS in the implementation of this functionality is quite atypical, and it isn’t clear what was the reason behind this\r\ndesign.\r\nThe algorithms used for the string deobfuscation differ at different stages of the malware. In the case of the current module\r\n(XS1, Stage 2) the following algorithm is deployed:\r\ndef mix_key_round(ctx, size, key3, key2, key_size):\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 9 of 55\n\nresult = (key2 + ((val \u003e\u003e 5) \u0026 0xFF)) + ctx[(val % size)] + (i * (((val + key3) \u003e\u003e 3) \u0026 0xFF)) + 1\r\nctx[i] = (ctx[i] + result) \u0026 0xFF\r\ndef decrypt_data(in_buf, in_size, key_buf, key_size, key2, key3):\r\nctx = [key_buf[(i % key_size)] for i in range(in_size)]\r\nctx = mix_key_round(ctx, in_size, key3, key2, key_size)\r\nout_buf[i] = (ctx[i] ^ in_buf[i]) \u0026 0xFF\r\ndef decrypt_string(in_buf, key_buf):\r\nreturn decrypt_data(in_buf, len(in_buf), key_buf, 16, 0x3779E9B, 0)\r\n#!/usr/bin/env python3 def mix_key_round(ctx, size, key3, key2, key_size): if not size: return for i in range(size): pos =\r\nkey_size % size key_size += 87 val = ctx[pos] result = (key2 + ((val \u003e\u003e 5) \u0026 0xFF)) + ctx[(val % size)] + (i * (((val + key3)\r\n\u003e\u003e 3) \u0026 0xFF)) + 1 ctx[i] = (ctx[i] + result) \u0026 0xFF return ctx def decrypt_data(in_buf, in_size, key_buf, key_size, key2,\r\nkey3): out_buf = [0] * in_size ctx = [key_buf[(i % key_size)] for i in range(in_size)] for _ in range(4): ctx =\r\nmix_key_round(ctx, in_size, key3, key2, key_size) for i in range(in_size): out_buf[i] = (ctx[i] ^ in_buf[i]) \u0026 0xFF return\r\nout_buf def decrypt_string(in_buf, key_buf): return decrypt_data(in_buf, len(in_buf), key_buf, 16, 0x3779E9B, 0)\r\n#!/usr/bin/env python3\r\ndef mix_key_round(ctx, size, key3, key2, key_size):\r\n if not size: return\r\n for i in range(size):\r\n pos = key_size % size\r\n key_size += 87\r\n val = ctx[pos]\r\n result = (key2 + ((val \u003e\u003e 5) \u0026 0xFF)) + ctx[(val % size)] + (i * (((val + key3) \u003e\u003e 3) \u0026 0xFF)) + 1\r\n ctx[i] = (ctx[i] + result) \u0026 0xFF\r\n return ctx\r\ndef decrypt_data(in_buf, in_size, key_buf, key_size, key2, key3):\r\n out_buf = [0] * in_size\r\n ctx = [key_buf[(i % key_size)] for i in range(in_size)]\r\n for _ in range(4):\r\n ctx = mix_key_round(ctx, in_size, key3, key2, key_size)\r\n for i in range(in_size):\r\n out_buf[i] = (ctx[i] ^ in_buf[i]) \u0026 0xFF\r\n return out_buf\r\n \r\ndef decrypt_string(in_buf, key_buf):\r\n return decrypt_data(in_buf, len(in_buf), key_buf, 16, 0x3779E9B, 0)\r\nThe decryption key is stored at the beginning of the block and is always 16 bytes long. The data is terminated by 0.\r\nThe IDA script for strings deobfuscation (assuming that the decrypting functions are named,\r\nappropriately:  dec_cstring  and  dec_wstring ):\r\nhttps://gist.github.com/hasherezade/c7701821784c436d40d1442c1a623614\r\nThe list of the deobfuscated strings for the Stage 2 loader:\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 10 of 55\n\nhttps://gist.github.com/hasherezade/fb91598f6de62bdecf06edf9606a54fb\r\nRaw syscalls and Heaven’s Gate\r\nOne of the techniques that we can observe across different Rhadamanthys modules is the use of raw syscalls for calling\r\nnative API. This is a known way to evade function hooking and monitoring, and also helpful in obfuscating the names of the\r\nAPIs used. This technique has a long history and occurs in multiple different variants (described, i.e. here: [3]).\r\nThe method relies on the fact that each native system function (implemented kernel-mode) is represented by a syscall ID.\r\nThese IDs may differ depending on the Windows version. For the programmer’s convenience, Windows allows access to\r\nthem via API exported by system DLLs such as NTDLL and WIN32U. NTDLL is often hooked by antimalware products, in\r\norder to watch the called APIs and detect suspicious activity.\r\nMalware tries to bypass the installed hooks by copying the numbers of syscalls directly to its own stubs, so that it won’t\r\nhave to use the NTDLL. However, doing so generates another event that some monitoring tools may find suspicious, as it’s\r\nnot usual to execute a syscall from a non-system module.\r\nLooking at the implementation, we can see that the author was well aware of this problem and used a variant of the\r\ntechnique called indirect syscalls. The stub within the malware only prepares the syscall and its actual execution is done by\r\nreturning to the NTDLL at the end of a function. In this way, the initial part of the function that contains the hook is\r\nbypassed, but the syscall is called from the NTDLL.\r\nFigure 8 – Implementation of indirect syscalls used by Rhadamanthys.\r\nThe raw syscalls are used by Rhadamanthys in both 32 and 64-bit modules. As we know, a syscall can be performed only\r\nfrom a module that has the same bitness as the operating system. Doing a syscall from the WoW64 process (32-bit process\r\non 64-bit Windows) requires a different approach, and using wrappers that may be different for different versions of\r\nWindows [4]. Underneath, each of those wrappers temporarily switch the process from 32-bit to 64-bit mode. The author of\r\nRhadamanthys decided not to use existing wrappers, but instead implement his own, using the Heaven’s Gate [6] technique.\r\nExecution flow\r\nThe role of the modules involved in the Stage 2 hasn’t changed since the last version. They are meant to prepare and\r\nobfuscate the downloading of the actual stealers that are shipped in package #2 supplied by the C2. As we know, the\r\ndownload operation is performed by the  netclient  module. The author used several other modules to scrupulously check\r\nthe environment and make it harder for an analyst or various monitoring tools to track when the download occurs.\r\nDepending on the settings, it is possible to load next modules into the current process, or to add an extra round by injecting\r\nthe current module into a new process, and deleting the original file.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 11 of 55\n\nFigure 9 – Overview of the main function. Different execution paths can be deployed depending on the flags\r\nset in the configuration. If the restart flag is set, on the first run the module injects itself into a new process.\r\nIn the case of the analyzed sample, the restart flag was selected. This caused the main loader module to run twice, with two\r\ndifferent paths of execution.\r\nOn the first run, the malware injects itself into a newly created process. It is implemented in the following steps:\r\n1. Creates a named mapping where it places important data, such as encrypted config, the package containing later\r\nmodules, the path to the original sample, checksums of functions to be used, etc.\r\n2. Unpacks modules implementing the process injection, 32 or 64-bit, depending on the system. These modules export\r\nseveral helper functions that are implemented using raw syscalls (for more about the method used see “Raw syscalls\r\nand Heaven’s Gate”). In the currently analyzed sample, the modules were named  early.x86  and  early.x64  . They\r\nmay be different depending on the build, as since 0.5.0 distributors can customize what injection method will be\r\nused.\r\n3. The loader creates a new 32-bit process, and implants there the  stage.x86  with the help of functions exported from\r\nthe injector component.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 12 of 55\n\n4. The implanted shellcode is responsible for accessing the named mapping, copying its content, and reloading the\r\nStage 2 module in the context of the new process. It then calls an alternative variant of the Stage 2 main function\r\n( main_alt  in the XS1 structure [1]), to deploy the second execution path.\r\nThe target for the injection is selected from a hardcoded list, and can be one of the following:\r\nL\"%Systemroot%\\\\system32\\\\dialer.exe\"\r\nL\"%Systemroot%\\\\system32\\\\openwith.exe\"\r\nL\"%Systemroot%\\\\system32\\\\dllhost.exe\"\r\nL\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\nL\"%Systemroot%\\\\system32\\\\dialer.exe\" L\"%Systemroot%\\\\system32\\\\openwith.exe\"\r\nL\"%Systemroot%\\\\system32\\\\dllhost.exe\" L\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\nL\"%Systemroot%\\\\system32\\\\dialer.exe\"\r\nL\"%Systemroot%\\\\system32\\\\openwith.exe\"\r\nL\"%Systemroot%\\\\system32\\\\dllhost.exe\"\r\nL\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\nThe execution second path is deployed when the module runs inside the new process. It involves deleting the original\r\nmalware file (if the relevant flag was selected in the configuration) and loading the other modules from package #1,\r\nincluding  netclient .\r\nFigure 10 – The alternative version of the main function (main_alt), called from the injected process.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 13 of 55\n\nAfter performing the evasion checks, and making sure that the process is not monitored (with the help of additional\r\nmodules), the malware connects to the C2 and downloads the next package (package #2 – Figure 5) with the stealer\r\nmodules. Just like in the previous version, the package is shipped in a steganographic way, appended to the JPG or WAV file\r\n(for more details, refer to [1]).\r\nRetrieving Stage 3: stealer components\r\nFigure 11 – Execution flow of the modules\r\nTwo modules are involved in downloading the payload:  netclient  (in XS1 format) and  proto  (shellcode). They are both\r\nloaded into the same memory region, and  proto  is copied after the  netclient . First  netclient  is called from the main\r\nmodule, with the appropriate parameters: the address of the C2 copied from the configuration, and the User Agent, selected\r\nfrom the  ua.txt  list (if the list fails to load, a hardcoded User Agent is used as a backup).\r\nFigure 12 – The Entry Point of the netclient module is called in the Event callback function\r\nThe interesting element of the flow is that at the beginning of the  netclient  execution, the main XS1 component gets\r\nencrypted. It is decrypted later, just before the execution returns to it. The encryption and decryption are done with the help\r\nof the  proto  module, which is called twice by  netclient . This is yet another obfuscation step to minimize the memory\r\nartifacts.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 14 of 55\n\nFigure 13 – If we try to view the code of the main module, i.e. go to the offset that called  netclient , we can\r\nsee that it no longer makes sense – as it was encrypted.\r\nThe  netclient  is responsible for connecting to the C2 and downloading the payload, then decrypting it. As before ([1]) the\r\ncorrectness of the resulting buffer is verified by comparing the hash calculated from the content with the expected hash that\r\nis stored in the header of the data block. In the currently analyzed case, the payload was shipped appended to a file in the\r\nWAV format.\r\nFigure 14 – The downloaded package after decryption\r\nAfter the payload is downloaded, and passes the verification step,  netclient  module calls  proto  for the second time to\r\ndecrypt the previously encrypted main module (XS1), using the RC4 algorithm and the key that was generated and saved at\r\nthe first run.\r\nThe execution goes back to the (now decrypted) main module, which first destroys the memory region\r\nwhere  netclient  and  proto  were loaded. It then proceeds to load the next stage from the downloaded package #2.\r\nDepending on whether the system is 32 or 64-bit, further execution may proceed in the current process, or in a newly\r\ncreated, 64-bit process, where the required elements are injected.\r\nOn a 64-bit system\r\nMost of the time we encounter a 64-bit version of Windows, which means there are several extra steps before the content\r\nfrom the downloaded package can be fetched and executed.\r\nThe malware creates a new, 64-bit process, selecting one of the paths from the hardcoded list:\r\nL\"%Systemroot%\\\\system32\\\\credwiz.exe\"\r\nL\"%Systemroot%\\\\system32\\\\OOBE-Maintenance.exe\"\r\nL\"%Systemroot%\\\\system32\\\\openwith.exe\"\r\nL\"%Systemroot%\\\\system32\\\\dllhost.exe\"\r\nL\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 15 of 55\n\nL\"%Systemroot%\\\\system32\\\\credwiz.exe\" L\"%Systemroot%\\\\system32\\\\OOBE-Maintenance.exe\"\r\nL\"%Systemroot%\\\\system32\\\\openwith.exe\" L\"%Systemroot%\\\\system32\\\\dllhost.exe\"\r\nL\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\nL\"%Systemroot%\\\\system32\\\\credwiz.exe\"\r\nL\"%Systemroot%\\\\system32\\\\OOBE-Maintenance.exe\"\r\nL\"%Systemroot%\\\\system32\\\\openwith.exe\"\r\nL\"%Systemroot%\\\\system32\\\\dllhost.exe\"\r\nL\"%Systemroot%\\\\system32\\\\rundll32.exe\"\r\nAs writing into a 64-bit process from a 32-bit one is not officially supported by the Windows API, it uses Heaven’s Gate\r\ntechnique [6] to do so. This time the injection functions are encapsulated in an additional module from package\r\n#1:  phexec.bin .\r\nThe malware now uses a 64-bit module  prepare.bin , which is to be injected and used to retrieve the downloaded package\r\n#2 from inside the new process. The module  prepare.bin  is a shellcode containing an empty data section to be filled. The\r\nunfilled version of the section starts with the marker  YHR!  which is replaced with  0xDEADBEEF  after it is filled.\r\nFigure 15 – Filled in data within the prepare.bin module.\r\nData transmission using BaseNamedObject and the use of Exception Handlers\r\nThe loader (32-bit executable) creates a named object that is used to share the information between the current process and\r\nthe infected one (64-bit). The content downloaded from the C2 is passed to this object and then received in the other process,\r\nvia  prepare.bin .\r\nDuring the injection, the  prepare.bin  is implanted into a fresh 64-bit process. The execution is redirected by patching the\r\nEntry Point of the main executable with a jump that leads to the shellcode.\r\nThe shellcode ( prepare.bin ) contains a loop waiting for the BaseNamedObject to be filled. It sets a Vectored Exception\r\nHandler that is triggered after the data transfer from the other process is finished. The use of an exception handler is\r\nintended to be an additional obfuscation of the execution flow.\r\nDuring its execution, the shellcode installs some more patches in the original executable of the process, and returns back to\r\nthe patched code after the exception handler was registered. The overwritten code changes the memory protection and waits\r\nfor the first malware process to send data over the BaseNamedObject.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 16 of 55\n\nFigure 16 – The code of the infected executable overwritten during shellcode execution, performing wait.\r\nWhen the wait is over, it triggers an exception executing the  int3  instruction. As a result the execution lands in the\r\nVectored Exception Handler, that is installed by the shellcode.\r\nThe exception handler is responsible for unpacking the retrieved package, fetching from it the next shellcode, and\r\nredirecting the execution. The further flow, starting from the retrieved shellcode from package #2, is analogous to the\r\nexecution on a 32-bit system described below.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 17 of 55\n\nFigure 17 – The exception handler responsible for unpacking the retrieved package, fetching from it a\r\nshellcode, and redirecting the execution.\r\nOn 32-bit system\r\nThe first element fetched from the new package is a shellcode.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 18 of 55\n\nFigure 18 – Two alternative paths after the data is downloaded from the C2. If the system is 32-bit, the\r\nshellcode from the downloaded package is copied into the current process, and then run in its context.\r\nOtherwise, it is injected into a new, 64-bit process.\r\nThe shellcode decrypts and decompresses the rest of the downloaded package. It then fetches the main stealer module,\r\nwhich is in the XS2 format [1].\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 19 of 55\n\nFigure 19 – The module in XS2 format revealed in memory\r\nThe unpacked module is loaded into a newly allocated memory region. However, the redirection contains some additional\r\nsteps. Once again, the author took extra care to minimize the memory artifacts and made sure that the loading shellcode is\r\nreleased after use. A a small chunk of the shellcode is copied to the new memory region, just after the loaded XS2 module.\r\nAfter that block, other necessary data is copied, including the pointer to the package, and the Entry Point of the next module.\r\nAfter finishing, the loading function jumps to such a prepared stub. As the stub is in the new memory region, it can free the\r\nregion containing the unpacking shellcode before the redirection to the next stage.\r\nFigure 20 – The copied stub frees the loading shellcode, and then redirects to the next module.\r\nStage 3: coredll.bin (XS2)\r\nAfter passing the full loading chain, the execution finally reaches the main stealer module: coredll.bin (in XS2 format).\r\nThe module coordinates all the work, collects the results, and reports them back to the C2. It is also responsible for\r\nretrieving other modules from package #2, and using them to perform various tasks.\r\nIn the current release, the following modules are available in the package:\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 20 of 55\n\nModule path Type Role\r\nIs new in\r\n0.5.0?\r\n/bin/i386/coredll.bin\r\n/bin/amd64/coredll.bin\r\nXS\r\nMain stealer module (analogous to the one\r\ndescribed in this chapter)\r\n–\r\n/bin/i386/stubmod.bin\r\n/bin/amd64/stubmod.bin\r\nXS\r\nPrepares a .NET environment inside the process,\r\nto load other .NET modules\r\n–\r\n/bin/i386/taskcore.bin\r\n/bin/amd64/taskcore.bin\r\nXS\r\nManages additional modules for the tasks\r\nsupplied by the C2\r\n✓\r\n/bin/i386/stubexec.bin\r\n/bin/amd64/stubexec.bin\r\nXS\r\nInjects into regsvr32.exe, and remaps the module\r\ninto a new process\r\n–\r\n/bin/KeePassHax.dll\r\nPE\r\n(.NET)\r\nSteals KeePass credentials –\r\n/bin/runtime.dll\r\nPE\r\n(.NET)\r\nRuns PowerShell scripts and plugins in the form\r\nof .NET assemblies\r\n–\r\n/bin/loader.dll\r\nPE\r\n(.NET)\r\nGeneral purpose .NET assemblies runner ✓\r\nAs seen earlier, the malware supports up to 100 LUA extensions. They are loaded from the package, retrieved by paths in the\r\nformat:  /extension/%08x.xs .\r\nThe  coredll.bin  not only coordinates the work of other modules, but also has a lot of vital functionality hardcoded. It\r\ncomes with a collection of built-in stealers that can be enabled or disabled depending on the configuration.\r\nString encryption\r\nIn case of this module not all strings are obfuscated, so we can obtain some of them with the help of common applications\r\nsuch as FLOSS . Those are mainly strings from the statically linked libraries. The most important strings, relevant to the\r\nmalware functionality, are encrypted and revealed just before use. Once again, TLS storage is used for the temporary buffer.\r\nThis time the algorithm used for the decryption is RC4. The first 16 bytes of the input buffer is the key, followed by the\r\nencrypted data.\r\nIDA script for deobfuscation:\r\nhttps://gist.github.com/hasherezade/51cb827b101cd31ef3061543d001b190\r\nDeobfuscated strings from the sample:\r\nhttps://gist.github.com/hasherezade/ac63c0cbe7855276780126be006f7304\r\nCommunication between the modules\r\nAs there are multiple modules involved in the execution of various tasks, and some of them are injected into remote\r\nprocesses, they must communicate with the central module ( coredll.bin ), to coordinate the work and pass the collected\r\nresults. The communication is implemented with the help of a pipe.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 21 of 55\n\nFigure 21 – The function creating the pipe within the main module.\r\nThe pipe is created by the main module, using the name  Core  and the current PID. This information, concatenated\r\ntogether, is hashed (SHA1), and the hash is used to generate the unique pipe name (following the pattern  \\\\.\\pipe\\{%08lx-\r\n%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x} ).\r\nFigure 22 – The function used to generate the pipe name.\r\nThe PID is further passed to the submodules so they can regenerate the name, following the same algorithm, and then\r\nestablish the connection.\r\nExecution flow\r\nAfter the module finishes initialization, which is typical for the XS2 format [1], execution is redirected to the main function\r\nof the module. The function takes 3 arguments: the pointer to the current module, a command to be executed, and a\r\nstructure, including all the data passed from the previous layers. Depending on the command argument, the module can\r\nfollow one of the 4 different execution paths. In each case, the most important functionality is to load additional\r\ncomponents, establish the connection with the C2, and deploy the built-in stealers.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 22 of 55\n\nFigure 23 – The overview of the main function within the Core module.\r\nIn some cases, the function responsible for running all the modules can be executed at the exit of the application where it is\r\ninjected. It is implemented by hooking the  ExitProcess  function.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 23 of 55\n\nDisabling the Event Tracer (and other NTDLL patches)\r\nAt the beginning of the main function (Figure 23), we can see a function patching NTDLL. Its role is to disable Event\r\nTracering (ETW), which is a built-in Windows feature allowing to collect information about the application behavior. The\r\nbypass is implemented similarly to that described in the article [5].\r\nIn the case of the WoW64 process, both the 32-bit and the 64-bit version of the NTDLL are patched. By scanning the\r\nprocess with PE-sieve, we can quickly dump the modified versions of NTDLLs and receive the  .tag  file informing about\r\nthe hooks. The found patches are listed below.\r\nIn NTDLL 64-bit:\r\nThe installed patch is simple, it forces the  EtwEventWrite function to always return 0.\r\nFigure 24 – The patch in the NTDLL (64-bit), disabling function EtwEventWrite.\r\nThe patches (NTDLL 32-bit):\r\nHere we can see two functions patched:  EtwEventWrite  and  NtTraceEvent – they both are forced to return immediately at\r\nthe start.\r\nFigure 25 – Multiple patches in the NTDLL (32-bit), including the ones disabling ETW.\r\nAdditionally, we can see a hook inside the exception dispatcher, whose role was described in detail in our previous article on\r\nRhadamanthys [1] (”Handling exceptions from a custom module”). In contrast to other hooks that are security bypasses, this\r\nhook is part of the XS format loading and allows to catch the exceptions thrown by the custom module.\r\nRunning the stealers\r\nThe main component of Stage 3 comes with a rich set of built-in stealers. They are stored as two distinct global lists. The\r\nfirst group involves stealers that rely on searching and parsing files of particular targets (i.e., profiles, local databases),\r\nwhich we refer to as “passive stealers”. The second set which we refer to as “active stealers” consists of more invasive\r\ncomponents: they can interfere with running processes, inject into them, etc.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 24 of 55\n\nFigure 26 – Global lists of the passive and active stealers.\r\nEach stealer has an initialization function and a run function. They also use a top-level structure from where they fetch the\r\ndata and where they report back the results. By sharing this structure, they can pass data from one to another, working as\r\nelements of the pipeline. The overview of the function responsible for running the stealers:\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 25 of 55\n\nFigure 27 – Fragment of the function responsible for the deployment of the stealers.\r\nFirst, the malware enumerates all the processes and stores their names, along with their PIDs, in a structure that will be used\r\nlater. Then, all the built-in active stealers are initialized in a loop. At this point, they may reference the list of the processes to\r\ncheck if their targets are on the list. Some of them may also read additional information from the process, which will be\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 26 of 55\n\npassed further into the pipeline. Next, the passive stealers are initialized. The User Profile Path is retrieved and walked\r\nrecursively to check if it contains some targeted directories from which the malware can steal.\r\nAfter the initialization of both types of stealers is finished and information about the targets is collected, the functions\r\nperforming the actual stealing activities run. First, all the initialized profile parsers are executed in a loop to collect the\r\ninformation from the files. Finally, the active stealers are executed.\r\nAfter all the hardcoded stealers were run, the malware initializes a built-in LUA interpreter and uses it to execute the\r\nadditional set of stealers, implemented as LUA scripts (described in more detail in “The LUA scripts“).\r\nThe results of all the executed stealers are collected in a global structure. They are posted into the queue and later uploaded\r\nto the C2.\r\nThe passive stealers\r\nAs mentioned earlier, passive stealers rely on reading and parsing files belonging to particular applications to retrieve saved\r\ncredentials.\r\nThe passive stealers are initialized by parsing recursively all the subdirectories in  %USERPROFILE%  and checking the\r\npresence of targeted paths. The inner function enumerates all the directories in the  %USERPROFILE% , and on each new\r\ndirectory found, it executes a passed callback.\r\nThe callback then runs the full list of initialization functions ( is_target ) of the stealers. If the path is identified as a target,\r\nthe relevant passive stealer is further initialized.\r\nFigure 28 – A loop initializing passive stealers with the directories found recursively in the %USERDATA%\r\ndirectory.\r\nThe paths used for the target identifications (passive stealers):\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 27 of 55\n\nTarget Paths/extensions Is Optional\r\nChrome “Web Data”, “Web Data Ts4” no\r\nFirefox “cookies.sqlite” no\r\nFileZilla “recentservers.xml” yes\r\nOpenVPN “OpenVPN Connect\\profiles”, “.ovpn” yes\r\nTelegram “configs”, “\\D877F783D5D3EF8C\\configs” yes\r\nDiscord “DiscordStorage”, “discordptbStorage”, “discordcanaryStorage” yes\r\nStickyNotes “Microsoft.MicrosoftStickyNotes”, “plum.sqlite” yes\r\nThe malware comes with a statically linked SQLite library which allows it to load and query local SQLite databases, and\r\nfetch saved data such as cookies.\r\nThe active stealers\r\nThe set of active stealers is more interesting and diverse. Some of these stealers open running processes and inject additional\r\ncomponents. One of such components is  KeePassHax.dll , injected into the KeePass process, to steal credentials from this\r\nopen-source password manager (more details in: “Stealing from KeePass”). The malware may also inject its main\r\ncomponent ( core.bin ) into other applications.\r\nThe set of the stealers is too big to describe each of them in detail. In summary, the following applications are targeted:\r\nChrome Vault WinSCP StickyNotes KeePass\r\nMozilla products (Thunderbird, Firefox)\r\nand some of the Firefox-based browsers,\r\nsuch as K-Meleon.exe\r\nFoxMail Telegram Stream TeamViewer\r\nInternet Explorer OpenVPN Discord CoreFTP 360Browser\r\nStealing from Chrome and Mozilla products\r\nIn some cases, the active stealer’s initialization function retrieves from the running process information about the current\r\nprofile and configuration files. It is done for the following targets:\r\nK-Meleon.exe (Firefox-based browser), Firefox\r\nChrome\r\nThe approach to finding the loaded profile is a bit different in each case.\r\nIn the case of K-Meleon.exe it identifies the target files by paths retrieved from associated handles. First, the malware\r\nretrieves all object handles that are currently opened in the system, using  NtQuerySystemInformation (with the\r\nargument  SystemHandleInformation ). It walks through obtained handles and selects the ones owned by the target process.\r\nThen, it iterates over those handles to check which names they are associated with (using  NtQueryObject ), and compares\r\neach name with the hardcoded one ( \\places.sqlite ) . If the check passed, the full path is retrieved and stored for further\r\nuse.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 28 of 55\n\nFigure 29 – Searching for the configuration file (“places.sqlite”) by walking through the retrieved object\r\nhandles.\r\nIn the case of Chrome, the current profile is provided in the command line used to run the application. The command line of\r\na process is stored in a dedicated field of the PEB ( PEB  →  ProcessParameters  →  CommandLine ), which is where the\r\nmalware retrieves it from. The path to the profile is given after the  —user-data-dir=  command line argument, so this\r\nhardcoded string is used for the search.\r\nAs mentioned earlier, the main stealing actions are executed in the  run  function of each stealer. The stealers targeting\r\nMozilla products may deploy additional processes and inject there the main module of the malware:  coredll.bin . Note\r\nthat although it is the same module as the one currently described, its execution path is not identical. Looking at the XS2\r\nheader [1], we can see that this format lets you provide alternative entry points of the application (denoted\r\nas  entry_point  – primary, and  entry_point_alt  – secondary). The execution of the implanted  coredll.bin  starts\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 29 of 55\n\nin  entry_point_alt . Looking at the injection routine, we can see the corresponding address being added to the APC queue\r\nof the target’s main thread.\r\nFigure 30 – Fragment of the injecting function, responsible for selecting the alternative Entry Point of the\r\nmodule, and setting it in the APC Queue of the targeted process, for execution.\r\nThe alternative entry point leads to the execution of a minimalist main, which contain only Mozilla-specific stealers.\r\nDepending on the given settings, the stealing functions can be executed immediately, or when the application exits. The\r\nexecution at exit may be necessary in case the current process blocks some files from which the module wants to read.\r\nFigure 31 – The overview of the Alternative Entry Point of the coredll.bin. We can see that the main, stealing\r\nfunction, can be executed either immediately, or at the exit of the process.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 30 of 55\n\nThere are three stealers implemented, and selected depending on the given configuration. Each of them sends the stolen\r\ncontent over the pipe back to the main element.\r\nFigure 32 – The function responsible for deploying a specific, targeted stealer attacking the Mozilla\r\napplication data.\r\nStealing from KeePass\r\nOne of the modules shipped in the package is a .NET DLL named  KeePassHax.dll . As the name suggests, this module\r\ntargets the KeePass password manager (which is a .NET application). The DLL is injected into the target along with the\r\nassisting native module, called  stubmod.bin . An interesting feature of the implementation is that it initializes the complete\r\n.NET environment of an appropriate version within the attacked KeePass process, just to deploy the stealing DLL.\r\nThe function leading to the deployment of those components belongs to the active stealers list. As explained earlier, every\r\nstealer has two callback functions:  init  and  run . In this case, the first function is empty, as there is nothing to initialize.\r\nThe activity starts in the  run  function, given below. First, it searches for the  keypass.exe  on the previously prepared list\r\nof running processes. If the name is found, it tries to inject the malicious modules into the corresponding process.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 31 of 55\n\nFigure 33 – Fragment of the function responsible for doing an injection into the KeePass.exe. The injected\r\npayload, and the function to be executed from it, are passed as arguments.\r\nTwo modules are fetched from the package:  stubmod.bin  (in a 32 or 64-bit version, matching the process)\r\nand  KeePassHax.dll . The  stubmod.bin  is an executable in the custom XS format [1], containing native code. This\r\nmodule is executed first, and prepares the stage for loading the DLL.\r\nThe start function of the  stubmod.bin  initializes the whole .NET environment inside the process where it is injected,\r\nsimilar to what is described in the following writeup [6].\r\nFigure 34 – Overview of the function responsible for custom initialization of the .NET environment within the\r\nprocess.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 32 of 55\n\nIt then runs the  KeePassHax.dll . As an argument, it passes a callback function which is responsible for sending the\r\ncollected data to the main malware process, over the previously created pipe (more details in “Communication between the\r\nmodules”). The way of passing the callback is a bit unusual, yet simple and effective: the pointer is first printed as a string\r\nand then given as an argument to the  DllMain  function of the  KeePassHax.dll .\r\nFigure 35 – The pointer to the callback function is printed as a string and then passed as an argument to the\r\n.NET module.\r\nLooking at the  DllMain  function, we can see the argument being parsed and used as two combined pointers. One of the\r\npointers, stored in the variable  NativePtr , leads to the function that sends data over the pipe (that is a part\r\nof  stubmod.bin ). The other one stored in  NativeData  contains a PID of the process running the core module, which is\r\nneeded to regenerate the pipe name.\r\nFigure 36 – The DllMain function of the KeePassHax.dll.\r\nThe main actions of dumping the credentials are done by the function  KcpDump , which retrieves values of relevant fields\r\nfrom the main KeePass form.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 33 of 55\n\nFigure 37 – The function KcpDump in the .NET module KeePassHax.dll.\r\nThe collected data is serialized and passed to the previously retrieved native function. The first supplied argument is\r\na  NativeData  containing the PID passed from the caller.\r\nFigure 38 – The KcpSendData function in the .NET module KeePassHax.dll.\r\nThe function  Program.FnSendData  is implemented in the native module, which was responsible for executing\r\nthe  KeePassHax.dll , and has the following prototype:\r\nint __cdecl to_read_write_to_pipe(int seed, DWORD numberOfBytesToWrite, _BYTE *data, int data_size)\r\nint __cdecl to_read_write_to_pipe(int seed, DWORD numberOfBytesToWrite, _BYTE *data, int data_size)\r\nint __cdecl to_read_write_to_pipe(int seed, DWORD numberOfBytesToWrite, _BYTE *data, int data_size)\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 34 of 55\n\nThe supplied seed argument is used in the generation of the pipe name, where the data is written to.\r\nFigure 39 – Generating the pipe name, analogous to the function described in “Communication between\r\nmodules”\r\nThis is how various components, native (in a custom format) as well as .NET modules, are blended together as one injected\r\npayload.\r\nThe LUA scripts\r\nAlthough the list of stealers available by default is already very rich, the author decided to provide even more options by\r\nincorporating a LUA script runner.\r\nThe main module can load up to 100 LUA scripts. In the analyzed cases, we found approximately 60 of them are used. They\r\nimplement a variety of stealers that target cryptocurrency wallets, FTP applications, e-mail agents, SSH, and more.\r\nFirst, the malware loads all the available scripts from the package in a loop. They are stored in the internal structure, that is\r\nlater passed to the interpreter.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 35 of 55\n\nFigure 40 – A LUA script fetched from the package and revealed in memory.\r\nScripts work as plugins to the built-in framework.\r\nStealers are grouped by one-character identifiers:\r\nID Type\r\nW wallets\r\nE e-mails\r\nF FTP\r\nN note-keeping apps\r\nM messengers\r\nV VPN\r\n2 authentication related, password managers, etc.\r\nThe stealer starts with a check if the group it belongs to is enabled in the framework.\r\nif not framework.flag_exist(\"W\") then\r\nif not framework.flag_exist(\"W\") then return\r\nif not framework.flag_exist(\"W\") then\r\n return\r\nSome examples are given below.\r\nStealer for Psi:\r\nif not framework.flag_exist(\"M\") then\r\nlocal filename = framework.parse_path([[%AppData%\\Psi+\\profiles\\default\\accounts.xml]])\r\nif filename ~= nil and framework.file_exist(filename) then\r\nframework.add_file(\"accounts.xml\", filename)\r\nframework.set_commit(\"$[M]Psi+\")\r\nif not framework.flag_exist(\"M\") then return end local filename =\r\nframework.parse_path([[%AppData%\\Psi+\\profiles\\default\\accounts.xml]]) if filename ~= nil and\r\nframework.file_exist(filename) then framework.add_file(\"accounts.xml\", filename) framework.set_commit(\"$[M]Psi+\")\r\nend\r\nif not framework.flag_exist(\"M\") then\r\n return\r\nend\r\nlocal filename = framework.parse_path([[%AppData%\\Psi+\\profiles\\default\\accounts.xml]])\r\nif filename ~= nil and framework.file_exist(filename) then\r\n framework.add_file(\"accounts.xml\", filename)\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 36 of 55\n\nframework.set_commit(\"$[M]Psi+\")\r\nend\r\nStealer for a DashCore wallet:\r\nif not framework.flag_exist(\"W\") then\r\nframework.parse_path([[%AppData%\\DashCore\\wallets\\wallet.dat]]),\r\nframework.parse_path([[%LOCALAppData%\\DashCore\\wallets\\wallet.dat]])\r\nfor _, filename in ipairs(filenames) do\r\nif filename ~= nil and framework.file_exist(filename) then\r\nframework.add_file(\"DashCore/wallet.dat\", filename)\r\nfile_count = file_count + 1\r\nframework.set_commit(\"!CP:DashCore\")\r\nlocal file_count = 0 if not framework.flag_exist(\"W\") then return end local filenames = {\r\nframework.parse_path([[%AppData%\\DashCore\\wallets\\wallet.dat]]),\r\nframework.parse_path([[%LOCALAppData%\\DashCore\\wallets\\wallet.dat]]) } for _, filename in ipairs(filenames) do if\r\nfilename ~= nil and framework.file_exist(filename) then if file_count \u003e 0 then break end\r\nframework.add_file(\"DashCore/wallet.dat\", filename) file_count = file_count + 1 end end if file_count \u003e 0 then\r\nframework.set_commit(\"!CP:DashCore\") end\r\nlocal file_count = 0\r\nif not framework.flag_exist(\"W\") then\r\n return\r\nend\r\nlocal filenames = {\r\n framework.parse_path([[%AppData%\\DashCore\\wallets\\wallet.dat]]),\r\n framework.parse_path([[%LOCALAppData%\\DashCore\\wallets\\wallet.dat]])\r\n}\r\nfor _, filename in ipairs(filenames) do\r\n if filename ~= nil and framework.file_exist(filename) then\r\n if file_count \u003e 0 then\r\n break\r\n end\r\n framework.add_file(\"DashCore/wallet.dat\", filename)\r\n file_count = file_count + 1\r\n end\r\nend\r\nif file_count \u003e 0 then\r\n framework.set_commit(\"!CP:DashCore\")\r\nend\r\nStealer for Notezilla:\r\nif not framework.flag_exist(\"N\") then\r\nlocal filename = framework.parse_path([[%AppData%\\Conceptworld\\Notezilla\\Notes9.db]])\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 37 of 55\n\nif filename ~= nil and framework.file_exist(filename) then\r\nframework.add_file(\"Notes9.db\", filename)\r\nframework.set_commit(\"$[N]Notezilla\")\r\nif not framework.flag_exist(\"N\") then return end local filename =\r\nframework.parse_path([[%AppData%\\Conceptworld\\Notezilla\\Notes9.db]]) if filename ~= nil and\r\nframework.file_exist(filename) then framework.add_file(\"Notes9.db\", filename) framework.set_commit(\"$[N]Notezilla\")\r\nend\r\nif not framework.flag_exist(\"N\") then\r\n return\r\nend\r\nlocal filename = framework.parse_path([[%AppData%\\Conceptworld\\Notezilla\\Notes9.db]])\r\nif filename ~= nil and framework.file_exist(filename) then\r\n framework.add_file(\"Notes9.db\", filename)\r\n framework.set_commit(\"$[N]Notezilla\")\r\nend\r\nList of all the targeted applications:\r\nArmory AtomicDEX AtomicWallet Authy Desktop AzireVPN BinanceWallet\r\nBinanceWallet BitcoinCore CheckMail Clawsmail Clawsmail CuteFTP\r\nCyberduck DashCore\r\nDefichain-Electrum\r\nDogecoin\r\nElectron-Cash\r\nElectrum-SV\r\nElectrum EMClient Exodus Frame FtpNavigator FlashFXP\r\nFTPRush GmailNotifierPro Guarda Jaxx Litecoin-Qt Litecoin-Qt\r\nLitecoinCore Monero MyCrypto MyMonero NordVPN Notefly\r\nNotezilla SSH Outlook Pidgin PrivateVPN ProtonVPN\r\nPsi+ PuTTY\r\nQtum-Electrum\r\nQtum RoboForm Safepay\r\nSmartFTP Solar Wallet The Bat TokenPocket\r\nTotal\r\nCommander\r\nTox\r\nTrulyMail WinAuth WalletWasabi WindscribeVPN Zap\r\nReceiving commands from the C2\r\nIn addition to running the modules that were embedded in the package and sending back their results, the malware\r\nestablishes a connection with the C2 to listen for additional instructions. On demand, it can drop and run additional\r\nexecutable files, or execute scripts via other modules.\r\nThere are 11 different supported commands that are identified by numbers.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 38 of 55\n\nFigure 41 – Switch-case parsing the commands from the C2 received by the coredll.bin module.\r\nThe additional modules that can be run on demand, are  taskcore.bin ,  runtime.dll , and  loader.dll .\r\nThe content received from the C2 is passed in the variable denoted above as  buf . Depending on the specifics of the\r\nparticular command, it can be saved into a file, or into a named mapping, whose handle is passed to the other malicious\r\nmodule.\r\nFor example, the module received from the C2 is passed to be executed via  taskcore.bin :\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 39 of 55\n\nFigure 42 – Fragment of the function running the received module via taskcore.bin. The buffer received from\r\nthe C2 (containing the module) is added into the mapping, whose handle is passed to the taskcore.bin module,\r\nthat is run in a new process.\r\nRunning received PowerShell scripts and .NET modules\r\nIn addition to the ability to run LUA scripts, the malware allows the execution of PowerShell scripts, and since the version\r\n0.5.0, also .NET assemblies. Unlike LUA, the scripts/assemblies to be executed are not shipped in the package but\r\ndynamically received from the C2.\r\nThis part of the functionality is managed by additional modules from package #2:  runtme.dll  (runs PowerShell scripts,\r\nand plugins) and  loader.dll  (a general-purpose loader of .NET assemblies).\r\nThe modules are run within a new process under the guise of  AppLaunch.exe  or  dllhost.exe .\r\nEvolution of PowerShell runner (runtime.exe/dll)\r\nIn the previous versions, the PowerShell runner was implemented as  runtime.exe , which is a very small executable\r\nwritten in .NET. The runner consisted of the  Main  function presented below. It takes two string arguments, which are in\r\nfact pointers in hexadecimal form. The pointers lead to the functions in the native module that loaded the current one and are\r\nused to pass the input and output. The scripts are received by calling the function  sysNativeWrapper.GetScript() , then\r\nresults are passed back by  sysNativeWrapper.SendDumpData(data) .\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 40 of 55\n\nFigure 43 – The .NET module: “runtime.exe” (decompiled using dnSpy)\r\nThe new version of the runner is a DLL, not an EXE ( runtime.dll ). It is fully rewritten, and much more complex. The\r\nrunner exposes a new interface, to support the API of the newly introduced plugin system.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 41 of 55\n\nFigure 44 – List of classes on the runtime.dll (decompiled using dnSpy).\r\nThe plugins are in the form of .NET assemblies.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 42 of 55\n\nFigure 45 – Fragment of the function executing the plugins (.NET assemblies following the defined API) –\r\nruntime.dll, decompiled using dnSpy.\r\nSimple PowerShell scripts, in the form of a string, are supported as well.\r\nFigure 46 – Fragment of the function executing PowerShell scripts – runtime.dll, decompiled using dnSpy.\r\nLoader of .NET assemblies (loader.dll)\r\nThe current version has yet another module,  loader.dll , that is also responsible for running .NET assemblies, but in a\r\nmuch simpler way, and outside of the plugin system. It expects two arguments – a pointer to a byte array representing the\r\nassembly, and the array size. Then, the passed assembly is simply invoked.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 43 of 55\n\nFigure 47 – Fragment of the function executing .NET assemblies – loader.dll, decompiled using dnSpy.\r\nThe “TaskCore” module\r\nIn the published changelog, the author advertises multiple changes in the task-running module:\r\n14. The task module has been greatly upgraded, and a new plug-in module has been introduced to support users in secondary\r\ndevelopment of their own plug-ins.\r\nSupports multiple task execution modes:\r\nIn Memory LoadPE Execution\r\nDotNet Reflection Execution\r\nDotNet Extension Execution\r\nDotNet Extension with Zip Execution\r\n14. The task module has been greatly upgraded, and a new plug-in module has been introduced to support users in secondary\r\ndevelopment of their own plug-ins. Supports multiple task execution modes: Normal execution In Memory LoadPE\r\nExecution Powershell Execution DotNet Reflection Execution DotNet Extension Execution DotNet Extension with Zip\r\nExecution VbScript Execution JScript Execution X86 shellcode execution X64 shellcode execution Native Plugin Loader\r\n14. The task module has been greatly upgraded, and a new plug-in module has been introduced to support users i\r\nSupports multiple task execution modes:\r\nNormal execution\r\nIn Memory LoadPE Execution\r\nPowershell Execution\r\nDotNet Reflection Execution\r\nDotNet Extension Execution\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 44 of 55\n\nDotNet Extension with Zip Execution\r\nVbScript Execution\r\nJScript Execution\r\nX86 shellcode execution\r\nX64 shellcode execution\r\nNative Plugin Loader\r\nIndeed, we can see the new module  taskcore.bin  which was added in this release. Depending on the specific command\r\npassed from the C2, it may be run under the guise of multiple applications, such\r\nas:  AppLaunch.exe ,  dllhost.exe ,  rundll32.exe ,  OpenWith.exe ,  notepad.exe ,  rkeywiz.exe ,  wmpntwrk.exe ,  wmpconfig.e\r\nSimilar to  coredll.bin , it comes with RC4-encrypted strings. The list of decrypted strings (format: RVA, string) is given\r\nbelow:\r\nhttps://gist.github.com/hasherezade/47fa641d054d82de4059ff36c7e99918\r\nAs the module is in the XS2 format. The start function first finishes the initialization, then deploys the core functionality of\r\nthe modules, i.e. command parsing. Each command is responsible for executing a module of a particular type.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 45 of 55\n\nFigure 48 – Switch-case parsing the commands from the C2 received by the taskcore module.\r\nThe passed structure contains parameters filled in by the  coredll.bin , and the mapping contains the buffer with a module\r\nto be executed that was received from the C2. While some of the other modules interact only with the  coredll.bin , this\r\none is also capable of establishing its own connection with the C2 and reports there directly.\r\nAs the author mentioned, the module is able to run a variety of content formats.\r\nThe simplest of them is running shellcodes.\r\nFigure 49 – A function within taskcore.bin, executing simple shellcodes.\r\nScripts, such as JScripts and VBScripts, are both executed by the same function:\r\nFigure 50 – Fragment of a function within taskcore.bin, executing JScripts and VBScripts.\r\nUnderneath, it uses a COM interface and parses the given script with the help of a function  ParseScriptText .\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 46 of 55\n\nFigure 51 – Parsing and executing scripts using the COM interface.\r\nSimilar to the previously mentioned  stubmod.bin  (”Stealing from KeePass”), the .NET environment is manually\r\ninitialized. It is then it is used to run PowerShell scripts as well as plugins in the custom format (that are delivered in the\r\nform of .NET assemblies).\r\nFigure 52 – Function leading to the execution of a plugin (.NET assembly).\r\nBefore running the PowerShell scripts, the malware zeroes out the Environment Variable  _PSLockdownPolicy . This\r\nmodification disables the PowerShell lockdown policy, which is a security feature restricting the execution of certain actions\r\nwithin the PowerShell environment. As a result, this allows more freedom in execution of scripts.\r\nFigure 53 – Function leading to the execution of a PowerShell script.\r\nThe module also disables other security-related features: for example, it patches out AMSI checks and event tracing in\r\nNTDLL.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 47 of 55\n\nAnalyzing the strings\r\nThe functionality of the modules is vast, but because we dumped and deobfuscated all the strings, we can get a good\r\noverview of different aspects of the modules by reviewing them. Selected artifacts described below.\r\nSQLite library\r\nThere are multiple strings indicating that the module comes with a statically linked SQLite library. The presence of SQLite\r\nmodules in malware strongly suggests that it steals cookies, as cookies are kept in local SQLite databases. The\r\nRhadamanthys core comes with the version string, which leads to the particular commit of the\r\nSQLite: https://www3.sqlite.org/src/info/fe7d3b75fe1bde41 (updated since the previous version of the malware, which used\r\nan earlier commit: https://www2.sqlite.org/src/info/8180e320ee4090e4)\r\n2016-04-08 15:09:49 fe7d3b75fe1bde41511b323925af8ae1b910bc4d\r\nSQLite format 3 2016-04-08 15:09:49 fe7d3b75fe1bde41511b323925af8ae1b910bc4d\r\nSQLite format 3\r\n2016-04-08 15:09:49 fe7d3b75fe1bde41511b323925af8ae1b910bc4d\r\nIn addition to the artifacts pointing to the library itself, we can see some queries among the decrypted strings, such as the\r\nfollowing:\r\nSELECT title, url FROM (SELECT * FROM moz_bookmarks INNER JOIN moz_places ON\r\nmoz_bookmarks.fk=moz_places.id)\r\nSELECT url FROM (SELECT * FROM moz_annos INNER JOIN moz_places ON moz_annos.place_id=moz_places.id) t\r\nGROUP BY place_id\r\nSELECT title, url FROM (SELECT * FROM moz_bookmarks INNER JOIN moz_places ON\r\nmoz_bookmarks.fk=moz_places.id) SELECT url FROM (SELECT * FROM moz_annos INNER JOIN moz_places ON\r\nmoz_annos.place_id=moz_places.id) t GROUP BY place_id\r\nSELECT title, url FROM (SELECT * FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id)\r\nSELECT url FROM (SELECT * FROM moz_annos INNER JOIN moz_places ON moz_annos.place_id=moz_places.id) t GROUP BY\r\nThose queries are used for retrieving Mozilla browsing history and will be applied on the found database. They are part of\r\nthe stealer described in “Stealing from Chrome and Mozilla products”.\r\nMbed-Crypto\r\nWe can find multiple strings suggesting that the malware makes use of a statically linked library with Elliptic curves. Some\r\nof the strings can help uniquely identify the library and its version.\r\n8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D\r\n14DEF9DEA2F79CD65812631A5CF5D3ED\r\n8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D\r\n14DEF9DEA2F79CD65812631A5CF5D3ED\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 48 of 55\n\n8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D\r\n14DEF9DEA2F79CD65812631A5CF5D3ED\r\nIt turns out to be Mbed Crypto (source), an old version of the library now renamed Mbed TLS.\r\nThe source file referencing the found strings can be seen on the project’s Github: [reference 1] [reference 2]. Note that the\r\nmentioned strings are not present in the new version of the library (under the new name Mbed-TLS) which suggests that the\r\nmalware author used the old copy.\r\nAfter analyzing the application, we know that this library is used to establish the TLS connection with the C2.\r\nCJSON Library\r\nSome unencrypted strings suggest the use of JSON, implemented by the statically linked library cJSON:\r\nBUG: Unable to fetch CJSON configuration\r\nJSON parser does not support UTF-16 or UTF-32\r\ncjson BUG: Unable to fetch CJSON configuration JSON parser does not support UTF-16 or UTF-32 '[' or '{' expected\r\nunexpected token '}' expected ':' expected string or '}' expected ']' expected\r\ncjson\r\nBUG: Unable to fetch CJSON configuration\r\nJSON parser does not support UTF-16 or UTF-32\r\n'[' or '{' expected\r\nunexpected token\r\n'}' expected\r\n':' expected\r\nstring or '}' expected\r\n']' expected\r\nLooking further at the context in which those strings are used, we can see that the JSON format was applied to create reports\r\nabout the stolen content, that was retrieved by the LUA scripts. We can also find relevant artifacts among the decrypted\r\nstrings:\r\ne7bcc,'{\"root\":' e7bb0,'root' e7d58,'profile' e3814,'username' e37f8,'password' e7d40,'openvpn'\r\ne7bcc,'{\"root\":'\r\ne7bb0,'root'\r\ne7d58,'profile'\r\ne3814,'username'\r\ne37f8,'password'\r\ne7d40,'openvpn'\r\nArtifacts from 360 Browser Password stealer\r\nAmong unencrypted strings, we see the following strings that can be found in the open-source 360 Browser Password\r\ndecoder.\r\ncf66fb58f5ca3485 (4B01F200ED01)\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 49 of 55\n\ncf66fb58f5ca3485\r\n(4B01F200ED01)\r\nThe first of the strings is an AES key that is used for decrypting the password. The second is the prefix of the encrypted\r\npassword that needs to be dropped.\r\nA snippet from a Chinese website\r\nOne of the strings is quite unusual, and looks like along key or an obfuscated content:\r\n0a{1b2c3d$4e5f6g7h_8@i9jAkBl`CmDnEo[FpGqHrI~s-JtKuLvMw%NxOyPz(Q9R8S7T6)U5V4]W3X2}Y1Z0\r\n0a{1b2c3d$4e5f6g7h_8@i9jAkBl`CmDnEo[FpGqHrI~s-JtKuLvMw%NxOyPz(Q9R8S7T6)U5V4]W3X2}Y1Z0\r\n0a{1b2c3d$4e5f6g7h_8@i9jAkBl`CmDnEo[FpGqHrI~s-JtKuLvMw%NxOyPz(Q9R8S7T6)U5V4]W3X2}Y1Z0\r\nHowever, Googling for it gives few results only, leading to a Chinese website with a simple code snippet. The snippet\r\nillustrates how to generate a random file name, and the aforementioned string is just used as a charset. The implementation\r\nused in Rhadamanthys is not identical, but has analogous functionality:\r\nFigure 54 – Function generating a random file name.\r\nThe string is referenced in the fragment of code responsible for generating names for the additional executables downloaded\r\nfrom the C2 that are dropped and executed.\r\nThis piece of code is not particularly interesting, but the choice is unusual and may give a subtle hint that the author is a\r\nChinese speaker. Hovewer, it is not enough to draw any conclusions.\r\nAdditions in the version 0.5.1\r\nDuring the writing of this article, the author already released version 0.5.1. The newest version contains additions such as a\r\nClipper plugin, which watches a clipboard and replaces wallet addresses with attackers’ addresses. This version enables even\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 50 of 55\n\nmore customization – distributors can order private stubs, prepared especially for them.\r\nFigure 55 – Announcement about the version 0.5.1, published on author’s Telegram account.\r\nList of changes, as presented by the author:\r\n2.Telegram notification, you can now choose whether to send wallet crack and seed records in the log ZIP\r\n3.Google Account Cookie Recovery\r\n4.Default build stub cleaning for Windows Defender, including cloud protection\r\n1.Added Clippers plug-in 2.Telegram notification, you can now choose whether to send wallet crack and seed records in the\r\nlog ZIP 3.Google Account Cookie Recovery 4.Default build stub cleaning for Windows Defender, including cloud\r\nprotection\r\n1.Added Clippers plug-in\r\n2.Telegram notification, you can now choose whether to send wallet crack and seed records in the log ZIP\r\n3.Google Account Cookie Recovery\r\n4.Default build stub cleaning for Windows Defender, including cloud protection\r\nWe can already see that the Clipper plugin supports a rich set of targets.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 51 of 55\n\nFigure 56 – List of the applications attacked by the Clipper plugin (added in version 0.5.1).\r\nConclusion\r\nRhadamanthys is a well-designed, modular stealer. In this article, we presented some details of its implementation, showing\r\nthe incorporated techniques and execution flow. Although the core component comes with a lot of interesting built-in\r\nfeatures, the power of this malware lies in its extensibility.\r\nThe currently analyzed version 0.5.0 supports multiple scripting languages, from LUA (whose interpreter is built-in to the\r\nmain module) to PowerShell and other scripting languages, that are supported via an additional module.\r\nAs we can see, the author keeps enriching the set of available features, trying to make it not only a stealer but a multipurpose\r\nbot, by enabling it to load multiple extensions created by a distributor. The added features, such as a keylogger, and\r\ncollecting information about the system, are also a step towards making it a general-purpose spyware.\r\nIt is evident that with the fast pace and ongoing development, Rhadamanthys is trying hard to become a big player on the\r\nmalware market and is most likely here to stay.\r\nCheck Point customers remain protected from the threats described in this research.\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 52 of 55\n\nCheck Point’s Threat Emulation provides comprehensive coverage of attack tactics, file types, and operating\r\nsystems and has developed and deployed a signature to detect and protect customers against threats described in this\r\nresearch.\r\nCheck Point’s Harmony Endpoint provides comprehensive endpoint protection at the highest security level, crucial to\r\navoid security breaches and data compromise. Behavioral Guard protections were developed and deployed to protect\r\ncustomers against threats described in this research.\r\nBG:\r\nInfoStealer.Wins.Rhadamanthys.E/F\r\nBS:\r\nInfoStealer.Wins.Rhadamanthys.C/D/G\r\nTE/Harmony Endpoint protections:\r\nInfoStealer.Wins.Rhadamathys.C/D/G\r\nIOC/Analyzed samples\r\nID Hash Module type Format\r\n#1.1 bb8bbcc948e8dca2e5a0270c41c062a29994a2d9b51e820ed74d9b6e2a01ddcf\r\nStage 1 (version\r\n0.5.0)\r\nPE\r\n#1.2.1 22a67f510dfb7ca822b5720b89cd81abfa5e63fefa1cdc7e266fbcbb0698db33\r\nStage 2: main\r\nmodule\r\nXS1\r\n#1.2.2 6ed3ac428961b350d4c8094a10d7685578ce02c6cd41cc7f98d8eeb361f0ee38 dt.x86.bin XS1\r\n#1.2.3 4fd469d08c051d6997f0471d91ccf96c173d27c8cff5bd70c3f2c5008faa786f early.x86.bin XS1\r\n#1.2.4 633b0fe4f3d2bfb18d4ad648ff223fe6763397daa033e9c5d79f2cae89a6c3b2 early.x64.bin XS1\r\n#1.2.5 50b1f29ccdf727805a793a9dac61371981334c4a99f8fae85613b3ee57b186d2 phexec.bin XS1\r\n#1.2.6 01609701a3ea751dc2323bec8018e11742714dc1b1c2dcb39282f3c4a4537c7d netclient.x86.bin XS1\r\n#1.2.7 a905226a2486ccc158d44cf4c1728e103472825fb189e05c17d998b9f5534d63 proto_x86.bin shellcode\r\n#1.2.8 ed713454c20844522304c49cfe25fe1490418c300e5ab0c9fca431ede1e91d7b strategy.x86.bin XS1\r\n#1.2.9 f82ec2246dde81ca9edb69fb9c7ce3f7101f5ffcdc3bdb86fea2a5373fb026fb unhook.bin XS1\r\n#1.3.1 ee4a487e78f23f5dffc35e73aeb9602514ebd885eb97460dd26635f67847bd16\r\nStage 3: main\r\nstealer\r\ncomponent:\r\n“coredll.bin” (32-\r\nbit)\r\nXS2\r\n#1.3.2 fcb00beaa88f7827999856ba12302086cadbc1252261d64379172f2927a6760e\r\nStage 3\r\nsubmodule:\r\n“KeePassHax.dll”\r\nPE\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 53 of 55\n\nID Hash Module type Format\r\n#1.3.3 a87032195e38892b351641e08c81b92a1ea888c3c74a0c7464160e86613c4476\r\nStage 3\r\nsubmodule:\r\n“runtime.dll”\r\nPE\r\n#1.3.4 3d010e3fce1b2c9ab5b8cc125be812e63b661ddcbde40509a49118c2330ef9d0\r\nStage 3\r\nsubmodule:\r\n“loader.dll”\r\nPE\r\n#1.3.5 ecab35dfa6b03fed96bb69ffcecd11a29113278f53c6a84adced1167b66abe62\r\nStage 3\r\nsubmodule:\r\n“stubmod.bin”\r\n(32-bit)\r\nXS2\r\n#1.3.6 5890b47df83b992e2bd8617d0ae4d492663ca870ed63ce47bb82f00fa3b82cf9\r\nStage 3\r\nsubmodule:\r\n“taskcore.bin”\r\n(32-bit)\r\nXS2\r\n#1.3.7 2b6faa98a7617db2bd9e70c0ce050588c8b856484d97d46b50ed3bb94bdd62f7\r\nStage 3\r\nsubmodule:\r\n“stubexec.bin”\r\n(32-bit)\r\nXS2\r\n#1.3.8 f1f33618bbb8551b183304ddb18e0a8b8200642ec52d5b72d3c75a00cdb99fd4\r\nStage 3: main\r\nstealer\r\ncomponent:\r\n“coredll.bin” (64-\r\nbit)\r\nXS2\r\nAppendix\r\nOur other writeups on Rhadamanthys:\r\n[1] “From Hidden Bee to Rhadamanthys – The Evolution of Custom Executable Formats”.\r\n[2] “Rhadamanthys: The”Everything Bagel” Infostealer”\r\nMore about used techniques:\r\n[3] https://redops.at/en/blog/direct-syscalls-vs-indirect-syscalls\r\n[4] https://media.defcon.org/DEF CON 30/DEF CON 30 presentations/Tarek Abdelmotaleb Dr. Bramwell Brizendine –\r\nWeaponizing Windows Syscalls as Modern 32-bit Shellcode – paper.pdf\r\n[5] https://whiteknightlabs.com/2021/12/11/bypassing-etw-for-fun-and-profit/\r\n[6] https://www.malwarebytes.com/blog/news/2018/01/a-coin-miner-with-a-heavens-gate\r\n[7] https://www.codeproject.com/Articles/11003/The-coding-gentleman-s-guide-to-detecting-the-NET\r\n[8] https://codingvision.net/calling-a-c-method-from-c-c-native-process\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 54 of 55\n\n[9] https://communities.bentley.com/products/programming/microstation_programming/f/archived-microstation-v8i-programming-forum/64713/write-a-com-server-in-c—call-from-vba-c-or-c-or-vb-net\r\nSource: https://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nhttps://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/\r\nPage 55 of 55\n\n https://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/  \nFigure 44-List of classes on the runtime.dll (decompiled using dnSpy).\nThe plugins are in the form of .NET assemblies.  \n  Page 42 of 55",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"ETDA",
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://research.checkpoint.com/2023/rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components/"
	],
	"report_names": [
		"rhadamanthys-v0-5-0-a-deep-dive-into-the-stealers-components"
	],
	"threat_actors": [
		{
			"id": "8941e146-3e7f-4b4e-9b66-c2da052ee6df",
			"created_at": "2023-01-06T13:46:38.402513Z",
			"updated_at": "2026-04-12T02:00:03.085596Z",
			"deleted_at": null,
			"main_name": "Sandworm",
			"aliases": [
				"FROZENBARENTS",
				"Seashell Blizzard",
				"Quedagh",
				"TEMP.Noble",
				"ELECTRUM",
				"UAC-0113",
				"UAC-0082",
				"APT44",
				"VOODOO BEAR",
				"IRON VIKING",
				"G0034",
				"TeleBots",
				"IRIDIUM",
				"Blue Echidna"
			],
			"source_name": "MISPGALAXY:Sandworm",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "3a0be4ff-9074-4efd-98e4-47c6a62b14ad",
			"created_at": "2022-10-25T16:07:23.590051Z",
			"updated_at": "2026-04-12T02:00:04.579883Z",
			"deleted_at": null,
			"main_name": "Energetic Bear",
			"aliases": [
				"ATK 6",
				"Blue Kraken",
				"Crouching Yeti",
				"Dragonfly",
				"Electrum",
				"Energetic Bear",
				"G0035",
				"Ghost Blizzard",
				"Group 24",
				"ITG15",
				"Iron Liberty",
				"Koala Team",
				"TG-4192"
			],
			"source_name": "ETDA:Energetic Bear",
			"tools": [
				"Backdoor.Oldrea",
				"CRASHOVERRIDE",
				"Commix",
				"CrackMapExec",
				"CrashOverride",
				"Dirsearch",
				"Dorshel",
				"Fertger",
				"Fuerboos",
				"Goodor",
				"Havex",
				"Havex RAT",
				"Hello EK",
				"Heriplor",
				"Impacket",
				"Industroyer",
				"Karagany",
				"Karagny",
				"LightsOut 2.0",
				"LightsOut EK",
				"Listrix",
				"Oldrea",
				"PEACEPIPE",
				"PHPMailer",
				"PsExec",
				"SMBTrap",
				"Subbrute",
				"Sublist3r",
				"Sysmain",
				"Trojan.Karagany",
				"WSO",
				"Webshell by Orb",
				"Win32/Industroyer",
				"Wpscan",
				"nmap",
				"sqlmap",
				"xFrost"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "a66438a8-ebf6-4397-9ad5-ed07f93330aa",
			"created_at": "2022-10-25T16:47:55.919702Z",
			"updated_at": "2026-04-12T02:00:03.467242Z",
			"deleted_at": null,
			"main_name": "IRON VIKING",
			"aliases": [
				"APT44 ",
				"ATK14 ",
				"BlackEnergy Group",
				"Blue Echidna ",
				"CTG-7263 ",
				"ELECTRUM ",
				"FROZENBARENTS ",
				"Hades/OlympicDestroyer ",
				"IRIDIUM ",
				"Qudedagh ",
				"Sandworm Team ",
				"Seashell Blizzard ",
				"TEMP.Noble ",
				"Telebots ",
				"Voodoo Bear "
			],
			"source_name": "Secureworks:IRON VIKING",
			"tools": [
				"BadRabbit",
				"BlackEnergy",
				"GCat",
				"NotPetya",
				"PSCrypt",
				"TeleBot",
				"TeleDoor",
				"xData"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "b3e954e8-8bbb-46f3-84de-d6f12dc7e1a6",
			"created_at": "2022-10-25T15:50:23.339976Z",
			"updated_at": "2026-04-12T02:00:04.384657Z",
			"deleted_at": null,
			"main_name": "Sandworm Team",
			"aliases": [
				"Sandworm Team",
				"ELECTRUM",
				"Telebots",
				"IRON VIKING",
				"BlackEnergy (Group)",
				"Quedagh",
				"Voodoo Bear",
				"IRIDIUM",
				"Seashell Blizzard",
				"FROZENBARENTS",
				"APT44"
			],
			"source_name": "MITRE:Sandworm Team",
			"tools": [
				"Bad Rabbit",
				"Mimikatz",
				"Exaramel for Linux",
				"Exaramel for Windows",
				"GreyEnergy",
				"PsExec",
				"Prestige",
				"P.A.S. Webshell",
				"AcidPour",
				"VPNFilter",
				"Neo-reGeorg",
				"Cyclops Blink",
				"SDelete",
				"Kapeka",
				"AcidRain",
				"Industroyer",
				"Industroyer2",
				"BlackEnergy",
				"Cobalt Strike",
				"NotPetya",
				"KillDisk",
				"PoshC2",
				"Impacket",
				"Invoke-PSImage",
				"Olympic Destroyer"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434370,
	"ts_updated_at": 1775960507,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/1436a8ea269cba1a82e72f72af783703100d2a3f.pdf",
		"text": "https://archive.orkl.eu/1436a8ea269cba1a82e72f72af783703100d2a3f.txt",
		"img": "https://archive.orkl.eu/1436a8ea269cba1a82e72f72af783703100d2a3f.jpg"
	}
}