{
	"id": "093204db-ea17-4a7d-95c1-18057cd32e62",
	"created_at": "2026-04-06T00:16:32.487559Z",
	"updated_at": "2026-04-10T03:22:39.318107Z",
	"deleted_at": null,
	"sha1_hash": "3bd693224c041be5b6d5d5c1bd6da107feaae741",
	"title": "Dancing With Shellcodes: Analyzing Rhadamanthys Stealer",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 12990438,
	"plain_text": "Dancing With Shellcodes: Analyzing Rhadamanthys Stealer\r\nBy Eli Salem\r\nPublished: 2023-01-16 · Archived: 2026-04-05 21:26:53 UTC\r\n20 min read\r\nJan 16, 2023\r\nThreat Background\r\nRhadamanthys is a newly emerged Information-Stealer that is written in C++. according to multiple reports[1] the\r\nmalware has been active since late 2022.\r\nIn addition, the malware appears to masquerade itself as legitimate software such as AnyDesk installers[2], and\r\nGoogle Ads[3][13] to get the initial foothold.\r\nAs for usage, in the dark web, the malware authors offer various deals for using the malware such as monthly or\r\neven lifetime payments.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 1 of 52\n\nRhadamanthys\r\nAlso, the authors emphasize the malware's capabilities ranging from stealing digital coins, and system information\r\ncollection, to execution of other processes such as Powershell.\r\nIn this article, I will investigate the Rhadamanthys stealer and reverse engineer the entire chain, from the first\r\ndropper to the malware itself.\r\nAs always, I will do it in a hybrid step-by-step tutorial and an actual presentation and will focus on the parts that I\r\npersonally find more interesting(the ways the malware tries to evade detection).\r\n1. PART 1: The Dropper\r\n- Unpacking mechanism: getting to the first shellcode\r\n- Shellcode execution via Callback\r\n- Investigating the first shellcode\r\n- Fixing functions statically: Defining functions\r\n- Fixing functions statically: Defining code\r\n- Fixing the shellcode: Rebase the address\r\n- Shellcode functionality\r\n- Summarize the first shellcode\r\n2. PART 2: The second shellcode aka Rhadamanthys loader\r\n- Evasion technique: Multiple Anti-Analysis\r\n- Evasion technique: Manipulate exception handling\r\n- Evasion technique: Avoiding error messages\r\n- Evasion technique: Creating Mutex and impersonating a legitimate\r\n- Evasion technique: Unhooking API calls\r\n- Config Decryption\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 2 of 52\n\n- Network\r\n- Loader’s goal\r\n3. PART 3: The Nsis module- The Rhadamanthys stealer\r\n- Nsis loader\r\n- Rhadamanthys stealer capabilities\r\n- Resolving APIs dynamically\r\n- Evasion technique: Check and possibly manipulate AVAST’s AMSI-related modules\r\nThe Dropper\r\nFile hash: 89ec4405e9b2cab987f2e4f7e4b1666e\r\nThe dropper\r\nThe Rhadamanthys’s dropper is a 32-bit file and similar to many droppers, it has relatively large entropy which\r\nindicates potentially packed content inside of it.\r\nOne of the relatively new features of PEstudio is the ability to check if the ASLR[4] feature is enabled. In my\r\nanalysis, I always prefer to disable the ASLR so the addresses in IDA and in XDBG will be the same for tracking\r\npurposes.\r\nIn PEstudio, go to “optional-header” and then to the ASLR bar, then you can see under the “detail” column if it is\r\nfalse (disabled) or true (enabled).\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 3 of 52\n\nCheck ASLR\r\nUnpacking mechanism: getting to the first shellcode\r\nAs we observe the dropper in IDA, we see a large embedded “blob” in the .rdata section. Usually, these kinds of\r\nblobs can potentially contain data that will be decrypted during runtime.\r\nPress enter or click to view image in full size\r\nBlob\r\nThe first activity the dropper do is to create a new heap\r\nCreating new heap\r\nThen, the function sub_408028 will be the core function that will deal with encrypting the blob. Inside\r\nsub_408028, there are two interesting functions:\r\n1. sub_406A28 - this function is responsible for returning an address containing the data to be written.\r\n2. sub_408528 - a wrapper of memcpy\r\nIn the first iteration, the embedded blob will be written into the newly created heap\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 4 of 52\n\nDecrypting the shellcode\r\nNext, the same function will override the blob and will decrypt a shellcode.\r\nDecrypting the shellcode\r\nThen, a call to VirtualAlloc will happen to create a newly allocated memory followed by memcpy to copy the\r\nshellcode from the heap to the new memory. Lastly, a VirtualProtect API call will be used to change the\r\npermission of the memory segment to RWX.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 5 of 52\n\nDecrypting the shellcode\r\nThe entire chain can also be seen in the following pseudo-code of IDA pro:\r\nPress enter or click to view image in full size\r\nDecrypting the shellcode\r\nThe next thing we’ll do is go to the address 004065A1 in the WinMain function (remember, ASLR is disabled so\r\nwe can navigate easily in IDA and the debugger).\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 6 of 52\n\nWe could see that the value of the shellcode (that is dynamically located in the EAX register) is being transferred\r\nto another offset variable 42F6F0.\r\nAssign the shellcode address\r\nShellcode execution via Callback\r\nAfter having a shellcode with EXECUTE permission, we need a way to execute it, in this case, the authors choose\r\na cool trick in form of a Callback function.\r\nThe shellcode execution will go as the following:\r\n1. The function sub_405728 is responsible to invoke the API call ImmEnumInputContext\r\n2. sub_405728 receives as a parameter function named sub_407228 which is just a wrapper for another\r\nfunction that jumps to the shellcode address\r\n3. The final result is that ImmEnumInputContext will get the address of the shellcode in its second argument\r\n“lpfn” and will execute it.\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 7 of 52\n\nImmEnumInputcontext function in Microsoft documentation\r\nThe logic can be seen in the following pseudo-code\r\nPress enter or click to view image in full size\r\nShellcode execution\r\nThe reason for choosing this way is most likely to evade anti-virus products that rely on CreateThread \\\r\nCreateRemoteThread as a trigger point to scan addresses that may contain malicious content.\r\nShellcode entry point\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 8 of 52\n\nInvestigating the first shellcode\r\nTo investigate the shellcode we can choose one of the two:\r\n1. Dump the entire allocated buffer and run it in Blobrunner[5]\r\n2. Continue with the code dynamically (because why not?)\r\nTo investigate it statically, we obviously must dump the shellcode, to do it do the following:\r\n1. Right click on the address of the shellcode and click “Follow in Memory Map”\r\nGoing to the memory map\r\n2. Then, in the memory map, right click on the shellcode address and then “Dump Memory to File”\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 9 of 52\n\nDumping the shellcode\r\nThen, drag and drop the dumped file in IDA.\r\nTo summarize the steps until now see the following graph\r\nPress enter or click to view image in full size\r\nFixing the shellcode: Defining functions\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 10 of 52\n\nAfter the shellcode was loaded, we can see 5 functions that appear in the Function name bar. In addition, in the\r\nnavigation bar, we can see the colors blue and brown.\r\nAccording to the IDA website[6] blue means “Regular functions, i.e. functions not recognized by FLIRT or\r\nLumina.”\r\nAnd brown means “Instructions(code) not belonging to any functions. These could appear when IDA did not\r\ndetect or misdetected function boundaries, or hint at code obfuscation being employed which could prevent proper\r\nfunction creation. It could also be data incorrectly being treated as code.”\r\nAnd when we look at an area in the IDA view that contains both we see the following:\r\nDefining functions\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 11 of 52\n\nWe can obviously see that the brown color is a legit code, however, IDA doesn't consider it as a code and therefore\r\ndoes not show it as a function.\r\nTo fix this, we can just scroll and observe statically from where this function starts and when it ends.\r\nIn our case, it starts at the address 000029E, we also see the prologue:\r\npush ebp\r\nmov ebp, esp\r\nAnd ends at the address 000036B with the epilogue:\r\nleave\r\nretrn\r\nPress enter or click to view image in full size\r\nDefining functions\r\nNow that we know the function boundaries, we can mark it all, and click “P”\r\nDefining functions\r\nThen, we can see that the brown code is now considered a function, and a new function sub_29E was added to the\r\nfunction name bar.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 12 of 52\n\nDefining functions\r\nNOTE: When fixing functions do not assume that the first “retrn” is the end of a function, pay attention to the\r\njumps that might bypass this return and might indicate a longer function.\r\nFixing the shellcode: Defining code\r\nIn addition to the convenient scenario of a code that looks like code and just doesn't interpret as a function, we\r\nhave a more tricky scenario when we need to change the data itself.\r\nAt the beginning of the shellcode, we can see dynamically the assembly code “call 450028” that suppose to take\r\nus to the address in 450028 which starts with “pop eax” and eventually calls to the function in the address 45029E\r\nwhich in our case called sub_29E.\r\nHowever, as we can see, statically we just see jibberish and it does not look like the dynamic view.\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 13 of 52\n\nDefining as code\r\nTo fix it, we need to tell IDA that some specific addresses are actual code.\r\nFor example: in the dynamic view, we can see that the first 5 bytes are:\r\nCall 450028\r\nTherefore, we should tell IDA that the first 5 bytes are code, then, we can tell IDA to look at it as a function.\r\nTo do it, do the following:\r\n1. Mark the data\r\n2. Right click\r\n3. Click on “Undefine”\r\nDefining as code\r\nThen, mark the 5 bytes and tell IDA to look at it as Code.\r\nDefining as code\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 14 of 52\n\nDefining as code\r\nAfter doing it, we can see that the same data looks like the code from the debugger view\r\nDefining as code\r\nAnd as said, we can always turn it into a function of its own (because why not?)\r\nDefining as function\r\nAs we see, the function jumps to the address at “loc_28” (IDA) or “450028” (debugger), however in IDA this\r\ncontent also needs to be fixed. Combining the two approaches of defining as code and defining as function can fix\r\nwill do the trick.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 15 of 52\n\nDefining as code and defining as function\r\nAfter doing that, we now have 8 functions in the function name bar.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 16 of 52\n\nFunction bar\r\nFixing the shellcode: Rebase the address\r\nThe last thing we need to do if we want to properly analyze the shellcode alongside the debugger is to match the\r\naddresses. To do it do the following:\r\n1. Go to Edit\r\n2. Segments\r\n3. Rebase program\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 17 of 52\n\nRebase\r\n4. Change the value to the value of the actual entry point of the shellcode in the debugger\r\n5. Click OK\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 18 of 52\n\nRebase\r\nAnd now we can see that the addresses statically and dynamically the same\r\nRebase\r\nFinally, we can start and actually analyze the shellcode\r\nShellcode functionality\r\nThe first thing we can see is that the actual code in shellcode is very small, there are 8\\9 functions, and the rest is a\r\nbig chunk of data. From this, we can assume that the shellcode will potentially use that data.\r\nSo let's “go with the flow” and understand this shellcode\r\n1. sub_450000 just jumps to sub_450028\r\n2. sub_450028 jump jumps to sub_45029E\r\nsub_45029E is a larger function that contains multiple functions.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 19 of 52\n\nPress enter or click to view image in full size\r\nShellcode functionality\r\nsub_450249\r\nThis function access the Process Environment Block to get the address of Kernel32.dll. This behavior is traditional\r\nand happens in many shellcodes.\r\nPress enter or click to view image in full size\r\nGet kernel32 address\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 20 of 52\n\nsub_45036E\r\nThis function gets 3 arguments\r\n1. Kernel32 address\r\n2. Hashes\r\n3. An array that holds 4 functions\r\nIt then iterates through the kernel32 export functions and sends the names of the functions to another function\r\nnamed sub_45040C. The only job of sub_45040C is to hash the function name it receives and return the hash.\r\nPress enter or click to view image in full size\r\nHashing function\r\nThen, sub_45036E checks if the hashed function name matches the hash it got as an argument, if yes, it puts it in\r\nthe array and sends it back to sub_45029E.\r\nOverall the functions will be “VirtualAlloc, LocalFree, LocalAlloc, VirtualFree”\r\nsub_450077\r\nThis function will decrypt the large data that is stored in our shellcode, and write it to the LocalAlloc we saw. This\r\nbeginning of the decrypted data will look like this\r\nDecrypting data\r\nNext, in the address 00450314, we can see the call for VirtualAlloc, don't forget to observe the allocated memory\r\nusing follow in dump of the EAX register (in my case it's 00470000).\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 21 of 52\n\nshellcode functionality\r\nsub_45003A\r\nThis function will happen several times and it is basically a memcpy that copies data from one variable to the\r\nother.\r\ncopy function\r\nsub_45003A will get the decrypted content and our newly allocated memory as arguments and will copy the data\r\nto it.\r\ncopied data\r\nAnd finally, in the address 00450365, we have a “call ebx” that will take us into this our allocated memory in the\r\noffset 5BAB, and as we can see, it's also another shellcode.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 22 of 52\n\nJump to another shellcode\r\nSummarize the first shellcode\r\nTo summarize the entire shellcode activity, we can look at it from a code point of view\r\nPress enter or click to view image in full size\r\nShellcode functionality\r\nAnd from the following graph's point of view\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 23 of 52\n\nPress enter or click to view image in full size\r\nSecond shellcode decryption\r\nThe second shellcode aka Rhadamanthys loader\r\nThe main objective of this shellcode is to be the actual loader of the Rhadamanthys stealer. This shellcode has\r\nmultiple evasion capabilities and we will observe some of them.\r\nNote- In a similar way to the first shellcode, some fixes are needed.\r\nEvasion Technique: Multiple Anti-Analysis\r\nThe Rhadamanthys loader contains large anti-analysis checks stolen from the al-khaser project[7]. This project\r\nwas also used in the Bumblebee malware.\r\nSome of the checks are checking for a virtual environment\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 24 of 52\n\nAnti-analysis checks\r\nAnti-analysis checks\r\nChecks for specific users that could hint about a lab environment\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 25 of 52\n\nAnti-analysis checks\r\nCheck for security-related DLLs\r\nAnti-analysis checks\r\nAt this point, it will be useless to continue writing the anti-analysis capabilities, so for those who want to see all,\r\nplease visit the al-khaser project GitHub page.\r\nEvasion Technique: Manipulate Exception Handling\r\nOne of the most interesting capabilities of the Rhadamanthys loader is exception-handling manipulation.\r\nWhat is Exception handling?\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 26 of 52\n\nAccording to Microsoft’s documentation[9]: “Structured exception handling (SEH) is a Microsoft extension to C\r\nand C++ to handle certain exceptional code situations, such as hardware faults, gracefully.”\r\nThe SEH is basically a linked list that has two pointers:\r\n1. A pointer to the next SEH record\r\n2. A pointer to the function that contains the code to deal with the error\r\nExamples of errors are division by 0, and excessive string length.\r\nMicrosoft allows programmers to create their own exception handlers in order to manage errors by themselves.\r\nHow the loader uses it?\r\nFirst, the loader gets the address of ZwQueryInformationProcess, then it saves it on another variable. Eventually,\r\nwe enter the function named sub_5978.\r\nPress enter or click to view image in full size\r\nGetting ZwQueryInformationProcess\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 27 of 52\n\nIn sub_5978, the loader gets the address of KiUserExceptionDispatcher and starts to iterate on it to search for a\r\nspecific location where ZwQueryInformationProcess is called.\r\nPress enter or click to view image in full size\r\nIterating in KiUserExceptionDispatcher\r\nIn sub_5A5C the loader set the hook in the desired location of the call to ZwQueryInformationProcess\r\nPress enter or click to view image in full size\r\nPatch KiUserExceptionDispatcher\r\nSo how the change looks like?\r\nIn the following image, we can see the call to ZwQueryInformationProcess that happens inside\r\nKiUserExceptionDispatcher from Ntdll as part of KiUserExceptionDispatcher's legitimate behavior.\r\nAfter the change, we can see that the call was replaced to jump to a function in the loader that will perform the\r\nZwQueryInformationProcess and will modify the ProcessInformation flag to be 6D or\r\nMEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 28 of 52\n\nWhy does this flag matters?\r\nThis flag determines whether to allow execution outside the memory space of the loaded module. In other words,\r\nit enables exception handling to be performed on shellcode.\r\nPress enter or click to view image in full size\r\nKiUserExceptionDispatcher after the patch\r\nSo how the exception handling will be managed?\r\nWithout being noticed, the initial dropper has registered an SEH record in the process memory with the name\r\n_except_handler3. Therefore, every exception that will be triggered by the shellcode will go there and will be\r\nmanaged by whatever logic the author decided.\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 29 of 52\n\n_except_handler3\r\nThis activity is most likely done to avoid raising suspicions if errors or exceptions anomalies will trigger.\r\nGet Eli Salem’s stories in your inbox\r\nJoin Medium for free to get updates from this writer.\r\nRemember me for faster sign in\r\nThe entire activity can be seen in the following graph\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 30 of 52\n\nManipulating the SEH\r\nEvasion Technique: Avoiding error message\r\nAfter controlling the exceptions, the loader will use the API call SetErrorMode with 0x8003 as an argument, this\r\nargument consists of the following three:\r\n1. SEM_NOOPENFILEERRORBOX - The system does not display the critical-error-handler message box.\r\nInstead, the system sends the error to the calling process.\r\n2. SEM_NOGPFAULTERRORBOX — The system does not display the Windows Error Reporting dialog.\r\n3. SEM_FAILCRITICALERRORS — The OpenFile function does not display a message box when it fails to\r\nfind a file. Instead, the error is returned to the caller.\r\nIn other words, the loader doesn't want the system to display any error on the screen, and wants to handle them by\r\nhimself.\r\nSimilar to controlling the exception handling, this is another maneuver of the loader to not raise any suspicions.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 31 of 52\n\nsetErrorMode\r\nEvasion Technique: Creating Mutex and impersonating a legitimate\r\nThe loader continues with creating a Mutex with the name that starts with “Global\\MSCTF.Asm.{digits}”.\r\nCreating Mutex\r\nNote that mutexes with this name are already found in the OS and are created by MSCTF.dll, and more info can be\r\nfound in this[10] article.\r\nAfter creating the Mutex, we moved to a function named sub_2B92 which holds the core activity and the main\r\npurpose of the loader.\r\nEvasion Technique: Disabling hooks\r\nIn the function named sub_8060, we see one of the cool tricks of malware to protect themselves against user mode\r\nhooking.\r\nIt first gets a handle to ntdll.dll and loads it to virtual memory, then, the loader gets the handle of the real ntdll.dll\r\nthat is already loaded.\r\nPress enter or click to view image in full size\r\nCheck for hooks\r\nIt will then copy the bytes of the SYSCALL of ZwProtectVirtualMemory into another virtual memory in order to\r\nuse it without explicitly using the ZwProtectVirtualMemory in ntdll address space.\r\nThen, it will get the export table of both real and fake modules and will iterate on them. They will be compared\r\nusing memcmp, and if they will found different, the loader will change the protection of the real function of ntdll\r\nand will use memcpy to copy the data from the fake to the real one. In this way, the malware verifies that no hooks\r\nare set.\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 32 of 52\n\nCheck for hooks\r\nIf we inspect it dynamically, this is a normal state when two functions are compared. We can see that the virtual\r\naddress is different but the bytes are the same\r\nCheck for hooks\r\nFor learning purposes, I changed the first byte of the real function to start with E9. Then, the loader took us to the\r\nmemcpy function that copied the data from the fake to the real to correct the change I made.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 33 of 52\n\nDisable hooks\r\nExcept for ntdll.dll, the loader will check the following DLLs:\r\n1. User32.dll\r\n2. Advapi32.dll\r\n3. Ole32.dll\r\nCheck for hooks in other DLLs\r\nThe entire activity can be seen in the following graph (Was lazy so I just copy paste this from my previous blob)\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 34 of 52\n\nCheck for hooks logic\r\nConfig Decryption\r\nThe config decryption occurs in a function named sub_3DD4, which is a function that will do various activities\r\nthat the main loader activity requires.\r\nIn sub_3DD4 we have two functions that will deal with the config decryption: sub_28AA and sub_2911.\r\nsub_28AA\r\nThis function is basically just an RC4 algorithm\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 35 of 52\n\nConfig decryption\r\nsub_2911\r\nThis function is also part of the decryption algorithm\r\nConfig decryption\r\nWhen we step over sub_2911 dynamically, we can see the data that hold the encrypted config at the third\r\nargument (address 42F6F8 in my case).\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 36 of 52\n\nConfig decryption\r\nIn our case, we can see that the C2 will be http://185[.]209.160.99/blob/top.mp4\r\nNetwork\r\nTo start the network activity, the loader first collects two key pieces of information from the machine:\r\n1. The default language using GetUserDefaultLangID\r\n2. The Locale using GetLocaleInfoW\r\nThen, the same function will start to set the user-agent to send the data to the C2 which is the decrypted config we\r\nsaw.\r\nCollect information about the machine\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 37 of 52\n\nSet the User-Agent\r\nTo communicate, the loader dynamically resolves multiple functions such as socket, WSAIotcl, and\r\nCreateCompletionPort to use the IOCP socket model.\r\nNetwork activity\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 38 of 52\n\nThe loader uses WSAIoctl to invoke a handler for LPFN_CONNECTEX to use the ConnectEx function.\r\nPress enter or click to view image in full size\r\nGetting ConnectEx\r\nEventually, the loader communicates with the APIs WSARecv \u0026 WSASend.\r\nPress enter or click to view image in full size\r\nSend \u0026 Recieve data\r\nIf we want to observe dynamically the data that is sent to the C2, do the following:\r\n1. Set a breakpoint at the address where WSASend is being executed.\r\n2. Follow in dump the address of the second parameter aka lpBuffers\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 39 of 52\n\n3. This buffer is a WSABUF structure, and its second parameter is a pointer to the actual buffer that is sent to\r\nthe C2.\r\n4. To see it, just follow in dump\r\nPress enter or click to view image in full size\r\nObserving data send to the C2\r\nObserving data send to the C2\r\nLoader’s goal\r\nAfter performing its various capabilities and tricks, the loader will execute its main goal.\r\n1. The loader will download a DLL from the C2\r\n2. Write it to the disk with the name of nsis_uns[xxxxxx].dll\r\n3. Spawn Rundll32 to execute the DLL with the export function “PrintUIEntry” which is a name of a\r\nlegitimate export function of the printui.dll.\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 40 of 52\n\nLoader goal\r\nNSIS Module: The Rhadamanthys stealer\r\nThe Nsis module consists of two parts:\r\n1. A loader (the Nsis module before unpacking)\r\n2. The actual stealer\r\nNSIS Loader\r\nThe loader is executed via a very long command that changed in every iteration\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 41 of 52\n\nNsis module command\r\nThe interesting thing about the NSIS loader is that there are many loaders out there, but their detection rate is very\r\nlow!\r\nNsis loader low detection rate\r\nFor the loader behavior, the NSIS loader just allocates data using LocalAlloc and copies it to mapped memory\r\nusing MapViewOfFile and memmove. Eventually, it will jump to the shellcode address.\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 42 of 52\n\nLoader main goal\r\nDue to time constraints, I will not display this shellcode, however, it is just a small shellcode that unpacks and\r\ninject into the memory the Rhadamanthys stealer itself.\r\nRhadamanthys stealer capabilities\r\nFinally, we arrived at the stealer himself!!!\r\nDisclaimer: because of not abling to dynamically analyze the sample when the C2 was on, I only got the stealer\r\nfrom the following tria.ge sandbox link[11].\r\nAlso, for this part, I will only focus on the stealing capabilities and its targets.\r\nStealing KeePass passwords\r\nThe malware appears to be able to use the DLL KeePassHax[12], an open-source tool used to decrypt the\r\npassword database.\r\nKeepass\r\nUsage of SQLite\r\nThe malware can collect and extract data using SQLite\r\nPress enter or click to view image in full size\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 43 of 52\n\nSqlite\r\nTarget multiple browsers\r\nThe malware target the following browsers in their info-stealing activity:\r\n1. Coc CoC\r\n2. Pale Moon\r\n3. Sleipnir5\r\n4. Opera\r\n5. Chrome\r\n6. Twinkstar\r\n7. Firefox\r\n8. Edge\r\nPress enter or click to view image in full size\r\nBrowsers\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 44 of 52\n\nTarget OpenVPN\r\nThe malware appears to get the profile, username, and password of OpenVPN.\r\nOpenVPN\r\nTarget steam accounts\r\nThe malware appears to aim at Steam’s config\\loginusers.vdf which contains information about Steam’s users.\r\nPress enter or click to view image in full size\r\nValve\r\nTarget FileZilla passwords\r\nThe malware search for FileZila’s specific files:\r\n1. recentservers.xml\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 45 of 52\n\n2. sitemanager.xml\r\nThese two files contain the passwords and other data of the FTP accounts.\r\nFileZilla\r\nTarget CoreFTP\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 46 of 52\n\nCoreFTP\r\nTarget Discord\r\nThe malware collects information from the discord directories, possibly to extract further data.\r\nDiscord\r\nCollecting Telegram data\r\nThe malware targets Telegram desktop data which is located in encrypted files (such as D877F783D5D3EF8) in\r\nthe “tdata” directory.\r\nTelegram\r\nCollecting information from various email\r\nThe malware target the following email clients:\r\n1. Foxmail\r\n2. Outlook\r\n3. The BAT\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 47 of 52\n\nEmails\r\nExtracting web credentials using Vaultcli functions\r\nVault activity\r\nTarget WinSCP\r\nThe malware target sensitive registry keys of the WinSCP in order to collect information.\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 48 of 52\n\nWinSCP\r\nTarget CryptoCurrency entities\r\nThe malware target the following cryptocurrencies entities and wallets:\r\n1. Dogecoin\r\n2. Litecoin\r\n3. Monero\r\n4. Qtum\r\n5. Armory\r\n6. Bytecoin\r\n7. Binance\r\n8. Electron\r\n9. Solar waller\r\n10. Zap\r\n11. WalletWasabi\r\n12. Zcash\r\n13. Ronin\r\n14. Avana\r\n15. OKX\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 49 of 52\n\nCrypto\r\nQuerying registry keys for digital coming entities from Joe[\r\nResolving APIs dynamically\r\nThe stealer is resolving dynamically his APIs using the GetModuleHandle and GetProcAddress API calls.\r\nDynamic resolving\r\nEvasion technique: Modify and possibly manipulate AVAST modules\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 50 of 52\n\nThe stealer uses the same code that was used in the loader to verify and unhook functions and the same function\r\nappears to aim for the AVAST-related modules aswhook.dll \u0026 aswAMSI.dll.\r\nPress enter or click to view image in full size\r\nCheck AVAST’s AMSI-related DLLs\r\nMore amsi-related functions and DLLs that are being targeted by the stealer are:\r\n1. avamsicli.dll\r\n2. amsi.dll\r\n3. AmsiScanString\r\n4. AmsiScanBuffer\r\n5. EtwEventWrite\r\nAt this stage, I decided to stop my analysis\r\nFor everyone's convenience, I also uploaded all the files from my analysis including the shellcodes to VirusTotal.\r\nRhadamanthys files\r\nhttps://www.virustotal.com/gui/file/8384322d609d7f26c6dc243422ecec3d40b30f29421210e7fba448e375a134f6\r\nReferences\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 51 of 52\n\n[1] https://threatmon.io/rhadamanthys-stealer-analysis-threatmon/\r\n[2] https://mobile.twitter.com/JAMESWT_MHT/status/1610620178441568261\r\n[3] https://mobile.twitter.com/1ZRR4H/status/1610590795278712832\r\n[4] https://en.wikipedia.org/wiki/Address_space_layout_randomization\r\n[5] https://github.com/OALabs/BlobRunner\r\n[6] https://hex-rays.com/blog/igors-tip-of-the-week-49-navigation-band/\r\n[7] https://github.com/LordNoteworthy/al-khaser\r\n[8] https://elis531989.medium.com/the-chronicles-of-bumblebee-the-hook-the-bee-and-the-trickbot-connection-686379311056\r\n[9] https://learn.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-170\r\n[10] https://www.hexacorn.com/blog/2018/12/25/enter-sandbox-part-22-ctf-capturing-the-false-positive-artifacts/\r\n[11] https://tria.ge/221227-vprhbsae8t/behavioral2#report\r\n[12] https://github.com/HoLLy-HaCKeR/KeePassHax\r\n[13] https://twitter.com/1ZRR4H/status/1614728368334716932\r\n[14] https://www.joesandbox.com/analysis/783578/0/html#\r\n[15] https://blog.cyble.com/2023/01/12/rhadamanthys-new-stealer-spreading-through-google-ads/\r\nSource: https://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nhttps://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88\r\nPage 52 of 52\n\n https://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88  \nDefining as code and defining as function \nAfter doing that, we now have 8 functions in the function name bar.\n   Page 16 of 52",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://elis531989.medium.com/dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88"
	],
	"report_names": [
		"dancing-with-shellcodes-analyzing-rhadamanthys-stealer-3c4986966a88"
	],
	"threat_actors": [
		{
			"id": "08c8f238-1df5-4e75-b4d8-276ebead502d",
			"created_at": "2023-01-06T13:46:39.344081Z",
			"updated_at": "2026-04-10T02:00:03.294222Z",
			"deleted_at": null,
			"main_name": "Copy-Paste",
			"aliases": [],
			"source_name": "MISPGALAXY:Copy-Paste",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434592,
	"ts_updated_at": 1775791359,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/3bd693224c041be5b6d5d5c1bd6da107feaae741.pdf",
		"text": "https://archive.orkl.eu/3bd693224c041be5b6d5d5c1bd6da107feaae741.txt",
		"img": "https://archive.orkl.eu/3bd693224c041be5b6d5d5c1bd6da107feaae741.jpg"
	}
}