You are on page 1of 25

Analysis of W32/Virut.

ce

Author: Liviu Serban

Avira GmbH

Page 1 of 25

W32/Virut.ce is one of the most widespread pieces of malware which can be found on infected computers. The virus is infecting executable files using latest techniques which make detecting and treating those files particularly difficult. On the current threat landscape we see more server-side polymorphism malware, infecting executable files is not that than a few years ago. During the last years emulation technics have become better which makes detection of polymorph malware much easier. The authors of the virus werent put off by the difficulties they faced in trying to infected executable files. But W32/Virut.ce is not only infecting executable files, the virus also includes a backdoor using the IRC protocol. This allows attackers to download and run further malware from the internet which can as example steal information. The server to which the malware connects is a pre-defined IRC server, the channel is called virtu. The technics used inside Virut reflects latest methods used to write malware using anti-emulation technics, anti-debugging tools and calling of multiple fake API functions. In our Virus Lab we made a deeper analysis of this file and created this document to share our information. Lets start with the analysis of the virus: The malware creates a section object and copies the virus code into the mapped view of the created section. After this is done, the section is mapped into the active process. Beside that it hooks some API functions from ntdll.dll, the functions are the following: NtOpenFile NtCreateFile NtCreateProcess NtCreateProcessExe

Every time someone creates a process or opens an executable file that file will be infected by the virus. The method of infection is quite straightforward. It copies the virus code at the end of the last section which is .rsrc or .reloc and employs several methods to gain control depending on the file that is currently infecting: 1) Modify the entry point to the address of the virus code 2) Patches a random kernel32.dll call which points to the virus code 3) Copies a small decryptor to the end of the .text section and modifies the entry point to point to the decryption code. This decryptor will decrypt the virus code and gives control to the decrypted virus code in the last section. 4) Similar to point 3 with the difference that a random kernel32.dll call is patched inside the file which calls the code at the end of the .text section The virus itself is using, as written above anti-debugging and anti-emulation techniques like: Running on the exception handler rdtsc calls Two polymorphic layers of encryption

Analysis of W32/Virut.ce

Avira GmbH

Page 2 of 25

Lets start analyzing the virus using a debugger:

As you can see in the code snipped, the virus is located in the .rsrc section the PE File. As general rule, whenever you see code within .rsrc, .reloc, .rdata or inside the .data section you could be quite sure that it might be some malicious code. The first what this virus does it to call a function (renamed to main_virut in the code snipped). This function sets up a shell handler on the stack push dword fs:0 and then move fs:0,esp after that it tries to call the GetProcAddress function but if you look at the GetProcAddress parameters pushed on the stack you would find something rather strange, ebx is the hModule which is zero and the lpProcName has a

Analysis of W32/Virut.ce

Avira GmbH

Page 3 of 25

strange value. The MSDN documentation tells us that lpProcName is a long pointer to the function or variable name or the functions ordinal value. On some versions of NT this is doomed to throw an exception, on others GetProcAddress will return NULL. If it throws an exception the last exception handles will be executed and is pushed on the stack by the virus itself. This means the rest of the virus code will be executed on the exception handler. Explanation of the anti-emulation trick: A few notes about exception handling in Win32 systems and some notes about how C/C++ linker and Microsoft Windows Win32 API using the shell handlers. In order to explain this, we need a short example:
DWORD do_something (void * pointer) { DWORD val = 0; _try { val = *(DWORD*)pointer; return val; } _except( EXCEPTION_EXECUTE_HANDLER ) { printf( "Caught the exception in main()\n" ); } return 0; }

Looking at this function if the pointer is NULL of course will crash and the filter exception routine (_except) will get executed. So in a nutshell the execution will stop at val = *(DWORD*)pointer and the execution will resume in the printf inside the _except function. So now lets see how the C linker translates this into raw code. You have probably seen these instructions before: Push dword fs:0 mov fs:0, esp This is exactly the exception handler (try / _except statement). The FS register holds the address of the TEB and FS:[0] is the list head of the exception handlers. The exception handlers are in fact a linked list stored on the stack. The structure looks like:
typedef struct _EXCEPTION_REGISTRATION { _EXCEPTION_REGISTRATION * Next PEXCEPTION_ROUTINE Handler; }

