My own technical analysis of the malware that, in 2017, spread like wildfire encrypting thousands of computers, using one of the tools leaked from the National Security Agency by the group named ShadowBrokers.
Almost two years passed after that weekend of May 2017, when the crypto-worm WannaCry infested the net thanks to the EternalBlue exploit. In roughly two days, WannaCry spread itself all over the world infecting almost 230.000 computers in over 150 countries:
At that time, working as an Information Security Officer, with my colleagues, especially the guys from IT Infrastructure dept., worked hard to keep the entire Company perimeter safe. Luckily for us, we were not hit by the ransomware, but a lot of effort was spent explaining to the rest of the Company what happened.
Flash forward to 2019
Since this January, I've been running my own Dionaea honeypot that keeps catching a huge number of WannaCry samples. Just to give you some numbers, within two months, the 445 port was hit almost half a million times and I was able to collect roughly 18.000 of its samples at the rate of almost 300 samples per day.
If you notice from the file size, all these samples are all the same, and everyone of them is a WannaCry sample, delivered right to the 445 port in a DLL fashion.
Just to make a contribution to the WannaCry story, though small and useless, I thought it would be fun to analyze the internals of this malware as I wasn't able to do it back in the days. I will concentrate the analysis on its various layers and the most important parts of the code that make this malware unique.
Peeling the onion
First look at one of these samples, confirms that we're dealing with a malicious DLL and it's worth to note its compilation timestamp. Let's call this as
launcher.dll because of the evidence found in a string inside the code.
Luckily for us, this sample is not packed. We can check its Import and Export Address Table to get an idea of what this sample is able to do.
Easily enough, checking the imported API, we can assume that the malware uses something in its resource section and supposedly create a file and run a process. Commonly, DLL malware exports functionalities to the outside via its Export Address Table. We can see only one exported function and it's called PlayGame:
As noted above, malware imported some specific APIs to manage its resource section, like
LoadResource. We can easily recognize the magic numbers of a Portable Executable file - a Windows executable file - stored inside this section. We can dump it easily with tools like ResourceHacker:
But before analyzing it, we need to get rid of some bytes in the header, we'll come to these bytes later.
So now, we can open it and check its sections like we just did with the aforementioned DLL. Interestingly this new dumped executable seems 7 years older than the first one, its compile timestamp is dated November 2010 but, be aware that this date can be easily fake.
We can get an idea of what its purpose is by checking out the imported libraries:
We have to expect much more complexity in this stage than the DLL. We have a bunch of standard libraries like
iphlpapi.dll. This DLL was unknown for me so I found, from MSDN, that:
The Internet Protocol Helper (IP Helper) API enables the retrieval and modification of network configuration settings for the local computer.
The IP Helper API is applicable in any computing environment where programmatically manipulating network and TCP/IP configuration is useful. Typical applications include IP routing protocols and Simple Network Management Protocol (SNMP) agents.
A quick look suggests that this executable operates with Windows services configuration, manages files and resources and also, has network capabilities:
My plan is to give a deep look inside all various stages that the malware extracts during its execution, analyzing its code and how it interacts with internal Windows subsystems.
For this reason, we're now stepping back to analyze and understand how the DLL extracts this executable in the first place. Then we'll give a look inside the debugger to see how things happen in realtime and then, we will analyze and try to understand what this executable is going to do once it infects the system.
Analysis of the first layer: launcher.dll
The purpose of this DLL is exactly what we supposed thanks to the analysis of the imported libraries. The only exported function
PlayGame is easily disassembled by IDAPro.
The first call to
sprintf compose the
Dest string as
C:\WINDOWS\mssecsvc.exe. Then it calls two functions,
sub_10001016 that extracts, from its resource section, the executable we dumped before and then, saves it into a new file named as
Dest string; after that
sub_100010AB runs the file. Notice that we have just gained our first host-based indicator:
C:\WINDOWS\MSSECSVC.EXE for this malware detection.
For better reading and understanding this function, we can rename it as
ExtractAndCreate and we can split it into two parts: the extract part and the create file part.
During this phase, the malware uses four API calls, that are completely covered inside the MSDN.
FindResourceA: Determines the location of a resource with the specified type and name in the specified module.
LoadResource: Retrieves a handle that can be used to obtain a pointer to the first byte of the specified resource in memory.
LockResource: Retrieves a pointer to the specified resource in memory.
SizeOfResource: Retrieves the size, in bytes, of the specified resource.
That being said, we can now analyze step by step this simple four blocks of code. First function prototype is:
HRSRC FindResourceA( HMODULE hModule, LPCSTR lpName, LPCSTR lpType );
We have three function parameters that, as per calling convention, must be pushed in reverse order, so:
push offset Type ; "W" push 65h ; lpName push hModule ; hModule call ds:FindResourceA
hModule is being populated inside the
DLLMain method, and is equals to variable
hinstDLL: A handle to the DLL module. The value is the base address of the DLL. The HINSTANCE of a DLL is the same as the HMODULE of the DLL, so hinstDLL can be used in calls to functions that require a module handle.
lpName: The name of the resource. In this case, name is
101 in decimal value. If you look, name is confirmed by analyzing the DLL with ResourceHacker:
lpType: The resource type. Can be also noticed in the screenshot above.
From MSDN: If the function succeeds, the return value is a handle to the specified resource's information block. To obtain a handle to the resource, pass this handle to the
LoadResource function. If the function fails, the return value is
Coming back to the disassembly, this handle is returned into
EAX and then moved inside
EDI, where is being tested to check if it's
null. If it's not, the handle is pushed, as the second argument, to the next API call to
LoadResource. Quoting MSDN: it retrieves a handle that can be used to obtain a pointer to the first byte of the specified resource in memory. It also suggests:"...to obtain a pointer to the first byte of the resource data, call the LockResource function; to obtain the size of the resource, call SizeofResource".
HGLOBAL WINAPI LoadResource( _In_opt_ HMODULE hModule, _In_ HRSRC hResInfo );
hModule: A handle to the module whose executable file contains the resource.
hResInfo: A handle to the resource to be loaded.
The same approach applies with the other two API calls:
SizeofResource. The interesting thing to note here is that the return value from this last call, stored inside
EAX register as
500000, won't be used at all:
So now, looking in the debugger, we have:
ESI register contains the pointer to the memory region referred to the resource section that contains the executable itself. You can notice it thanks to the
MZ header in the memory dump. Remember the
4 bytes that were been removed with hex editor before? According to MSDN this DWORD is the actual size of raw data inside the resource section of the binary itself. So, this value
0x0038D000is moved into
EBX and then pushed as
lpBuffer to the
WriteFile function. Pretty standard call here:
CreateFileA will create a file with specific attributes. Parameter
dwFlagsAndAttributes, according to MSDN, a value of
0x4stands for: "The file is part of or used exclusively by an operating system".
After the call to
WriteFile, we have our executable saved and ready to run. The interesting parameters for this call are:
lpBuffer: equals to
ESI, is the value returned by the call to
LockResourceand is a pointer to the buffer to write into the file. Basically is a pointer to the binary inside the resource section.
nNumberOfBytesToWrite: as we said earlier, this parameter is the value pointed by the
DWORDinside of resource header. Its value represent the size of the binary data.
So now, we can enable a breakpoint right after the
WriteFile call and get the freshly created executable.
Here we're dealing with a very simple API call to
CreateProcessA, nothing fancy to add. I'd prefer not to dig inside all these parameters, it's completely covered inside the MSDN.
Conclusion after the first layer
What I would show here is my own study process: be aware, sometimes it can be very, very time-consuming but it gives me a big, complete and deep look inside Windows internals and how malware uses them. This proceeding, for me as a novice, helped a lot.
Analysis of the second layer: mssecsvc.exe
This will differs from the DLL file. As we noted initially, this executable is way more complex: we'll deal with various libraries and functionalities. But all start with a (Win)main function, right?
Do you remember the kill-switch? Do you remember the story behind? Give it a read, it's very interesting.
In general terms, the main function of a Windows program is named
WinMain, this is the first function that will be called when the program starts. We see a very strange url inside this code. Exactly the string is:
http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com and is referred through the
EDI register. After that, the
WinINet subsystem is initialized using the call to
InternetOpenA, this function returns a valid handle that the application passes to subsequent WinINet functions. Next, there's a call to
InternetOpenUrlA that opens a resource specified by a complete FTP or HTTP URL. After that the handle is closed and a new function is called:
sub_408090, we'll name it
In the first block of code, according to MSDN:
GetModuleFileNameA retrieves the fully qualified path for the file that contains the specified module. The module must have been loaded by the current process, first parameter
hModule is the handle to the loaded module whose path is being requested. If this parameter is NULL,
GetModuleFileNameA retrieves the path of the executable file of the current process. Here the value is set to
NULL, so it retrieves the name of the executable itself:
We then find a check on the number of arguments: if there are arguments the
TRUE path will be taken. Because, in our case, we're debugging without any argument, the
FALSE path is taken and a new function
sub_407F20 is called. This is a simple function that calls other two, so let's call it
sub_407C40 create a new service and then starts it, so we name it
CreateAndStartService. Service will be run with command line
mssecsvc.exe -m security and with a display name as
"Microsoft Security Center (2.0) Service" defined as
When we move then to
sub_407cE0, things start to become fun. For the sake of simplicity, we'll analyze this function in four parts. The first part is easy because the malware dynamically resolve some APIs:
Nothing too much complicated here: it uses
GetProcAddress to populate some variables with the address of specific APIs, so it can call them in the next lines of code. After that, the second part will manage the resource section, just like the way we analyzed in the DLL
This is confirmed into the debugger:
The return value from
LockResource, as we know, is the pointer to the resource section into the binary and we can notice the
MZ header into the memory dump. We then reach another interesting piece of code:
Two distinct string:
NewFileName, are created using
sprintf function. This two evidence are others good host-based indicators:
After that, the old file
tasksche.exe is moved into the new file
qeriuwjhrf and a new
tasksche.exe is created. Now, I found myself lost into somehow obscure code: I got that
WriteFile will dump the R resource into the created file
tasksche.exe and runs it at the end. What's inside the middle part, for me, remains in the dark.
In situations like this, I prefer to view the code inside the debugger because viewing the code during runtime maybe can help to shed some light. Indeed, seems like It created the command line for the incoming
To recap: this function dumps its resource data inside a new executable file named
tasksche.exe, making a copy inside another file named
qeriuwjhrf, and then run
Stepping back to
ServiceStuff function, there's the other path to analyze: when there are the arguments
"-m security", it enters into service mode. After its initialization, it changes service config:
According to MSDN, it changes the config so that failure actions occur if the service exits without entering a SERVICE_STOPPED state. After that, it executes its
This function setup the handles and starts exploiting the
MS17-010 vulnerability into the reachable networks. Note that it exits after 24h. Here, I renamed this function
This call starts a number of events that let the infection to happen. First thing, Winsock subsystem is initialized and a CryptoContext is generated:
Next, the malware will load a DLL into the memory - the very same
launcher.dll we analyzed before - and then run it. Networks attacks happen inside two new threads. This flow can be easily observed if we decompile this function:
The first thread, involving the function
sub_407720, will enumerates local network adapters and generates IP addresses compatible for those networks. For every IP, it tries to connect to port 445 and, if successful, launch the attack. Second thread, involving function
sub_407840, will run 128 times with 2 seconds (hex
7D0) delay between each run. It will generates random IP address and tries to connect on port 445, if connection is successful, malware will launch the EternalBlue attack. It's a pretty big chunk of code, but one interesting block of code is this:
Basically the malware, with the random IP placed into the
Dest string converted into the proper format, calls
CreateSocketAndConnect to try a connection to the 445 port, if the connection is successful, real attack is launched within the function
Conclusion after the second layer
So, until now, we got a DLL -
launcher.dll - that loads and runs a binary stored inside its resource section,
mssecsvc.exe. The very first time, a new service is created to achieve persistence and after that it scans the networks (local and random remote) launching the EternalBlue exploits against 445 ports. In its stand-alone version, it dumps another binary from its resource section and runs it. What's the purpose of this third binary? Let's give a look.
Analysis of the third layer: tasksche.exe
Remember that this executable come from the resource section of previous file,
mssecsvc.exe. When it runs as service, locates its resource section and writes it to the disk creating
tasksche.exe. When it starts, it first generates a random string based on computer name, then checks if there are some command line arguments, in particular, if there's
/i as argument. We have now two branches to analyze:
- If there's
/iargument: it creates specific directories and copies the file over it, like
C:\ProgramData\somerandomstring\tasksche.exeand runs it from there.
- If there's no
/iargument: it locates its resource section, named XIA, storing and extracting it onto disk. What's interesting to note here that this resource is a compressed password protected archive. Luckily for us, password is hardcoded in clear text.
Let's give a look inside the archive knowing the password: [email protected]
We can recognize the magic numbers for a ZIP file that we can dump directly and extract.
b.wnry is the bitmap image of the ransomware. Basically what you see as wallpaper when the computer is infected.
c.wnry is the configuration file in clear text, we can see some
onion servers and the archive containing the TOR browser.
r.wnry contains some text ransom note.
msg folder there are some localized ransom note:
Conclusion after the third layer
This new executable seems pretty interesting because basically, it manages all the crypto actions involved within the ransomware. I won't go into this analysis because it's beyond my actual skills and also because, there are plenty of resources available on the internet, from amazing guys that are way better than me. For example, this technical analysis by FireEye was published only few days aftermath and is complete, deep and detailed. I used it a lot to better understand many pieces of obscure code.
I have learned a lot from this research: I learned how malware interacts with their resource section to hide, dump and create files; I learned how malware interacts with Windows service manager and how they actually load DLLs in memory, how they scans networks and how EternalBlue actually works. Also, having available such complete and detailed technical analysis, on this very specific malware, helped me to not loose the direction when I went too deep inside the assembly code. It was very fun and I hope this research will be helpful to someone at least as it was for me.