SpyEye is a malware family which we are monitoring for some time. Today we are analyzing a sample which is detected as TR/Spy.SpyEye.flh by Avira products.
The Trojan is able to inject code in running processes and can perform the following functions:
- Capture network traffic
- Send and receive network packets in order to bypass application firewalls
- Hide and prevent access to the startup registry entry
- Hide and prevent access to the binary code
- Hide the own process on injected processes
- Steal information from Internet Explorer and Mozilla Firefox
A detailed analysis of this malware by Liviu Serban, Virus Researcher at Avira.
The sample we are analyzing is packed using the UPX runtime packer. After the file has been unpacked it runs a polymorphic decryptor. The runtime packer contains a lot of redundant calls until it gets to the actual decryption code.
The Trojan makes use of user mode rootkit techniques to hide both, its registry key located inside HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Current Version\Run and the folder containing the Trojan executable and the configuration file config.bin. The folder is usually located in the root directory of the drive where the operating system is located.
The following API functions are hooked by the Trojan within the winlogon.exe virtual address space:
After execution the Trojan connects to a server and sends some information about the system to the server like:
- MD5 of the executed sample
- Operating System version
- Computer name
- Internet Explorer Version
- Version number of the malware
In the next picture you can see how the injected code communicates with the malicious server:
You can see in this picture that the malware has injected a piece of code within winlogon.exe virtual address space. That code then establishes connections to some servers. One of the actions is to download an updated version of the malware.
Decryption process and polymorphism
As written before, the malware is packed with UPX and a polymorphic decryptor.
In the code snippet above you can see a call to another routine after the end of the usual UPX decryption: call sub_42F851. Looking at the routine we will see something like:
So in a nutshell the whole polymorphic decryption code looks something like this:
Before arriving at the actual decryption code you need to follow dozens of garbage functions just like those ones presented above. The whole code is basically a back and forth between these functions. They are used to make debugging the malware more confusing to the Virus Researchers.
Finally after a dozen calls or more we get to the point where the malware is decrypted. The code looks very confusing because of added junk instructions:
Hooking and Injection process
The Trojan will first call a function that will hook several APIs in ntdll.dll and other DLLs like wininet.dll, ws2_32.dll, advapi32.dll and crypt32.dll. As you can see from the snippet bellow it will create a call function that will hook APIs in ntdll first. After this is done, it’ll hook into the rest of the DLLs and then it will create a thread. This thread will create some mutex on the system, some registry keys and then will try to create remote threads in the rest of the processes.
First let’s take a look at how the APIs are obtained and hooked:
The code first tries to load the library in which it wants to hook the APIs. Then it starts searching the desired APIs addresses in that DLL and hooks them: After a particular DLL has been loaded in the virtual address space it goes and calls hook_apis_dll_name functions. Let’s now look at a snippet from the function that searches for API addresses and hooks them:
It first calls the function get_api by passing the API name and the base address of the DLL in which the API resides. With the resulting address it calls a function hook_routine and then jumps back to do the same thing for the next API until there are no more APIs to hook in that DLL.
The next snippet shows how the sample gets the address of an API based on the API name which is done in get_api function.
This function receives the base address of the DLL and a string pointer which contains the API name. The first thing the malware does is to get to the IMAGE_EXPORT_DIRECTORY of the DLL. From there the malware will get the AddressOfNames, AddressOfFunctions and NumberOfNames arrays. The malware will loop through the AddressOfNames array and at each step will get the RVA of an API name, convert it to a virtual address and then do a strcmp with the string passed as parameter. If a string matches it will get the NameOrdinal of that API name and will use that to get the address of the API from the AddressOfFunctions array. If it won’t match it goes to the next step and will loop until there are no more names in AddressOfNames.
For a clear understanding of this algorithm you need to keep the IMAGE_EXPORT_DIRECTORY image in mind:
After the code has the address of the desired API it hooks it by calling hook_routine function. The algorithm inside this function is fairly simple: It writes a jump at the API address to a label that is 5 bytes ahead. At this label it writes another jump to the new routine.
This is how every System Service kernel entry should look like:
And this is how it will look like after the Trojan hook has been applied:
You see that a jump has been written instead of the classic “move eax, SSDT_Index/move edx, offset KiFastSystemCall”. This jump (inline_jump) points a couple of bytes ahead and from there the code will finally jump to the Trojan code. This is done to trick antivirus software which typically will look at the system services for jumps to suspicious code. In this case the first jump doesn’t point to the suspicious code.
After this hooking process is completed the Trojan creates a thread. The logic for this thread creation inside the Trojan is very simple: It tries to open a mutex, and if this fails, the mutex obviously hasn’t been created yet – and the code creates a new mutex. The fact that the mutex doesn’t exist shows that the Trojan is running for the first time. When the thread is running, it creates registry keys and injects the malicious code in all running processes by creating remote threads inside them.
The whole thing is done in a loop so the registry key is created every time the thread runs. This will hinder deleting the registry key by security software. The same technique is used for API hooks and remote thread creation.
In the last code snippet you can see a call to infected_trojan_code. This function creates some registry keys and starts to inject code in running processes:
The code is not injected inside System Process/System Idle Process, smss.exe, crss.exe, services.exe and the current process of the Trojan itself.
What write_trojan_thread_code_in_remote_process does is very simple. It gets some code from the Trojan (for example Current Process) and copies it into a section object that is backed by the paging file and then maps the section object into this remote process and returns an address that will be used as the startup address for the future remote thread.
APIs hooked by the Trojan
As the Trojan injects code into any currently running system processes it is able to perform a lot of actions with the hooked APIs such as capture network traffic, send and receive network packets, hide own process and so on. We’ll have a look at those hooked API functions in order to see what the Trojan is doing.
To understand the behavior we will analyze the ring3/ring0 calls and will start to look at the regular NtEnumerateValueKey under Windows NT before the Trojan hooks the function.
In EAX the SSDT index is stored and in EDX a pointer to a function is stored. After this the actual jump is executed. The KiFastSystemCall function pointer looks like:
It is just a sysenter x86 instruction that will make an change from ring3 to ring0. The jump will look like:
It just calls a function via a pointer in EDX. Actually in EDX is the function pointer to do the sysenter call.
Analysis of injected code in remote processes
A look at NtEnumerateValueKey after the Trojan hooked it shows that instead of the classic entry to ring0, we see the following code:
The Trojan has inserted a jump instead of the classic sysenter call. In order to better understand what the Trojan code does we need to understand what the actual API does. In the case of NtEnumerateValueKey, the function is simple. The API will get information about the value entries of an open key.
The prototype looks like:
NtEnumerateValueKey( IN HANDLE KeyHandle, IN ULONG Index, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformation, OUT PVOID KeyValueInformation, IN ULONG Length, OUT PULONG ResultLength );
You give the function a key handle and this function will get the values for this specific key. This function is hooked by the malware in order to hide some values – by filtering them in the output – that it adds to the registry in particular a start-up value added to HKLM\Software\Microsoft\Windows\CurrentVersion\Run.
This analysis is also available as download here (PDF).