So what is pushed on the stack is a pointer to a function (the handler) and the link to the next exception_registration structure and the brand new exception_registration is now the list head. If you are scrolling back to the virus code you would see:

Analysis of W32/Virut.ce

Avira GmbH

Page 4 of 25

call main_virut call 0xwhatever

when call main_virut is executed, the address of the next instruction is pushed on the stack and the execution continues at main_virut function which, as we know now sets up the exception handler. FS:0 (exception registration linked list) is ESPs value and ESP itself points to the previous FS:0 and the next item on the stack is the return address that we were talking about. So thats a new exception_registration structure. If GetProcAddress fails the execution is passed to the exception handler which is the rest of the virus code. Now looking at the exception handler it points at the first byte after GetProcAddress call. This call is the virus decrypter code, the virus has two layers of decryption. First it gets a key in EDX. The size is in ESI and the base is in EDI. It then starts to decrypt the virus using a simple XOR operation and adds certain values to the key at each step. After the decryption operation completed it jumps at the decrypted virus code using jump EDI.

Analysis of W32/Virut.ce

Avira GmbH

Page 5 of 25

Explanation of the anti-virtualization trick: After we can look at the decrypted virus code we see two interesting rdtsc calls. The simple rdtsc calls are used as anti-virtualization/anti debugging trick: First rdtsc reads the time stamp counter into EDX:EAX. After the first call the virus saves the EAX value into ECX and calls the rdtsc function again. The the virus substracts the new EAX (from the last rdtsc call from ECX which was the first rdtsc call). If the value is less than 0x40 it continues otherwise it will jump to exit. Why does the virus do that? Well, on a real computer the time between those two rdtsc calls should be in general less than 50 but on a debugger or a virut machine the value is generally higher than that. So on a virtual machine it will exit and the virus wouldnt start.

After that it goes and calls the second decryption function. EAX points to virut_body, dl holds the decryption key and now we are able to go to the decrypted virus body to see the payload.

Analysis of W32/Virut.ce

Avira GmbH

Page 6 of 25

We see the following interesting instruction in the code snipped: cmp dword ptr [ebx+4eh], This If you look before the two calls to rdtsc, you can see were EBX points to: mov ebx, [esp+4] Inside the esp+4 we can see a address within kernel32.dll. In order to understand you need to know the layout of the stack when int main() gets called via CreateProcess API. If you create a process using CreateProcess via the API or double click an executable file, CreateProcess gets called and besides doing a lot initialization it also creates a thread (the startup thread for the new process) and the startup function of this thread is a tiny stub located in kernel32.dll called BaseProcessStartup, this stub looks like:

Analysis of W32/Virut.ce

Avira GmbH

Page 7 of 25

VOID WINAPI BaseProcessStartup (PPROCESS_START_ROUTINE lpStartAddress) { UINT uExitCode = 0; DPRINT("BaseProcessStartup(..) - setting up exception frame.\n"); try { NtSetInformationThread(NtCurrentThread(), ThreadQuerySetWin32StartAddress, &lpStartAddress, sizeof(PPROCESS_START_ROUTINE)); /* Call the Start Routine */ uExitCode = (lpStartAddress)(); } _except(BaseExceptionFilter(GetExceptionInformation())) { uExitCode = GetExceptionCode(); } ExitProcess(uExitCode); } The first thread in the process was created and its startup address is this stub which calls the entry point of the executable file. Now we know that after this instruction mov ebx,[esp+4], ebx points to something inside kernel32.dll. Since we have this information and since viruses dont have imported functions the usual way to get to those APIs is get to the base address of the kernel32.dll and from there use the layout of PE files in order to get to the export directory of the DLL. From there the virus can get the exported functions which are needed, this is what the virus does in the last code snipped. In general there are four ways viruses can get the desired APIs: 1) 2) 3) 4) Get the address of GetProcAddress which can be used to get the needed API Scan the whole IMAGE_EXPORT_DIRECTORY of kernel32.dll and get the needed APIs Use a CRC32 on the API names or the API address Use the direct addresses of those APIs since kernel32.dll and ntdll.dll are located at known addresses in all process (This doesnt work on Microsoft Windows Vista because Vista uses randomization of the base address of these DLLs. It wont relocate the DLLs at the same addresses every time).

