{
	"id": "db0c7f68-b500-416d-a941-8ee65a9497cc",
	"created_at": "2026-04-06T00:21:53.345135Z",
	"updated_at": "2026-04-10T03:30:32.954832Z",
	"deleted_at": null,
	"sha1_hash": "bb2d8571dfc335cf251ad729b01023f5a5ce7089",
	"title": "PLAY Ransomware",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1775958,
	"plain_text": "PLAY Ransomware\r\nBy Chuong Dong\r\nPublished: 2022-09-03 · Archived: 2026-04-05 14:58:09 UTC\r\nReverse Engineering  · 03 Sep 2022\r\nContents\r\nPLAY Ransomware\r\nContents\r\nPLAY CTI\r\nOverview\r\nIOCS\r\nRansom Note\r\nAnti Analysis\r\nAnti-Analysis: Return-Oriented Programming\r\nAnti-Analysis: Garbage Code\r\nAnti-Analysis: API Hashing\r\nAnti-Analysis: String Encryption\r\nStatic Code Analysis\r\nCommand-Line Arguments\r\nCrypto Initialization\r\nCheck Existing Drives\r\nRecursive Traversal\r\nPopulating File Structure\r\nChild Thread Encryption\r\nFile Encryption\r\nReferences\r\nPLAY CTI\r\nPLAY Ransomware (aka PlayCrypt) campaigns have been active since at least mid-July 2022. Up to five ransom\r\nnotes of PLAY Ransomware have been uploaded to VirusTotal so far. In mid-August 2022, the first public case of\r\nPLAY Ransomware was announced when a journalist uncovered that Argentina’s Judiciary of Córdoba was\r\nvictimized.\r\nThe operators have been known to use common big game hunting (BGH) tactics, such as SystemBC RAT for\r\npersistence and Cobalt Strike for post-compromise tactics. They have also been known to use custom PowerShell\r\nscripts and AdFind for enumeration, WinPEAS for privilege escalation, and RDP or SMB for lateral movement\r\nwhile inside a target network.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 1 of 38\n\nThe group appends “.play” to encrypted files and its ransom note only includes the word “PLAY” and an email\r\naddress to communicate with the threat actors. The threat actors have been known to exfiltrate files using WinSCP\r\nbut are not known to have a Tor data leak site like many other BGH ransomware campaigns.\r\nHuge thanks to my man Will Thomas for this information!\r\nOverview\r\nThis is my analysis for PLAY Ransomware. I’ll be solely focusing on its anti-analysis and encryption features.\r\nThere are a few other features such as DLL injection and networking that will not be covered in this analysis.\r\nDespite its simplicity, PLAY is heavily obfuscated with a lot of unique tricks that have not been used by any\r\nransomware that comes before.\r\nThe malware uses the generic RSA-AES hybrid-cryptosystem to encrypt files. PLAY’s execution speed is pretty\r\naverage since it uses a depth-first traversal algorithm to iterate through the file system. Despite launching a\r\nseparate thread to encrypt each file, this recursive traversal hinders its performance significantly.\r\nIOCS\r\nThe analyzed sample is a 32-bit Windows executable.\r\nMD5: 223eff1610b432a1f1aa06c60bd7b9a6\r\nSHA256: 006ae41910887f0811a3ba2868ef9576bbd265216554850112319af878f06e55\r\nSample: MalwareBazaar\r\nFigure 2: VirusTotal Result.\r\nRansom Note\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 2 of 38\n\nThe content of the default ransom note is stored as an encoded string in PLAY’s executable, which contains the\r\nstring “PLAY” as well as an email address for the victim to contact the threat actor.\r\nPLAY’s ransom note filename is “ReadMe.txt”.\r\nFigure 3: PLAY’s Ransom Note.\r\nAnti Analysis\r\nAnti-Analysis: Return-Oriented Programming\r\nUpon opening the executable in IDA, we can see that most of the assembly code does not make sense and is not\r\ntoo meaningful. An example can be seen from WinMain, where there is no clear return statement with garbage\r\nbytes popping up among valid code.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 3 of 38\n\nFigure 3: Anti-decompiling Feature in WinMain.\r\nAs shown in the disassembled code above, the control flow in WinMain calls sub_4142F5, and upon return, edi\r\nis popped and we run into the garbage bytes at 0x4142F2. As a result, IDA fails to decompile this code properly.\r\nFigure 4: Unpatched WinMain Decompiled Code.\r\nExamine sub_4142F5, we see that the value stored at the stack pointer is immediately added by 0x35 before a\r\nretn instruction is executed.\r\nWe know that the call instruction basically contains two atomic instructions, one pushing the address of the next\r\ninstruction (after the call instruction) onto the stack and one jumping to the subroutine being called. When the\r\ncode enter sub_4142F5, the return address (in this case, it is 0x4142F1) is stored at the stack pointer on top of the\r\nstack. The subroutine adds 0x35 to this, changing the return address to 0x414326, and retn to jump to it.\r\nKnowing this, we can scroll down and try to disassembly the bytes at 0x414326 to get the next part of the\r\nWinMain code.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 4 of 38\n\nFigure 5: Disassembled Hidden Code.\r\nUsing this return-oriented programming approach to divert the regular control flow of the program, PLAY is able\r\nto bypass most static analysis through IDA’s disassembly and decompilation.\r\nWe can also quickly see that at 0x41433A, there is another call instruction followed by some garbage bytes. This\r\nmeans that the obfuscation occurs multiple times in the code.\r\nMy approached to this was to programmatically patch all these call instructions up. A simple patch used in my\r\nanalysis is calculating the jump (the value added to the return address) and replacing the call instruction with a\r\njump instruction to the target address.\r\nTo scan for all of this obfuscated code, I use 3 different (but quite similar) regexes(is this a word?) in IDAPython\r\nto find and patch them. You can find my patching script here.\r\nAfter patching, the WinMain code looks something like this.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 5 of 38\n\nFigure 6: Patched WinMain.\r\nA little underwhelming, but now we have successfully deobfuscated the code, get a meaningful call instruction to\r\nsub_415110 and a proper returning statement in the decompiled code!\r\nAnti-Analysis: Garbage Code\r\nBeside control flow obfuscation, PLAY also litters its code with random moving instructions that don’t contribute\r\nto the main functionality of the program.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 6 of 38\n\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 7 of 38\n\nFigure 7, 8: Garbage Code.\r\nThis makes the decompiled code looks a lot messier, and it is not simple to patch all of these ups since valid code\r\nis usually stuffed in between of these garbage code. Patching by jumping over them would sometime break the\r\nprogram itself.\r\nThe only solution I have for this is to mentally ignore them while analyzing.\r\nAnti-Analysis: API Hashing\r\nSimilar to most modern ransomware, PLAY obfuscates its API call through API name hashing. The API resolving\r\nfunction takes in a target hash and a DLL address.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 8 of 38\n\nIt walks the DLL’s export table to get the name of the exports. For each API name, the malware calls sub_40F580\r\nwith the name as the parameter and adds 0x4E986790 to the result to form the final hash. This hash is compared\r\nwith the target hash, and if they match, the address of the API is returned.\r\nFigure 9: API Hashing.\r\nAs shown below, the hashing function contains a lot of unique constants, which allows us to quickly look up that it\r\nis xxHash32. With this, we know that the full hashing algorithm is xxHash32 with the seed of 1 and the result\r\nadded to 0x4E986790.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 9 of 38\n\nFigure 10: xxHash32 Code.\r\nFrom here, I developed an IDAPython script to automatically resolve all APIs that the malware uses, which you\r\ncan find here.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 10 of 38\n\nFigure 11: Resolving APIs.\r\nAnti-Analysis: String Encryption\r\nMost important strings in PLAY are encoded in memory. The decoding algorithm does not seem to be too clear, so\r\nI just dynamic-ed my way through these. School is whooping my ass right now, so I try to avoid analyzing stuff\r\nwhenever I can.\r\nFigure 12: PLAY’s String Decryption.\r\nStatic Code Analysis\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 11 of 38\n\nCommand-Line Arguments\r\nPLAY can run with or without command-line arguments.\r\nBelow is the list of arguments that can be supplied by the operator.\r\nArgument Description\r\n-mc\r\nExecute normal functionality. Same as no command-line\r\nargument.\r\n-d \u003cdrive path\u003e Encrypt a specific drive\r\n-ip \u003cshared resource path\u003e \u003cusername\u003e\r\n\u003cpassword\u003e\r\nEncrypt network shared resource\r\n-d \u003cpath\u003e Encrypt a specific folder/file\r\nFigure 13: Checking Command-Line Arguments.\r\nCrypto Initialization\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 12 of 38\n\nPrior to encryption, PLAY initializes and retrieves cryptographic algorithm providers.\r\nFirst, it calls BCryptOpenAlgorithmProvider to load and initialize a CNG provider for random number\r\ngeneration and BCryptImportKeyPair to import its hard-coded RSA public key.\r\nFigure 14: Initializing \u0026 Importing Cryptographic Key.\r\nNext, the malware calls VirtualAlloc to allocate a buffer to store 128 file structures used for encrypting files. The\r\nstructure’s size is 0x48 bytes with its content listed below.\r\n struct play_file_struct\r\n {\r\n int struct_index;\r\n char *filename;\r\n int initialized_flag;\r\n int padding1;\r\n char *file_path;\r\n int file_marker[2];\r\n int chunk_count;\r\n int chaining_mode_flag;\r\n DWORD large_file_flag;\r\n HANDLE AES_provider_handle;\r\n HANDLE bcrypt_RNG_provider;\r\n HANDLE RSA_pub_key_handle;\r\n HANDLE file_handle;\r\n LARGE_INTEGER file_size;\r\n DWORD file_data_buffer;\r\n DWORD padding2;\r\n };\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 13 of 38\n\nField Description\r\nstruct_index Index of the structure in the global structure list\r\nfilename The name of the file being processed\r\ninitialized_flag Set to 1 when the structure is populated with a file to encrypt\r\nfile_path Path of the file being processed\r\nfile_marker Address of constants to write to file footer marking that it’s been encrypted\r\nchunk_count Number of chunks to encrypt in the file\r\nchaining_mode_flag Set to 1 to use chaining mode GCM, 0 to use chaining mode CBC\r\nlarge_file_flag Set to 1 when the processed file is large\r\nAES_provider_handle AES algorithm provider handle\r\nbcrypt_RNG_provider RNG algorithm provider handle\r\nRSA_pub_key_handle RSA public key handle\r\nfile_handle File handle\r\nfile_size File size\r\nfile_data_buffer Address to virtual buffer to read file data in\r\nPLAY iterates through this global structure list and populates each structure’s field. First, it sets the encrypted file\r\nmarkers in the struct to the following hard-coded values, which will later be written to the end of each encrypted\r\nfile.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 14 of 38\n\nFigure 15: Encrypted File Markers.\r\nThen, the malware sets the RNG and AES provider handles as well as the RSA public key handle to the structure.\r\nThese will later be used to generate random AES key and IV to encrypt files.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 15 of 38\n\nFigure 16: Encrypted File Markers.\r\nCheck Existing Drives\r\nBefore iterating through all drives to encrypt, PLAY enumerates all volumes on the victim’s system by calling\r\nFindFirstVolumeW and FindNextVolumeW. If the volume is not a CD-ROM drive or a RAM disk, the malware\r\ncalls GetVolumePathNamesForVolumeNameW to retrieve a list of drive letters and mounted folder paths for\r\nthe specified volume.\r\nIf this list is empty, which means the volume is not mounted to any folder, PLAY calls GetDiskFreeSpaceExW\r\nto check if the volume’s free space is greater than 0x40000000 bytes. If it is, the malware calls\r\nSetVolumeMountPointW to try mounting the volume to a drive path.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 16 of 38\n\nFigure 17: Enumerating Volumes.\r\nFor each volume to be mounted, PLAY iterates through all characters to find a drive name that it can call\r\nSetVolumeMountPointW to mount the volume to.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 17 of 38\n\nFigure 18: Setting Mount Point for Volume.\r\nUsing the same trick to iterates through all possible drive names, PLAY calls GetDriveTypeW to check the type\r\nof each drive.\r\nIt avoids encrypting CD-ROM drive or RAM disk. If it’s a remote drive, the malware calls\r\nWNetGetUniversalNameW to retrieve the universal name of the network drive.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 18 of 38\n\nFigure 19: Processing Network Drive.\r\nThe final drive path to be encrypted is set to the network drive’s universal name or connection name, depending\r\non which exists.\r\nFigure 20: Retrieving Network Drive Name.\r\nIf the drive is a regular drive, its name remains the same. Each valid drive has its name added to the list of drive\r\nnames to be traversed and encrypted.\r\nRecursive Traversal\r\nTo begin traversing drives, PLAY iterates through the list of drive names above and spawns a thread with\r\nCreateThread to traverse each drive on the system.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 19 of 38\n\nFigure 21: Spawning Threads to Traverse Drives.\r\nBefore processing a drive, the malware extracts the following ransom note content before dropping it into the\r\ndrive folder. This is the only place where the ransom note is dropped instead of in every folder like other\r\nransomware.\r\nPLAY\r\nteilightomemaucd@gmx.com\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 20 of 38\n\nFigure 22, 23: Dropping Ransom Note in Drive.\r\nTo begin enumerating, the malware calls FindFirstFileW and FindNextFileW to enumerate subfolders and files.\r\nIt specifically checks to avoid processing the current and parent directory paths ”.” and ”..”.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 21 of 38\n\nFigure 24: Enumerating Files.\r\nIf the file encountered is a directory, the malware checks to avoid encrypting the “Windows” directory. After that,\r\nit concatenates the subdirectory’s name to the current file find path and recursively traverse through the\r\nsubdirectory by calling the traversal function on it.\r\nFigure 25: Recursively Traverse Subdirectory.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 22 of 38\n\nIf the file encountered is a regular file, the malware checks its name as well as its size to see if it’s valid for being\r\nencrypted.\r\nFigure 26: Checking Files.\r\nIf its name/extension is in the list below or if its size is less than 6, PLAY avoids encrypting it.\r\n.exe, .dll, .lnk, .sys, readme.txt, bootmgr, .msi, .PLAY, ReadMe.txt\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 23 of 38\n\nFigure 27: Checking Filename \u0026 Extension.\r\nPLAY also performs an additional check to see if the file extension is that of typical large files to determine its\r\nencryption type later. The file is classified as large if its extension is in the list below.\r\nPopulating File Structure\r\nFor each file to be encrypted, PLAY first populates the file structure with the appropriate data about the file.\r\nFirst, it starts iterating through the global file structure list to check if there is an available structure to process the\r\nfile.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 24 of 38\n\nFigure 28: Checking for Available File Structure.\r\nIf there is no available structure in the global list, PLAY calls Sleep to have the thread sleep and rechecks until it\r\nfinds one.\r\nOnce the structure is found, the malware sets its initialized_flag field to 1 and the filename field to the target\r\nfilename. It also populates other fields such as the file size, large file flag, and file handle.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 25 of 38\n\nFigure 29, 30: Populating A File Structure To Encrypt File.\r\nChild Thread Encryption\r\nAfter populating a file structure for a specific file, PLAY spawns a thread to begin encrypting a file.\r\nIf the file is not classified as a large file, the malware calculates how many chunks it needs to encrypt depending\r\non the file size. The number of encrypted chunks is 2 if the file size is less than or equal to 0x3fffffff bytes, 3 if the\r\nfile size is less than or equal to 0x27fffffff bytes and greater than 0x3fffffff bytes, and 0 if the file size is equal to\r\n0x280000000. If the file size is greater than 0x280000000 bytes, then the number of encrypted chunks is 5.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 26 of 38\n\nFigure 32: Calculating Encrypted Chunks.\r\nThe default chaining mode is set to AES-GCM. However, if the file size is greater than 4025 times the encrypted\r\nsize (which is the chunk size 0x100000 multiplied by the chunk count), the chaining mode is set to AES-CBC.\r\nThis is because AES-GCM has worst performance compared to AES-CBC. According to this post, AES-GCM is a\r\nmore secure cipher than AES-CBC, because AES-CBC, operates by XOR’ing (eXclusive OR) each block with the\r\nprevious block and cannot be written in parallel. This affects performance due to the complex mathematics\r\ninvolved requiring serial encryption.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 27 of 38\n\nFor file encryption, PLAY now introduces a new structure that represents the file footer content that gets written\r\nat each encrypted file.\r\nIt took me an eternity to fully understand and resolve this structure’s fields, which reminds me I’m probably just\r\nwashed up at malware analysis now rip.\r\nstruct file_footer_struct\r\n{\r\n byte footer_marker_head[16];\r\n WORD last_chunk_size;\r\n WORD skip_chunks;\r\n WORD large_file_flag;\r\n WORD small_file_flag;\r\n DWORD default_chunk_size;\r\n DWORD footer_marker_tail;\r\n QWORD encrypted_chunk_count;\r\n byte encrypted_symmetric_key[1024];\r\n};\r\nField Description\r\nfooter_marker_head First index in the file_marker of file struct\r\nlast_chunk_size Size of the last chunk at the end of the file\r\nskip_chunks Number of chunks to skip each time\r\nlarge_file_flag Set to 1 if file is larger than 0x500000\r\nsmall_file_flag\r\nSet to 1 when file size high is less than 0, used to determine GMC encryption\r\nmode\r\nchunk_count Number of chunks to encrypt in the file\r\ndefault_chunk_size 0x100000 bytes\r\nfooter_marker_tail\r\nxxHash32 hash of footer_marker_head. Also the second index in the\r\nfile_marker of file struct\r\nencrypted_chunk_count Total number of chunks successfully encrypted\r\nencrypted_symmetric_key encrypted AES key BLOB\r\nFirst, PLAY reads 0x428 bytes at the end of the file to check the file footer. If the file size is smaller than 0x428\r\nbytes, the file is guaranteed to not be encrypted, so the malware moves to encrypt it immediately.\r\nIf the last 0x428 bytes is read successfully, the malware then checks if the xxHash32 hash of the footer marker\r\nhead is equal to the footer marker tail. If they are, then the file footer is confirmed to be valid, and the file is\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 28 of 38\n\nalready encrypted.\r\nIf this is not the case, PLAY checks each DWORD in the footer marker head and compare it to the hard-coded\r\nvalues in the file structure. This is to check if the file footer is not encrypted, if the file footer is written but it has\r\nnot been encrypted, or if the file is already encrypted.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 29 of 38\n\nFigure 33, 34: Checking File Footer for Encryption State.\r\nFile Encryption\r\nTo encrypt a file from scratch, PLAY first generates an AES key to encrypt the file with.\r\nIt calls BCryptGenRandom to generate a random 0x20-byte buffer. Depending on the chaining mode specified in\r\nthe file structure, the malware calls BCryptSetProperty to set the chaining properly for its AES provider handle.\r\nNext, BCryptGenerateSymmetricKey is called on the randomly generated 0x20-byte buffer to generate the AES\r\nkey handle.\r\nFigure 35, 36, 37: Generating AES Key Handle.\r\nNext, to store the AES key in the file footer struct, PLAY calls BCryptExportKey to export the AES key into a\r\n0x230-byte key blob. It also calls BCryptGenRandom to randomly generate a 0x10-byte IV and appends it after\r\nthe key blob.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 30 of 38\n\nFigure 38, 39: Exporting AES Key Blob \u0026 IV.\r\nThen, it calls BCryptEncrypt to encrypt the exported key blob and the IV using the RSA public key handle and\r\nwrites the encrypted output to into a 0x400-byte buffer. This buffer is then copied to the\r\nencrypted_symmetric_key field of the file footer structure.\r\nFigure 40: Encrypting AES Key Blob with RSA Public Key.\r\nPLAY then populates the file footer’s other fields such as footer_marker_head, footer_marker_tail,\r\nsmall_file_flag, and large_file_flag with existing information from the file structure. The default chunk size is\r\nalso set to 0x100000 bytes.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 31 of 38\n\nFigure 41: Populating File Footer Structure.\r\nOnce the file footer is fully populated, the malware calls SetFilePointerEx to move the file pointer to the end of\r\nthe file and calls WriteFile to write the structure there.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 32 of 38\n\nFigure 42: Writing File Footer Structure To End Of File.\r\nIf the file size is greater than 0x500000 bytes, PLAY only encrypts the first and last chunk in the file.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 33 of 38\n\nFigure 43, 44: Encrypting Large File’s First \u0026 Last Chunk.\r\nThe encrypting function consists of a ReadFile call to read the chunk data in the buffer in the file structure, a\r\nBCryptEncrypt call to encrypt the file using the AES key handle and the generated IV. After encryption is\r\nfinished, the malware calls WriteFile to write the encrypted output to the file as well as the index of the chunk\r\nbeing encrypted in the file footer. This is potentially used to keep track of how many chunks have been encrypted\r\nin the case where corruption or interruption occurs.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 34 of 38\n\nFigure 45, 46, 47: Data Encrypting Function.\r\nIf the file size is smaller than the default chunk size of 0x100000 bytes, the malware encrypts the entire file.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 35 of 38\n\nFigure 48: Encrypting Small File Whole.\r\nIf the file size is somewhere in between 0x100000 and 0x500000, the malware encrypts it in 0x100000-byte\r\nchunks until it reaches the end of the file.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 36 of 38\n\nFigure 49: Encrypting Mid-Size File.\r\nFinally, after the file is encrypted, the malware changes its extension to .PLAY by calling MoveFileW.\r\nFigure 50: Appending Encrypted Extension.\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 37 of 38\n\nThere is a small bug in the code that it always changes the extension of a file despite if encryption is successful or\r\nnot due to the return value of the file encrypting function.\r\nFigure 51: Encrypting Mid Size File.\r\nReferences\r\nhttps://www.bleepingcomputer.com/news/security/argentinas-judiciary-of-c-rdoba-hit-by-play-ransomware-attack/\r\nhttps://helpdesk.privateinternetaccess.com/kb/articles/what-s-the-difference-between-aes-cbc-and-aes-gcm#:~:text=AES%2DGCM%20is%20a%20more,mathematics%20involved%20requiring%20serial%20encryption.\r\nSource: https://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nhttps://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/\r\nPage 38 of 38\n\nAfter populating If the file is not a file structure classified for a specific as a large file, file, PLAY the malware calculates spawns a thread how many to begin encrypting chunks it needs a file. to encrypt depending \non the file size. The number of encrypted chunks is 2 if the file size is less than or equal to 0x3fffffff bytes, 3 if the\nfile size is less than or equal to 0x27fffffff bytes and greater than 0x3fffffff bytes, and 0 if the file size is equal to\n0x280000000. If the file size is greater than 0x280000000 bytes, then the number of encrypted chunks is 5.\n   Page 26 of 38",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://chuongdong.com/reverse%20engineering/2022/09/03/PLAYRansomware/"
	],
	"report_names": [
		"PLAYRansomware"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "75108fc1-7f6a-450e-b024-10284f3f62bb",
			"created_at": "2024-11-01T02:00:52.756877Z",
			"updated_at": "2026-04-10T02:00:05.273746Z",
			"deleted_at": null,
			"main_name": "Play",
			"aliases": null,
			"source_name": "MITRE:Play",
			"tools": [
				"Nltest",
				"AdFind",
				"PsExec",
				"Wevtutil",
				"Cobalt Strike",
				"Playcrypt",
				"Mimikatz"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434913,
	"ts_updated_at": 1775791832,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/bb2d8571dfc335cf251ad729b01023f5a5ce7089.pdf",
		"text": "https://archive.orkl.eu/bb2d8571dfc335cf251ad729b01023f5a5ce7089.txt",
		"img": "https://archive.orkl.eu/bb2d8571dfc335cf251ad729b01023f5a5ce7089.jpg"
	}
}