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 |
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].
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.
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
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