- The first variant of “Nokoyawa” ransomware is suspected to be related to the “Hive” ransomware family, but is currently identified as an autonomous threat actor.
- The Nokoyawa ransomware version examined in this report (1.1) is written in C++ and requires a configuration file to be executed.
- Nokoyawa contains misleading techniques to avoid analysis.
- This version of Nokoyawa has a bilingual ransom note.
Since its first appearance, four versions of Nokoyawa have been developed. Version 1.0 and 1.1 (which are written in C/C++), and 2.0 and 2.1 (AKA “Nevada”), which are written in Rust. Versions 1.1 and 2.0 require a configuration file passed as a CLI argument to execute. The ransomware strains of versions 1.1 and 2.1 were first found at the beginning of 2023, however, all four versions of Nokoyawa are used interchangeably, up to this day.
As Nokoyawa has evolved, it’s become a more dangerous threat, and it appears that the gang has now claimed some victims. According to Nokoyawa’s leak site, the gang is already known to have compromised organizations including Tampa General Hospital, a non-profit hospital located in Florida.
Up until now, Nokoyawa’s only known method of distribution of the ransomware is via Cobalt Strike. However, it is unclear if this is still in use in recent attacks, as there is no data regarding it.
The Nokoyawa gang claims to encrypt and extract its victims’ sensitive information, as can be seen on their leak site.
The analyzed sample is a 32-bit architecture Portable Executable (PE), that was compiled with Borland Delphi 3.0 compiler.
Further examination of the malware reveals that Nokoyawa uses CLI as a subsystem, which implies that this is a sample of Nokoyawa version 1.1 or 2.0.
Given the findings that this malware sample was both compiled in Delphi 3.0 and has CLI, we can determine that we are looking at Nokoyawa version 1.1.
Examining the first code block in the debugger, we can see that the malware calls a function before performing any other actions. This function call appears suspicious — it’s unexpected for malware to perform any major functional operation regarding payload execution, because no execution-related DLL has been loaded that might support it.
By analyzing the function that is being called, as seen in the image below, we see that it contains hardcoded strings that are passed to two main decryption functions. The decrypted strings turn into command line arguments and configuration file parameters. Those functions are referred to as “Secret Decryption Initialization.”
The first hardcoded string is passed to the function as an expected argument, and another two strings are stored in registers: edx and ecx.
- First string – First part of the decryption key
- Second string – Second part of the decryption key
- Third string – “Secret”
- Initialized secret decryption
Upon examination of the decryption functions, it becomes apparent that the code is nearly identical, with the exception of the switch between operations when the ebx and esi registers are used.
The malware first uses a function to determine whether "Crypt32.dll" was successfully loaded before attempting to obtain a handle to one of the functions contained within Crypt32.dll. Those functions are not yet mapped into the memory and are only loaded when called during runtime; thus, they are represented in the code by their offset inside Crypt32.dll.
Nokoyawa attempts to get its process heap stub to allocate memory to write into by using the "GetProcessHeap" and "RtlAllocateHeap" functions.
The ransomware utilizes the "CryptStringToBinary" function, which is located in the Crypt32.dll library. This function converts a string into a binary array and writes it to the memory.
The string that is being written as a binary array is the “secret” that was prepared before the calling of the “initialize secret decryption” function.
The function that is being called is meant to write the passed strings into the memory. The function is called twice, once for every part of the decryption key.
After Nokoyawa writes the first and second strings into the memory, it calls a function referred to as “Decrypt Secret,” which prepares the strings for the decryption of the third passed string (the “secret”).
In the “Decrypt Secret” function, there is a loop consisting of three blocks of code. The second block of code, which is called the “Prepare Final Key” function, is executed only once to get the final decryption key for the “secret.”
The first and third blocks of code execute as part of the final secret decryption step. The first block of code is used as a counter to the length of the secret’s string. The third block of code is used to run an XOR operation on every four bytes of the secret’s binary array and the respectively located four bytes of the final decryption key.
The part below is linked to the Salsa20 stream cipher, and is the method of producing the cipher's key schedule. The malware is deceptively pushing the string “expand 32-byte k” into the memory, giving the impression that the key generation is made by the Salsa20 algorithm. The true nature of the static string differs — the string is never read from memory, but is instead used as a string that is the third and last part of the full decryption key.
The following code block stores the pushed characters to construct the full expression “expand 32-byte k.” Since the characters that are stored in the stack are four bytes each, the characters are pushed four at a time in one code block execution.
Every four characters are stored in the stack 16 bytes away from each other. When put together, the following expression is constructed.
Due to moving 16 bytes in one code block execution, and since the whole expression is 16 characters long, the code block executes four times in total.
Next, Nokoyama writes the second and first string between the memory spaces of “expand 32-byte k.”
This is done by entering the first 16 bytes of the second part of the decryption key in the first space. Then, the first part of the decryption key — followed by zeroes (0x0) to match the 16-byte length — is entered. The third space is filled by the rest of the bytes of the second part of the decryption key.
This creates a 64-byte string in the memory, which is the full decryption key.
According to the analysis, Nokoyama creates a 64-byte key, which it attempts to copy to two other memory locations. Specifically, the malware copies the key to the previous 64 bytes (0x40) and 128 bytes (0x80) in memory relative to the address of the full decryption key.
The following code blocks set a counter for how many times the full decryption key is encrypted by the Salsa20 cipher. Two functions that are being called in the second code block are implementation of the Salsa20 algorithm.
The Salsa20 algorithm involves adding the values of registers ecx and ecx+0x30.
The values that are stored in ecx and ecx+0x30 are “expa” (ecx) and the second 4 bytes of the second part of the second decryption key (ecx+0x30). Here’s a look at the values before and after the Salsa20 code block is executed:
Since the third part of the decryption key is being used with a different, second part of the key each time, the first four bytes of the second copy of the full key in the memory are always “expa.” The expected value of the encrypted decryption key in the memory has a different hex value.
Before and after performing the Salsa20 code block:
The “Prepare Final Key” function goes over every four bytes of the encrypted copy of the full decryption key, and adds to its hex value the value of the respective four bytes of the unencrypted copy of the full key.
The hex value that results from this operation is stored in the respective four bytes in the original full decryption key address. This results in a final decryption key that is used to decrypt the “secret.”
The figure below shows the before and after of the decryption.
The code block below shows the order of the command line arguments that are passed for the malware to run.
The command line arguments:
- --config – The configuration file the malware uses.
- --dir – Encrypt selected directory and sub-directories.
- --file – Encrypt only selected file.
Nokoyawa’s configuration file is built modularly, allowing the attacker to modify every aspect of the ransomware’s execution.
During the encryption stage, Nokoyawa encrypts all files in every directory of the infected host, except the directories that are excluded specifically in the configuration file.
In each directory, the ransomware encrypts all files except those with file extensions that are excluded in the configuration file.
File encryption is performed by encrypting the current file and having a handle for the next file in the listdir list.
In each encrypted directory, Nokoyawa leaves the ransom note NOKOYAWA_readme.txt.
After each file is encrypted, it adds an extension provided by the configuration file. In this case, the extension is “.NOKOYAWA”.
The ransom note’s contents may vary depending on the configuration file, but the note used in one of the examined samples contains the following:
Detected by Acronis
Acronis Cyber Protect successfully detects and prevents execution of Nokoyawa ransomware.
Nokoyawa ransomware has evolved greatly since its first appearance at the beginning of 2022. It currently has four different known versions. In some of these, the malware expects a configuration file, making the sample more protected.
Victims who fail to comply with the attackers’ ransom demands risk having their files leaked on Nokoyawa's data leak site on the dark web.
About the authors
Yuval Shoef is an MDR analyst at Acronis, taking part in various malware research projects as well as day-to-day work on Acronis Detection and Reponse and Acronis Cyber Protect
Ilia Kulmin is an MDR analyst at Acronis, focusing primarily on researching emerging threats and sophisticated malware, as well as daily work with Acronis Detection and Response and Acronis Cyber Protect.