Virut makes use of the first method which is obviously the most straightforward of all. The following APIs are requested by Virut from kernel32.dll using GetProcAddress:

Analysis of W32/Virut.ce

Avira GmbH

Page 8 of 25

After obtaining the desired APIs from kernel32.dll, the virus goes to ntdll.dll to get some other APIs. After obtaining the ntdll.dll APIs it stores the SSDT index of the following APIs:

NtCreateFile NtOpenFile NtCreateProcess NtCreateProcessEx

Analysis of W32/Virut.ce

Avira GmbH

Page 9 of 25

The mentioned APIs will be hooked by the virus. Hooking NtCreateProcess will end up that every started process will be infected. This is another method than using the classic FindFirstFile/FindNextFile functions. After the infection of the file, it will use the saved index to do an in2E or systenter into ring 0 to actually let the OS doing the real work of creating a process or file. It then creates a section object with the following name \BaseNamedObjects\VtSect maps the section into memory and copies the virus code into that mapped view of the section. The section is backed by the paging file and by any ordinary file. It will use this mapped view of the section to pen it in other processes, so that the virus code will end up in several processes. The following code is responsible for this action:

Analysis of W32/Virut.ce

Avira GmbH

Page 10 of 25

After the section object has been created and it has been mapped into memory and the virus code has been copied into it, now the virus will use some useful APIs to find the winlogon address space. The set of APIs which are used are CreateToolHelp32Snapshot similar APIs. As you can see ESI is 0, it calls Process32First which is obviously the System Idle Process. Not that much to do with the system process since we are in User Mode. Then it calls Process32Next until ESI is > 4. We will open a process explorer to see why, the first process is the System Idle Process, the second is the System Process, the third is smss.exe and the fourth process is crss.exe. After all these iterations we will get to the winlogon.exe process. Looking at the stack in the right side of the picture you will see an smss.exe string on the stack. This comes due to the fact that Process32Next has two parameters, a handle to the snapshot obtained by calling CreateToolHelp32Snapshot and a PROCESSENTRY32 pointer that contains some info about the current process.

Analysis of W32/Virut.ce

Avira GmbH

Page 11 of 25

Analysis of W32/Virut.ce

Avira GmbH

Page 12 of 25

We open the process and then we go to the mapped section (Virut section that we have created earlier) into winlogon virtual address space, we hook NtCreateFile, NtOpenFile, NtCreateProcess and NtCreateProcessEx and then we create a remote thread inside winlogon.exe. This method allows to stay resident in memory as winlgon is not an ordinary user mode process and winlogon wont close until shutdown the system. Hooking of the APIs in ntdll.dll will enable the virus to infected any exe file that is used as an argument for CreateProcess or CreateFile APIs. The following code snipped shows the map section in winlogon.exe and writes the inline jumps in the specified API functions:

Analysis of W32/Virut.ce

Avira GmbH The next code snipped shows the inline_jump routine:

Page 13 of 25

Now we know that NtCreateFile, NtOpenFile, NtCreateProcess and NtCreateProcessEx are hooked, we start debugging winlogon.exe and analyze the code over there to see how Virut infects files via the hooked API calls. The next code snipped shows the infected code in one of the active processes virtual address space:

Now going at virus_inline_jump we will see the code, that is used to infect the file give as argument to NtCreatefileSystem service:

Analysis of W32/Virut.ce

Avira GmbH

Page 14 of 25

Now we try to understand what the virus is doing for this well first have a look to the MSDN and look for the NtCreateFile System Service declaration:
NTSYSAPI NTSTATUS NTAPI NtCreateFile( OUT PHANDLE IN ACCESS_MASK IN POBJECT_ATTRIBUTES OUT PIO_STATUS_BLOCK IN PLARGE_INTEGER IN ULONG IN ULONG IN ULONG IN ULONG IN PVOID IN ULONG FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize OPTIONAL, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer OPTIONAL, EaLength );

