WannaCry Ransomware
Last updated
Was this helpful?
Last updated
Was this helpful?
after detonating the malware we can notice that
sandbox escape technique which detects fake internet by connecting to a url.
it runs if there is no internet connection
files are encrypted with the extenstion WNCRY
there is a readme file where the malware author asks for money to decrypt victim files
this is the interesting strings i've found i didn't look deeply into the strings
the resource 1831
contains an executable which can be malicious and unpacked by wannacry binary at runtime to perform malicious behaviors.
calls the InternetOpenA
win32 api function to is used to initialize the use of WinINet
functions which enables your application to interact with FTP and HTTP protocols to access Internet resources.
the binary loads a url string http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com
into ecx register
calls the InternetOpenUrlA
win32 api function to open the url and returns a valid handle to the URL if the connection is successfully established, or NULL if the connection fails.
if the connection to the url is established successfully then it will exit without doing anything to the victim.
if the connection is not established and the InternetOpenUrlA
win32 api function returned NULL
then it will call the function sub_408090
if we have internet connection we can see that the program always exits since the domain is registered by someone
here is the domain being checked which is already registered on the web by someone
so we have 2 solutions. patch the binary to make the comparaison always go to the interesting part where it calls the function sub_40890
or we can just turn off internet connection which we will do to make things simple.
now setting a breakpoint again we can see that it jumps to the other location
this function gets the full path to the wannacry executable using GetModuleFilenameA
and then checks if the wannacry executable is executed with arguments or no arguments.
if it's executed with no arguments the function sub_407F20
is called and then the program is done. else it opens an already created service called mssecsvc2.0
(will see later the program will be executed with arguments using an auto start service mssecsvc2.0
)
proceeding to the function sub_407F20
since the ransomeware wannacry is executed by victims by clicking on the exe so it's run without arguments. the function calls 2 functions
let's proceed to the first one sub_407C40
.
the variable buffer is assigned the string {path_to_wncry_exe} -m security
for exemple in my case its C:\Users\Azer\Desktop\Ransomware.wannacry.exe -m security
open the service manager using OpenSCManagerA
which is used to make other service related operations like starting or creating a service.
creates a service using CreateServiceA
with the ServiceName mssecsvc2.0
and DisplayName Microsoft Security Center (2.0) Service
and the fifth arg is 0x10 which means that the service will run in its own process
the sixth arg is 2 which means the service is set to auto-start
eigth arg is Buffer which is the BinaryPathName which is C:\Users\Azer\Desktop\Ransomware.wannacry.exe -m security
you can view the official docs and check all arguments passed and what they mean
starts the created service using StartServiceA
to see the service created we will be detonating the malware or setting a breakpoint after starting the service
let's run the binary by clicking on the green start button after hitting out breakpoint let's open the services windows by clicking on win + R -> services.msc
after we will enter the function sub_407CE0
Hiding imports via dynamic WinAPI functions resolving :
Import Address Table (IAT) stores information about libraries and functions that are used by the application. OS dynamically loads them at the executable startup. Very convinient (well it’s just how Windows works) however the table contents can give a lot of information about program functionality which could lead to being detected statically by antivirus vendors.
to hide this informations malware authors use a technique to dynamically resolve API function addresses using GetModuleHandleW
to get handle to kernel32.dll
loaded in memory and then find necessary functions with GetProcAddress
.
to find the module used to find function address we have to find it dynamically so we will break after calling GetModuleHandleW
which will return a handle to the module being used. which will be stored in eax
register.
after it starts extracting the resource 1831
which contains an executable from resources section. this is the resource we've found using pestudio.
so now to extract this resource content we can either copy the whole hex dump of the executable using a debugger or we can just dump it statically since its hard coded into the resources section of the binary, using pestudio
tool we can do so.
using a debugger :
set a breakpoint just after the LockReource
function after this the executable content will be stored in the eax register since functions return values are stored in the eax register. copy the address of eax and then go to hex view click on g
and paste the address of eax and you will see that the eax data starts with the MZ
header which confirms that its an executable.
using pestudio :
double click on executable and then save the file
let's open it using a hex editor program HXD
we can also use detect it easy
to see more infos about the executable
opening the dumped executable using ida pro and looking at strings we can see crypto related strings which ensures that this is the part doing the encryption process. we can also see the encryption model used which is RSA so the ransomware may be is using public private key encryption.
let's get back to the code after extracting the resource 1831
, after it creates two variables taskexe_path
qeriu_path
which hold different file paths and then creates a file using CreateFileA
.
to find out what is the file created we will set a breakpoint at CreateFileA
and then we will double click on taskexe_path
after knowing the path we will step one instruction and search for the file created in the file system
breaking at the call CreateFileA instruction, double click on taskexe_path to view the path
the file will be created at C:\Windows\tasksche.exe
let's step one more instruction in the debugger using f8
and then open file explorer and search for this file
we notice that the file created is empty.
after this we will break after the WriteFile
api function
now let's search for the value stored in &off_431340
by searching for the offset in hex view click on g
and paste the offset and click enter
20 2F 69 00
-> \i
so the variable taskexe_path
will be C:\WINDOWS\tasksche.exe \i
after this a new process will be created using CreateProcessA
which will be executing the command line C:\WINDOWS\tasksche.exe \i
we will open process hacker since it may notify us about some changes if there is any when the process is created also we can search in the list of processes for any newly created process. let's set a breakpoint just after the call CreateProcessA
instruction and then run the debugger.
we can notice just after the instruction call CreateProcessA
being executed process hacker notifies us about a newly created service with the name bejrpjlecxiq111
process hacker detected a newly created service bejrpjlecxiq111
let's search in process hacker for newly created process and we can find the process tasksche.exe
which is the file containing the executable extracted from 1831
resource.
for more informations about the process tasksche.exe
double click on it.
we can see that the path of the tasksche.exe is moved from C:\Windows\tasksche.exe
to C:\ProgramData\bejrpjlecxiq111\tasksche.exe
after few minutes new subprocesses apppear
to run a binary with arguments in ida click on debugger -> run -> local windows debugger
and then specify the path to the binary and the argument
now let's reverse the resource 1831 which is injected into tasksche.exe using ida pro again
first thing it gets the path to the executable, after it calls the function sub_401225
, essentially this function generates a pseudo-random string with a length between 11 and 18 characters, consisting of lowercase letters followed by digits generated based on the computer name value retrieved using GetComputerNameW
to see what is the random string generated we will set a breakpoint and follow execution after the instruction call sub_401225
which will return the value of the random string and therefore this value will be stored in eax register labeled as DisplayName, copy the address of eax and then in the hex view click on g
and search for that address anc click enter
the random string generated is bjerpjlecxiq111
which is the service created previously and its part of the path where tasksche.exe is moved.
after this it will do a bunch of checks
first check :
checks if the res 1831 program is launched with an argument and if it retuns false it will pass to the next check
second check : if it passed to this check that means that the argument is provided so this second check checks if the argument passed is "/i" (we saw that the res 1831 is passed to tasksche.exe and executed with "/i") if it's not "/i" it will pass to the next check
third check :
it will call the function sub_401B5F
to find out what is FileName value is we will resolve its value dynamically by following execution after executing the whole command and then hover over the FileName and search for it in hex view
we see that FileName is :
FileName -> C:\ProgramData
after it will call GetFileAttributesW
on FileName
which is C:\ProgramData
to check whether this Directory exists or not, if it exists it will proceed to call the function sub_401AF6
after this it will call the function sub_401AF6
with FileName C:\ProgramData
as first arguement and bjerpjlecxiq111
as second argument
here is the decompiled code for sub_401AF6
it changes the current working directory to the lpPathName directory C:\ProgramData\
and then creates a directory bejrpjlecxiq111
at C:\ProgramData
and finally sets the directory bejrpjlecxiq111
as hidden using SetFileAttributesW
and supplying
after this it will exit the function sub_401B5F
and it will execute this command
after executing the instruction call CopyFileA
, the file tasksche.exe
will be copied to the destination C:\ProgramData\bejrpjlecxiq111\
fourth check :
then sub401F5D
is called
first of all it will get the full path name for tasksche.exe
using the windows api function GetFullPathNameA
and then it will call sub_401CE8
which tries to open the service with the name bejrpjlecxiq111
and if it's already created ,it will just start it if not it will create it
if the service is not already created it will create it, but before it will set up some arguments and the first one is the command line that the created service will execute. so it formats the buffer variable with the string cmd.exe /c C:\ProgramData\bejrpjlecxiq111\tasksche.exe
wich will be the CommandLine to execute.
to see the content of buffer we can just double click it
we can copy the beginning address in hex view for better formatting and readability
there is a bunch of arguments passed to CreateServiceA
api function you can visit microsoft docs to read what each one does but the most important ones are binaryPathName which is assigned the value of the buffer which contains the command line constructed cmd.exe /c C:\ProgramData\bejrpjlecxiq111\tasksche.exe
since the buffer is passed to eax and then eax is passed to the 8th argument (binaryPathName arg) and the StartType which is 2
which means that the service will auto-start
and the ServiceType which is 10
which means that the process will run in its own process
and then it starts the service using StartServiceA
which run the wannacry res1831 encryptor with no arguments as a result it encrypts all the files in the system.
and then calls the function sub_401EFF
which creates a mutex to ensure that no two instances of the binary are running at the same time
and then exits the program.
when tasksche.exe
is run without arguments another path is taken where it does file system encryption and other operations.
importing the wncry.dump (1831 res) into ida pro directly and start executing it will make it execute with no arguments.
so it will bypass the if check since the first check *_p___argc() != 2
will return true and then jump into the strrchr
command
and then the function sub_4010FD
is called with argument 1
aSoftware -> "Software\"
, this string is passed to the variable Destination
the string WanaCrypt0r
is appended at the end of the string aSoftware so the Destination variable will be Software\WanaCrypt0r
since v12 = 0 the registry subKey will be created at HKEY_LOCAL_MACHINE
, to search for the subkey in regedit just CTRL + F
and search for WanaCrypt0r
since a1 is the argument passed to the function sub_4010FD
and the argument is 1
that means that the first block will be executed, so it will get the CurrentDirectory and create a key value pair in the registry subKey created
after it will close the handle to registry and exit.
then call sub_401DAB(0, Str);
where Str is WNcry@2ol7
in the beginning it will extract the resource 2058 from resources section using 4 windows api functions FindResourceA
, LoadResource
, LockResource
and SizeofResource
let's extract this resource, i've couldn't extract it using pestudio
tool
instead i will be using the wrestool
the resource is a password protected zip, let's try using the string passed to the function WNcry@2ol7
and it worked
we can notice that those files extracted from the resource 2058 are the files copied to C:\ProgramData\bejrpjlecxiq111\
it loops through all extracted zip files creates files with there names writes their content in the files, change timestamp of the files and then moves them to the current working directory where tasksche.exe file is located
creates and writes the content of b.wnry
and then changes some time properties of the file using SetFileTime
before it modified the time properties
after it has modified the time properties using SetFileTime
finally when the function sub_401DAB
ends all files are moved to C:\ProgramData\bjerpjlecxiq111\
after it calls the function sub_401E9E
the function sub_401000
when takes second argument different than 0 it reads the content of c.wnry
into the first argument Buffer
, and then wannacry randomly chooses one of the three available Bitcoin addresses and then writes this address back to the c.wnry
file.
c.wnry
file contains multiple .onion
addresses and Tor zip file
the function sub_401064
sets the current directory of the running process which is C:\ProgramData\bejrpjlecxiq111
to hidden using attrib +h .
command
the function sub_401064
uses windows icacls to grant full access to all files on the target system.
After it retrieves the cryptographic key provider using CryptAcquireContextA
— Microsoft Enhanced RSA and AES Cryptographic Provider
if the lpFileName is 0 it will call the function CryptImportKey
with a global buffer variable &unk_40EBF8
, double clicking on it apprears that it's a Microsoft RSA key BLOB
, according to microsoft documentation page this function transfers a cryptographic key
from a key BLOB
into a cryptographic service provider
(CSP), so i have renamed it to RSA_KEY in case it's used somewhere else.
if lpFileName is not 0 it will read the RSA_KEY from a file
in case of failure it will destoryKeys and release Crypto Context
and then passes the t.wnry
file name as first argument and 0 as second argument
if the t.wnry
file is already created it takes the file size using GetFileSizeEx
and it reads the first 8 bytes
from the file and compares to WANACRY!
, then reads 4 bytes and checks if it equals to 256
, then reads 256 bytes
.
calls the function sub_4019E1
which takes the 256bytes as argument, and tries to decrypt it using CryptDecrypt
function and the RSA_KEY loaded previously.
so t.wnry
contains encrypted content and the decompiled code and the assembly code is very hard to understand so rather than understanding the decryption logic and do it ourselves what we will do is follow execution until it gets fully decrypted by the malware :)
setting a breakpoint at the return value of the function sub_4021BD
reveals an executable since the header magic bytes
is MZ
.
let's copy the hex dump of the executable and dump it. once it's dumped let's open it using detect it easy
tool which detected the file as a 32 bit DLL.
and then calls the function sub_402924
with 2 arguments the first one being pointer to DLL
and the second one the string TaskStart
which uses the function stricmp
to lookup for the function TaskStart within the DLL and returns the address of the function within the DLL.
then loads the dll and calls the function TaskStart
so we can conclude thatthe file
t.wnry is an Encrypted DLL Component
and the main ransomware encryption component and harmfull code is within this DLL.
first thing the malware creates 3 strings 00000000.res
, 00000000.eky
and 00000000.pky
then calls sub_10004600
which opens a mutex Global\\MsWinZonesCacheCounterMutexW
and if the mutex is already opened and we can get a handle to it that means that the TaskStart function is already executed and the return value is 1 if not the mutex will be created and the result returned is 0.
if the returned value is 0 it will call the function sub_10004990
if not it will start by creating a thread. let's suppose that the TaskStart is being executed for the first time so the mutex will not be opened since there's no handle to it so it will return 0 so the next function sub_10004500
will be executed.
creates 00000000.dky
string and then verifies the existance of the pky and dky files using GetFileAttributesA
, then calls the function sub_10003D10
which imports the pky and dky files and tests the encryption and decryption process of some test data using CryptEncrypt
and CryptDecrypt
so 00000000.dky
file presents a decryption RSA key which is received upon the payment has been verified. When the victim clicks the “Check Payment” button.
if both files pky and dky exist and the encryption and decryption of TESTDATA
was successfull the returned value will be 1 which means a thread will be created which will execute the function sub_10004990
. for now let's suppose the files do not exist and we will be explaining the function sub_10004990
later.
so if both files do not exist it will call the function sub_10003AC0(pky, eky)
which takes pky and eky files as arguments, it starts by acquiring crypto context so it can use the crypto api provided by windows then it checks if the pky file exists, if it's the case it will import it from file using CryptImportKey
, if it doesn't exist it will import it from the binary
CryptImportKey returns TRUE if it succeeds and with the !
it will be FALSE so it will generate a 2048 bit RSA Victim Public/Private Key Pair using CryptGenKey
and then export the public key using CryptExportKey
to pky file. then export the private key using CryptExportKey
and encrypt it using another binary hardcoded Attacker public key and save it to eky file.
00000000.eky
-> is the Victim Private Key Encrypted with the Attacker Public Key hardcoded in the binary
00000000.pky
-> is the victim's Public Key
every 5 seconds checks whether the user payed the ransom by testing the existence of the pky and dky files and if they exist testing the encryption and decryption process using some test data, and if everything works perfectly it sets a global variable to notify all other parts of the program.
first it gets bitmask representing all drives connected to the system (hard drive, removal media, CD-ROM ...etc) using GetLogicalDrives
and then copies the result to another variable and after 3 seconds it gets another result again using GetLogicalDrives
and compares the two results and if they are different it detects that a new drive is attached to the system and it keeps doing so every 3 seconds until the global variable decryption_successful_global_var
is set to TRUE which means that the victim has payed the ransom, so we can conclude that it does this so it encrypts every drive attached to the system.
so when a new drive is attached it will call sub_10005680
function. using GetDriveTypeW
it checks the type of the drive attached and if the drive id of the drive attached is 5 it simply returns without encrypting its files. 5 indicates a drive of type CD-ROM so all drives attached their files will be encrypted except for CD-ROM.
and then it starts iterating through directories of the drive and does some checks on what files to encrypt and what to not encrypt.
it checks the directory being iterated is one of those directories and if it does it skips it since wannacry doesn't encrypt the files important to the filesystem since corrupting the system files will not give the victim the ability to pay the ransom.
if the file being iterated is one of the wannacry files it skips it since wannacry doesn't want to encrypt its own files.
and then it checks the type of the file being iterated using the function sub_10002D60
so it cat determine which files should be encrypted and which files should be ignored.
which checks for the extension of the file using the function wcsrchr
and get the last occurence of the character .
in the filename and then gets the extension of the file.
if the extension of the file is .exe
or .dll
returns 1.
if the extension of the file is .WNCRY
returns 6.
if the file extensions matches one of those extensions in the list it will return 2.
if the file extensions matches one of those extensions in the list it will return 3.
all the extensions to be encrypted
and finally checks for the extension .WNCYR
for which it returns 5 and WNCRYT
for which it returns 4.
and then it adds the files to a list which returned values different than 1 or 6 which means files that have extensions different than .WNCRY
, .exe
, .dll
and then to encrypt each file being iterated in the file list, it generates for each file a 16-byte symmetric AES key using the CryptGenRandom
function, and then encrypts the key using the file 00000000.pky
which contains the victim public key, the encryption is done using the function CryptEncrypt
.
Each file encrypted by the malware starts with the string WANACRY!
, then the encrypted key length, the encrypted key, the file type which is 4, then file size, and finally the encrypted file contents.
to decrypt data encrypted by wannacry we have to first know how data is getting encrypted.
we know that each file is encrypted using an AES key, and then the AES key is encrypted using victim's public key
and stored inside the encrypted file.
to decrypt the AES KEY encrypted with the victim's public key we should have the victim's private key, we know that the file 00000000.eky
contains the victim's private key encrypted with the attacker public key which was embedded in the binary.
to decrypt the encrypted victim's private key we need the attacker private key which we do not have until we pay the ransomware.
Steps to decrypt data :
use attacker's private key to decrypt the victim's private key encrypted with the attacker public key.
use the victim's private key to decrypt the encrypted AES key encrypted with the victim's public key for each file (the encrypted AES KEY is stored in each encrypted .WNCRY file).
use the decrypted AES key to decrypt file.
spawns a thread running the function sub_10005300
which runs the executable taskdl.exe
every 30 seconds using a process if the global variable decryption_successful_global_var
is not true which means the victim hasn't payed the ransom.
then spawns another thread running the function sub_10004990
which runs the command taskse.exe @WanaDecryptor@.exe
every 30 seconds using a process and then WannaCry adds malicious registry entries to make persistence into the system, so that it could launch the infection after each system reboots using the command cmd.exe /c reg add %s /v \"%s\" /t REG_SZ /d \"\\\"%s\\\"\" /f
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
<random_alphanumeric>=C:\ProgramData\<random_alphanumeric>\tasksche.exe
taskse.exe is an executable which enumetates RDP Sessions using WTSEnumerateSessions
function and executes the first argument in the RDP Sessions found. and this is done to ensure all the rdp sessions can see the wannacry window.
@WanaDecryptor@.exe
which is responsible for showing the payment and timer windows for the victim and decryption process if the victim payed the ransom.
it runs the command cmd.exe /c start /b @WanaDecryptor@.exe vs
using CreateProcessA
reversing @WanaDecryptor@.exe
we can find that it checks if the argument passed to it is vs
if it's the case it will execute the command cmd.exe /c vssadmin delete shadows /all /quiet & wmic shadowcopy delete & bcdedit /set {default} bootstatuspolicy ignore allfailures & bcdedit /set {default} recoveryenabled no & wbadmin delete catalog -quiet
using a CreateProcessA
these commands are used by wannacry ransomware after encrypting data to prevent data recovery
vssadmin delete shadows/all/quiet : delete all Volume Shadow Copies silently.
wmic shadowcopy delete : same as the previous one. used to ensure removal of any backup copies.
bcdedit /set {default} bootstatuspolicy ignore allfailures : setting the boot status policy for the default operating system to "ignore". This action is aimed at preventing the system from displaying error messages during startup, which could potentially alert the user to suspicious activity.
bcdedit /set {default} recoveryenabled no : Disables the Windows recovery feature, which means preventing the victims from the possibility to reverting their system to a previous build.
wbadmin delete catalog -quiet : delete the backup catalog without generating any notification or prompts.
terminate processes associated with Microsoft Exchange, SQL Server, and MySQL which ensures that the ransomware can encrypt files without interference from these database or server processes, which might prevent encryption. doing this it can encrypt as many files as possible, maximizing the impact of the ransomware attack