{
	"id": "e55326e5-3cef-476e-b7bc-c205900a0d75",
	"created_at": "2026-04-06T01:31:23.434778Z",
	"updated_at": "2026-04-10T03:20:22.981969Z",
	"deleted_at": null,
	"sha1_hash": "4691c6ddb28d362a6613f219a0f2fb73e89eb49d",
	"title": "Reversing Golang Developed Ransomware: SNAKE | 0ffset Training Solutions",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 3799613,
	"plain_text": "Reversing Golang Developed Ransomware: SNAKE | 0ffset\r\nTraining Solutions\r\nBy Gabriele Orini\r\nPublished: 2022-11-23 · Archived: 2026-04-06 00:37:07 UTC\r\nIntroduction\r\nSnake Ransomware (or EKANS Ransomware) is a Golang ransomware which in the past has affected several\r\ncompanies such as Enel and Honda.  The MD5 hashing of the analyzed sample\r\nis ED3C05BDE9F0EA0F1321355B03AC42D0. This sample in particular is obfuscated with Gobfuscate, an open\r\nsource obfuscation project available on Github.\r\nLet’s start by quickly summarizing the functionality of the malware:\r\nFirst, the sample checks the domain to which the infected host belongs to, before continuing execution\r\nNext, it checks whether the computer is a Backup Domain Controller or Primary Domain Controller, and if\r\nso will only drop the ransom note, rather than encrypting the machine\r\nSNAKE will then isolate the host machine from the network by leveraging the netsh tool\r\nThe shadow copies on the system are deleted using WMI\r\nSNAKE attempts to terminate any running AV, EDR, and SIEM components\r\nFinally, local files on the system are encrypted\r\nFor each file, a unique AES encryption key is generated, which is later encrypted with an RSA-2048\r\npublic key and stored within the encrypted file.\r\nLet’s start reversing this sample with IDA!\r\nStatic Analysis\r\nThere are some differences of Go from other languages to keep in mind:\r\nFunctions can return multiple values.\r\nFunction parameters are passed on the stack.\r\nStrings are typically a sequence of bytes with a fixed length, that are not null terminated; the string is\r\nrepresented by a structure formed by a pointer to a byte array, and the length of the string.\r\nThe constants are stored in one large buffer and sorted by length.\r\nMany stack manipulations are present within the binaries, that can make the analysis complex.\r\nObfuscation\r\nOpening the sample with IDA we immediately notice that the function names are very obfuscated:\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 1 of 21\n\nGobfuscate obfuscates almost all function names within the binary\r\nPerforming a quick search, I found that the malware is obfuscated with Gobfuscate. This project performs\r\nobfuscation of several components: Global names, Package names, Struct methods, and Strings.\r\nEach string in the binary is replaced by a function call. Each function contains two arrays that are xored to get the\r\noriginal string. When implementing the decryption function, keep in mind that there are different ways in which\r\nthese arrays are passed to the function runtime.stringtoslicebyte – either via a variable, a pointer or a hardcoded\r\nvalue).\r\nAnalyzing the sample, you will usually find the call to a main function that contains a large number of other calls\r\nwithin it, where each subroutine performs decryption of only one string. Sometimes only the decryption\r\noperations are found within these subroutines, other times additional operations are performed on the decrypted\r\nstring.\r\nString Decryption Functions\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 2 of 21\n\nString Decryption Functions\r\nAs mentioned, the string encryption is fairly basic, XORing the contents of two arrays together to retrieve the final\r\nstring.\r\nLoading the two arrays for decryption\r\nXORing the arrays together to get the decrypted string\r\nDue to the simplicity of the algorithm, we can develop a simple Python script utilising some regular expressions to\r\nlocate and decrypt 90% of the encrypted strings within the binary! The script can be found at the end of this post.\r\nstartDecryptFunction = b\"\\x64\\x8B\\x0D\\x14\\x00\\x00\\x00\"\r\nsliceStr = b\"(\" + b\"\\x8D.....\\x89.\\$\\x04\\xC7\\x44\\$\\b....\" + b\")\"\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 3 of 21\n\nxorLoop = b\"\\x0F\\xB6\u003c\\)1\\xFE(\\x83|\\x81)\\xFD\"\r\nWith the majority of the strings decrypted, let’s continue the analysis!\r\nCheck Environment\r\nOne of the first operations I perform when analyzing malware in GO is to jump to the main.init function.\r\nThe main.init is generated for each package by the compiler to initialise all other packages that this sample relies\r\non, as well as the global variables; analysing this function is very important because it allows us to understand a\r\nlarge amount of the malware’s functionality and speed up subsequent analysis.\r\nIn the main.init function we can find, for example, references to encryption: AES, RSA, SHA1, X509. In\r\naddition, there are several functions for decryption of strings and function names.\r\nInitialisations performed within main.init function\r\nAPI function decryption and loading through NewProc\r\nNow we move on to analyze the main.main function. One of the first activities the malware performs is to check\r\nthe environment before continuing with encryption.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 4 of 21\n\nCall to CheckEnvironment within main.main\r\nThe function CheckEnvironment starts by attempting to resolve the hostname mds.honda.com and compare the\r\nreturned value with 172[.]108[.]71[.]153. This check is used to confirm that the infected machine is part of the\r\ncorrect domain. In fact, it is important to remember that this ransomware is deployed at the end of the infection\r\nchain by other loaders, and thus it is likely custom-built for the victim.\r\nResolving hostname via DNS\r\nComparing resolved address to hardcoded address\r\nAfter the first environment check, the malware executes the API\r\ncalls CoInitializeEx, CoInitializeSecurity and CoCreateInstance to instantiate an object of\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 5 of 21\n\nthe SWbemLocator interface. Using the SWbemLocator object, SNAKE then invokes the\r\nmethod SWbemLocator::ConnectServer and obtains a pointer to an SWbemServices object. Finally, with this\r\nobject, it will execute ExecQuery with the following query:\r\nselect DomainRole from Win32_ComputerSystem\r\nIn an attempt to determine whether the infected computer is a server or a workstation.\r\nDecryption of object used to perform WMI query\r\nDecryption of WMI query to retrieve DomainRole\r\nAfter making the query, the malware only continues execution if the DomainRole value is equal to or less than 3.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 6 of 21\n\nExecution of WMI query and checking of result\r\nAccording to Microsoft documentation, the integers returned by the call correspond to different values:\r\nVALUE MEANING\r\n0 Standalone Workstation\r\n1 Member Workstation\r\n2 Standalone Server\r\n3 Member Server\r\n4 Backup Domain Controller\r\n5 Primary Domain Controller\r\nTherefore, the malware performs the infection only if the role obtained of the computer is Standalone\r\nWorkstation, Member Workstation, Standalone Server, or Member Server.\r\nIf this check is successful, the mutex Global\\EKANS is created, and presuming the mutex is created successfully,\r\nthe sample continues executing.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 7 of 21\n\nExecution flow depending on the result of the DomainRole\r\nIf, on the other hand, the computer role is either a backup domain controller or primary domain controller, a\r\nransom note is dropped to C:\\Users\\Public\\Desktop, and files are not encrypted. Within the ransom note is an\r\nemail on how to contact the threat actors, with the email used in this sample being CarrolBidell@tutanota.com.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 8 of 21\n\nRansom note\r\nWhen analyzing Go developed programs, two functions to pay attention to are NewLazyDll (essentially\r\nLoadLibrary), and NewProc (as you may have guessed, basically GetProcAddress). With the use of Gobfuscate to\r\nobfuscate this sample, the names of the libraries and API functions to be passed to the described functions.\r\nPointers to the loaded libraries/functions are stored within DWORDs for later reference.\r\nFor example, we can see in the sample we have the function that performs the decryption of a function name\r\nbefore calling LazyDLL.NewProc:\r\nAPI function decryption and loading via NewProc\r\nA pointer to the function is saved in a DWORD, so that we can trace to see where the function is called within the\r\nbinary.\r\nCross references for API functions\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 9 of 21\n\nExecution of previously loaded API function\r\nEndpoint Isolation\r\nAfter the function CheckEnvironment has finished, the strings “netsh advfirewall set allprofiles state on” and\r\n“netsh advfirewall set allprofiles firewallpolicy blockinbound,blockoutbound” are decrypted and executed\r\nvia cmd.run. The first command enables Windows Firewall for all network profiles, while the second blocks all\r\nincoming and outgoing connections. This is fairly unusual behaviour for ransomware, which typically performs\r\nlateral movement across a network to infect additional machines.\r\nDecryption of netsh commands to alter the firewall\r\nExecution of above commands through os.exec\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 10 of 21\n\nTerminate Process And Services\r\nPrior to encryption, the ransomware terminates a number of processes, to reduce the amount of interference with\r\nthe encryption (for example any open file handles), as well as disable any running EDR/SIEM software on the\r\nmachine.\r\nDecryption of target processes to be terminated\r\nProcesses are terminated using syscall.OpenProcess and syscall.TerminateProcess calls. In order for SNAKE to\r\nretrieve the PIDs of the target processes, the usual calls of CreateToolhelp32Snapshot, Process32FirstW, and\r\nProcess32NextW are performed.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 11 of 21\n\nTerminating processes with OpenProcess and TerminateProcess\r\nIn addition to terminating processes, the ransomware stops more than 200 services related to EDR, SIEM, AV, etc.\r\nDecryption of target service names to be terminated\r\nIn order to terminate services, the following API function calls are made:\r\nOpenSCManagerA: gets a service control manager handle for subsequent calls.\r\nEnumServicesStatusEx: enumeration of services.\r\nOpenServiceW: gets a service handle for subsequent calls.\r\nQueryServiceStatusEx: check the status of services.\r\nControlService: used to stop the service (flag SERVICE_CONTROL_STOP).\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 12 of 21\n\nTermination of services using OpenService and ControlService\r\nShadow Copy Deletion\r\nThe ransomware executes the WMI query “SELECT * FROM Win32_ShadowCopy” to get the IDs of Shadow\r\nCopies and will always use WMI for deletion (remember that there are many ways to perform shadow copy\r\ndeletion).\r\nIn addition to the Wbemscripting.SWbemLocator object, WbemScripting.SWbemNamedValueSet is also\r\ncreated.\r\nFor deletion, SNAKE uses the DeleteInstance method by passing the ID of previously obtained Shadow Copies.\r\nDecryption of WbemScripting.SWbemNamedValueSet\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 13 of 21\n\nDecryption of WMI Query\r\nDecryption of WMI namespace\r\nEncryption Process\r\nSNAKE first encrypts all the various files by initializing 8 go-routines (runtime.newproc), before beginning to\r\nrename the files.\r\nThe offset of the function that does the encryption is passed to runtime.newproc (OffsetStartEncryption).\r\nInitialisation of go-routines prior to file renaming function\r\nBefore beginning encryption of the file, it’s checked that it has not already been encrypted by checking for the\r\npresence of the string EKANS at the end of the file.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 14 of 21\n\nChecking if file is already encrypted\r\nIf the file hasn’t yet been encrypted and the files are among those to be encrypted (there is an allowlist and a\r\ndenylist), encryption is initiated, which takes care of:\r\nGenerating AES key for each file; this key is encrypted with an RSA public key in OAEP Mode.\r\nEncryption of file via AES in CTR mode, with Random Key (32 bytes) and Random IV (16 bytes).\r\nA random 5 character is appended to the file extension of encrypted files.\r\nAdds data to the end of the file: encrypted AES Key, IV and EKANS string.\r\nKey generation, encryption, and metadata being added to file\r\nAfter instantiating the CTR cipher with cipher.NewCTR, encryption is performed with\r\nthe XORKeyStream method of that class.\r\nThe function reads 0x19000 bytes at a time and after encryption the file is rewritten using WriteAt.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 15 of 21\n\nGenerating the buffer to hold bytes read from the file\r\nEncrypting buffer data and overwriting file\r\nAfter finishing the encryption, three more writes are performed on the file:\r\nAdding metadata to the file\r\nIt’s easy to see that in the last one the string EKANS is written (which is used to determine if the file has already\r\nbeen encrypted), while it is much more complex to figure out what is written in the first two. As a result, let’s\r\njump over to a debugger.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 16 of 21\n\nObserving metadata being written to end of file using a debugger\r\nThe first write adds the following to the file:\r\nThe encrypted AES Key\r\nThe random IV\r\nThe path of encrypted file\r\nThe AES Key for each file is encrypted with a public RSA key. After decryption, the public key is parsed\r\nwith pem.decode and x509.ParsePKCS1PublicKey.\r\nDecryption of RSA public key\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 17 of 21\n\nParsing of the RSA key\r\nThe first parameter of the EncryptOAEP function must be the hash function, which in this case is sha1:\r\nEncryptOAEP Function\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 18 of 21\n\nCall to EncryptOAEP function\r\nVarious extensions, file and folders are excluded for file encryption, also using a regex.\r\nPartially excluded Files:\r\nIconcache.db Ntuser.dat Desktop.ini\r\nNtuser.ini Usrclass.dat Usrclass.dat.log1\r\nUsrclass.dat.log2 Bootmgr Bootnxt\r\nNtuser.dat.log1 Ntuser.dat.log2 Boot.ini\r\nctfmon.exe bootsect.bak ntdlr\r\nPartially excluded extensions:\r\nExe Dll Sys\r\nMui Tmp Lnk\r\nconfig settingcontent-ms Tlb\r\nOlb Bfl ico\r\nregtrans-ms devicemetadata-ms Bat\r\nCmd Ps1  \r\nExcluded Paths:\r\n\\ProgramData\r\n\\Users\\All Users\r\n\\Temp\\\r\n\\AppData\\\r\n\\Boot\r\n\\Local Settings\r\n\\Recovery\r\n\\Program Files\r\n\\System Volume Information\r\n\\$Recycle.Bin\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 19 of 21\n\n.+\\\\Microsoft\\\\(User Account Pictures|Windows\\\\(Explorer|Caches)|Device\r\nAnd that just about wraps up this post on the SNAKE Ransomware!\r\nDecryption Script\r\n#!/usr/bin/env python3\r\nimport re, struct, pefile, sys\r\npe = None\r\nimageBase = None\r\ndef GetRVA(va):\r\n return pe.get_offset_from_rva(va - imageBase)\r\ndef GetVA(raw):\r\n return imageBase + pe.get_rva_from_offset(raw)\r\ndef main():\r\n global pe, imageBase\r\n \r\n filename = sys.argv[1]\r\n \r\n with open(filename, 'rb') as sample:\r\n data = bytearray(sample.read())\r\n \r\n pe = pefile.PE(filename)\r\n imageBase = pe.OPTIONAL_HEADER.ImageBase\r\n \r\n startDecryptFunction = b\"\\x64\\x8B\\x0D\\x14\\x00\\x00\\x00\"\r\n sliceStr = b\"(\" + b\"\\x8D.....\\x89.\\$\\x04\\xC7\\x44\\$\\b....\" + b\")\"\r\n xorLoop = b\"\\x0F\\xB6\u003c\\)1\\xFE(\\x83|\\x81)\\xFD\"\r\n \r\n regex = startDecryptFunction + b\".{10,100}\" + sliceStr + b\".{10,100}\" + sliceStr + b\".{10,100}\" + xorLoop\r\n pattern = re.compile(regex, re.MULTILINE|re.DOTALL)\r\n found = pattern.finditer(bytes(data))\r\n for m in found:\r\n \r\n va = GetVA(m.start())\r\n funcVA = GetVA(m.start())\r\n str1VA = struct.unpack(\"\u003cL\", data[m.start(1) + 2 : m.start(1) + 2 + 4])[0]\r\n str1Len = struct.unpack(\"\u003cL\", data[m.start(1) + 0xE : m.start(1) + 0xE + 4])[0]\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 20 of 21\n\nstr2VA = struct.unpack(\"\u003cL\", data[m.start(2) + 2 : m.start(2) + 2 + 4])[0]\r\n str1RVA = GetRVA(str1VA)\r\n str2RVA = GetRVA(str2VA)\r\n \r\n decrypted = \"\"\r\n for i in range(str1Len):\r\n decrypted += chr ( ( data[str2RVA+i] ^ (data[str1RVA+i] + i * 2)) \u0026 0xFF)\r\n \r\n print(f\"## (hex(funcVA)) - {decrypted}\")\r\nif __name__ == \"__main__\":\r\nmain()\r\nSource: https://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nhttps://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/\r\nPage 21 of 21",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.0ffset.net/reverse-engineering/analysing-snake-ransomware/"
	],
	"report_names": [
		"analysing-snake-ransomware"
	],
	"threat_actors": [],
	"ts_created_at": 1775439083,
	"ts_updated_at": 1775791222,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/4691c6ddb28d362a6613f219a0f2fb73e89eb49d.pdf",
		"text": "https://archive.orkl.eu/4691c6ddb28d362a6613f219a0f2fb73e89eb49d.txt",
		"img": "https://archive.orkl.eu/4691c6ddb28d362a6613f219a0f2fb73e89eb49d.jpg"
	}
}