We can see that the virus is doing a push instruction which pushes all registers. The size on the stack for all register is 0x24 and we have the return address from NtCreateFile and the arguments for NtCreateFile itself. The instruction mov eax,[esp+30h] will get to the object attributes pointer within the stack. Using mov edx,[eax+8] will get the address of the file name that was passed as argument to the CreateFile API. Together with this file name we can check if it is a executable file and if yes, the file will get infected. The virus code is looking if the file is a EXE file and not a DLL file.

Analysis of W32/Virut.ce

Avira GmbH

Page 15 of 25

The infection algorithm is pretty simple the only difficult is with the EPO (Entry Point Obscuring). The virus copies itself to the last section .rsrc or .reloc with its polymorphic decrypter and then it tries to find a way to gain control. One method is to copy a tiny stub to the last portion of the .text section and modify the entry point to point to that tiny stub and from there the virus will get to its decryption code in the last section. If it cannot copy the stub to the end of the .text section the virus will try to find a kernel32.dll call to hook it to point to the virus code within the last section. There are two methods to handle import calls depending on the used compiler: Using Borland C++ and using the GetModuleHandle API function, the code which is generated by the Borland compiler would look like:
call somewhere_inside_text_section opcode is 0xE9xxxxxxxx somewhere_inside_text_section: jmp dword ptr [address_of_GetModuleHandle_in_import_table]

For the Microsoft C++ compiler the same would look like:
call dword ptr [address_of_GetModuleHandle_in_import_table] opcode is 0xFF15xxxxxxxx

The reason why Borland and Microsoft have chosen different approaches is beyond the scope of this article. Coming back to our virus analysis what Virut tries to do is to find 0xE9xxxxxxxx or a 0xFF15xxxx opcode to patch to point to the virus code. That makes the detection and disinfection even harder since what it basically does is to patch a random kernel32.dll call and finding that patched call to repair it makes the disinfection process tricky. The following sniped shows the used code:

Analysis of W32/Virut.ce

Avira GmbH

Page 16 of 25

Analysis of W32/Virut.ce

Avira GmbH

Page 17 of 25

In the last snipped it gets the .text section IMAGE_SECTION_HEADER and subtracts SizeOfRawData from VirtualSize. If this value is lower than the virus stub than just copy that stub at the Entry Point (of course saving the Entry Point before giving control to the original file).

Analysis of W32/Virut.ce

Avira GmbH

Page 18 of 25

There are basically four methods Virut employs to infect a file: 1) Modify the Entry Point (no Entry Point Obscuring)

2) Get a random kernel32.dll call and patch it to point to the virus code within the last section

Analysis of W32/Virut.ce

Avira GmbH

Page 19 of 25

3) Copy a small stub to the end of the .text section and modify the entry point to that code which will decrypt the virus and the will pass control to the decrypted virus code within the last section

4) Get a random kernel32.dll call and patch it to point to the code stub at the end of the .text section

Analysis of W32/Virut.ce

Avira GmbH

Page 20 of 25

IRC and Download File W32/Virut functionality


As we have written above, Virut is not only infecting PE Files, it also offers a IRC Backdoor and Download File functions. First it loads the required API functions used to establish connections to a IRC server and to download files.

The following APIs the call will return:

Analysis of W32/Virut.ce

Avira GmbH

Page 21 of 25

After this first step it then tries to establish a connection to a IRC server. First a socked is created and after the socked is created the connection will be done via HTTP:

In the next code snipped you can see all the addresses, the nickname and the parameters needed for the IRC connection.

If the connection to the IRC server is successful it tries to send IRC parameters in order to inform the server:

Analysis of W32/Virut.ce

Avira GmbH

Page 22 of 25

After this it waits to receive data from the IRC server. This is basically a HTTP link that Virut will use to download some files and run the downloaded files on the local machine.

Now the information has been sent back by the server and Virut has been woken up. What it needs to do is to parse the information from the server. This work is done in parse_irc function which basically checks to see if a HTTP link has been sent. The code looks like:

Analysis of W32/Virut.ce

Avira GmbH

Page 23 of 25

After this it goes to create an internet connection and use that link to download the file from the receive URL and create a thread that will write the file on the disc and create a process using the file as an argument:

Analysis of W32/Virut.ce

Avira GmbH

Page 24 of 25

Last but not least, we found the following strings inside the malware:

Analysis of W32/Virut.ce

You might also like