Malware that steals banking credentials is still one of today’s most lucrative cybercrime schemes. It’s not unusual for a banking Trojan to evolve over the years, and Ramnit is a perfect example. It was active for several years until it was disrupted in early 2015 by Europol working with several tech companies. It resurfaced in late 2015, and again in mid-2016.
I was surprised by this behavior because the challenge for investigating malware usually lies in fetching the configuration from the C&C server. Typically, after the configuration is fetched, it is stored on the infected machine until an update is due. However, based on user data sent from the Trojan, the C&C server might decide not to fetch the configuration for a variety of reasons (for example, because it’s running on a virtual machine). In any case, it is unusual for the configuration to be fetched and then deleted.
Could this behavior of deleting the configuration mean that Ramnit is now adding more complexity to make it more difficult to detect during execution? Or, could this indicate a bug in the malware functionality?
Whatever the reason might be, I didn’t want to theorize before having complete data. I had to find a way to preserve the configuration data to continue my web inject research. Before I could do that, I had to understand the exact flow of the configuration data within the Ramnit processes and modules and find out which process was responsible for deleting the configuration.
During its execution, Ramnit creates and injects its modules into several processes:
- Svchost.exe #1
- Svchost.exe #2
- Browser processes
Investigating the Browser Process
I started by checking how the configuration finds its way to the browser’s memory. The module that is responsible for Ramnit’s webinject capability is hooker.dll. This module is originally injected into explorer.exe, and when the browser is launched, the module is propagated into the browser’s memory by copying its own code from explorer.exe’s memory.
The propagation method that hooker.dll uses is as follows:
- Generally, whenever a new process is created, the (Zw/Nt)ResumeThread API is eventually called to run a first thread.
- The hooker.dll module within explorer.exe hooks the ZwResumeThread API and uses it to inject code into newly created processes.
Figure 1: The hooker.dll function responsible for hooking ZwResumeThread
Once hooker.dll is unpacked in the browser’s memory, it tries to map the configuration data into the browser’s memory from shared memory sections. This is done using a dedicated worker thread:
Figure 2: The hooker.dll thread for mapping data from shared memory
3. The Ramnit configuration consists of the following parts:
- DNSChanger: Ramnit hooks the DnsQuery API, and replaces the resolved IP addresses of targeted domains, with new IP addresses.
- WebFilters: a list of targeted URL patterns that should be monitored by Ramnit. Any POST request to a URL that matches one of these patterns will be captured and forwarded to the C&C server.
Each configuration part has its own shared memory section, which is named in the following format:
The worker thread continues its execution regardless of whether the configuration is present in the shared memory section. There is only one flow for both cases.
The only interaction the browser’s process has with the configuration data in the shared memory is a read operation. This led me to the conclusion that the browser process is not the one responsible for removing the configuration. So, I continued the search for another process that is responsible.
Even though the explorer.exe process is the one that I immediately suspected, a quick check revealed that it does not interact with shared memory, meaning it cannot be the process I was looking for.
Svchost.exe #1 and svchsot.exe #2?
Ramnit’s execution flow creates two svchost.exe processes:
- Svchost.exe #1. Hosts rmnsoft.dll, a module that is responsible for the direct communication with the C&C server, receives modules, configurations, and commands.
- Svchost.exe #2. Hosts modules.dll is dedicated for loading other modules and command execution.
Rmnsoft.dll uses pipe communication to relay C&C commands to modules.dll.
Figure 5: rmnsoft.dll function for communicating with the C&C server and with modules.dll
Inspecting the processing flow of data that modules.dll receives from the pipe communication reveal the actions that are taken by the module once receiving the configuration data:
- Modules.dll stores the encrypted configurations on the disk in the %localappdata% path as txt files.
Figure 6: Configurations on the disk
2. Modules.dll encrypts (crc32+XOR) and writes the configuration into the shared memory. The configuration struct in the shared memory has the following fields:
- conf ptr
Figure 7: Webinjects configuration struct fields
So, now it is evident that mapping the configuration data into shared memory happens constantly following a pipe conversation between modules.dll and rmnsoft.dll, and it does not depend on a specific event occurring (such as opening of a browser). This allows Ramnit to constantly change and update its configuration from the C&C server.
But, despite the fact that the writing access to the shared memory occurs in modules.dll, while inspecting all of the writing occurrences within modules.dll, I found that the configuration was never deleted there.
So, I needed to inspect other modules that access the shared memory. The footprints once again lead to the “hooker.dll” module, but now it is an additional instance inside the svchost.exe process where modules.dll resides with other Ramnit modules.
During its communication with the C&C server, rmnsoft.dll receives additional modules and delivers them to modules.dll through the pipe communication. Then, modules.dll maps the received modules to the memory of the svchost.exe process.
Each module (vncinstall.dll, bond.dll, cookie.dll, hooker.dll, etc.) has its own field of responsibility that is activated by exported functions.
Figure 8: Modules inside svchost process
Modules.dll receives commands through the pipe and calls the exported functions accordingly.
Figure 9: modules.dll receives commands through the pipe and calls one of the exported functions
During the inspection, I found that CommandRoutine, which is one of hooker.dll’s exported functions, tries to access the configuration in the shared memory mapping.
Figure 10: Webinjects configuration removal inside CommandRoutine
CommandRoutine receives a struct with command data and a handle to a pipe. In the flow that I inspected, CommandRoutine was called four times:
- First: the configuration was not modified, only pipe communication occurred
- Second: the dnschanger configuration was removed
- Third: the webinjects configuration was removed
- Fourth: the webfilters configuration was removed
Finally, I had found the guilty function!
CommandRoutine Configuration Removal Steps
- Overwrites the content of the configuration data inside the Shared Memory section with 2 bytes of encrypted, meaningless data
- Overwrites the configuration size parameter in the structure to 0x2
- Deletes the configuration data from the disk
Example of the webinjects configuration removal routine:
Figure 11: Webinjects configuration removal inside CommandRoutine
So, the next time the browser tries to map a copy of the shared memory into its own memory (which holds the configuration), it receives the config struct which has a valid field structure, but with 2-byte data length instead of the original config length and without any configuration data:
Figure 12: Configuration fields after removal
Now the injection to the targeted web pages will not occur anymore. Mystery solved!
Figure 13 illustrates the complete configuration data flow within the Ramnit modules.
Figure 13: The configuration data flow within the Ramnit modules
My main goal in this investigation was to preserve Ramnit’s configuration data so I could analyze it’s webinject content. Since the configuration was deleted from the memory I had to find out the exact flow that processes the removal and the reason for it. After investigating a number of Ramnit’s processes and finding the function responsible for removing the configuration, it was possible for me to bypass this flow and preserve the data.
It seems that the actual decision as to why to remove the configuration is done on the C&C server and not by a logic in Ramnit’s processes. It is definitely a conscious decision designed to make the malware more difficult to investigate, and not a bug in the malware’s functionality.
Sampled MD5: eeefe08b66f68b3ab10ca1c8ae3840cc