Analyzing DynoWiper - Sandworm's Polish Power Grid Wiper

in

Introduction

On it's 10th anniversary of the destructive attacks on Ukraine's power grid, Sandworm gained access to OT systems at energy plants in Poland at the end of December 2025. Using a wiper dubbed DynoWiper by Eset, it was not successful in causing electrical outages. Nonetheless, Dragos reported that some OT equipment was bricked on affected sites in what has been described as the largest cyberattack targeting the country in years.

We have obtained the specific DynoWiper sample that was used in this attack and we will dive into reversing the wiper in this blog post.

DynoWiper has the following features and behaviours:

  • Initializes a pseudorandom number generator using the Mersenne Twister with a seed of 0x1571
  • Uses the PRNG to generate 16 pseudorandom bytes for file overwrite operations
  • Identify all removable and fixed media drives on the system
  • Identify all folders, subfolders and files which it selectively overwrites
  • Removal of crucial operating system files
  • Obtaining of token privileges to force a system shutdown
Hash Type Hash Value
SHA1 4EC3C90846AF6B79EE1A5188EEFA3FD21F6D4CF6
SHA256 835b0d87ed2d49899ab6f9479cddb8b4e03f5aeb2365c50a51f9088dcede68d5

Table of Contents

Initializing Mersenne Twister PRNG

Directly at the start of WinMain, sub_403A90 is called, which initializes the internal state of a pseudorandom number generator, specifically using the Mersenne Twister MT19937 (or a very close variant). Distinct to Mersenne Twister in this operation is the usage of static value 0x6c078965 and the length of 0x270 (624).

Next, from WinMain, sub_401F40 uses the pseudorandom number generator to calculate blocks of 16-bytes which are stored at [esi+edi+5000].
DynoWiper Mersenne Twister Init

Identifying all drives and root paths

In sub_402CE0, all logical drives are obtained after which the malware loops over each drive. For each drive, it will obtain the lpRootPathName and the corresponding drivetype using GetDriveTypeW. When the drive is either a removable media or a fixed media, it will store the lpRootPathName.

Identifying, overwriting and removing files

In sub_402290, the wiper will iterate over each identified drive and enumerates every file in each drive using the iterator provided by FindFirstFileW and FindNextFileW. It first ensures that the obtained file is not equal to . or .., which by default are references to the current and top level directory. Next, it checks if the obtained file is of type directory. If the file is a directory, it will set the file attributes to FILE_ATTRIBUTE_NORMAL (0x80).

Subsequently, it will call sub_402500 which iterates over each file. If the file is once again a directory, it will first check that the directory name is not equal to system32, windows, program files, program files(x86), temp, recycle.bin, $recycle.bin, boot, perflogs, appdata, documents and settings. It will then call itself again using the newly obtained subdirectory and continue looping until a file has been found.
DynoWiper File Identification

In case the file is actually a file, it will call sub_402B30 which sets the file's attributes to and then attempts to open the file with generic read/write access. If it has obtained access, it will overwrite the first 16 bytes with the value stored in [esi+edi+5000] which holds a 16-byte buffer of bytes which were generated using the Mersenne Twister initialized PRNG. If the size of the file is larger than 16 bytes, it will continuously overwrite blocks of 16 bytes. Once this operation completes, the function returns to sub_402290.

Back in sub_402290, the obtained file is then removed using DeleteFileW
Mersenne Twister Init

Obtain token privileges to force a system shutdown

Back in the main function, the wiper obtains the current process token and checks if the SeShutdownPrivilege is part of the current token privileges. If it isn't the privilege is attempted to be obtained through a call to AdjustTokenPrivileges. Lastly, it will call ExitWindowsEx with a reason of SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_UPGRADE or SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_MINOR_MAINTENANCE
DynoWiper Shutdown