Just like the rest of the world, I’ve been fascinated by the CIA documents released by WikiLeaks (aka Vault 7 release). The more you read about the way CIA operates, the more it feels like there’s little anyone can do.
On a technical level, the CIA has some fascinating abilities. And I’m not just talking about the zero-day weaknesses in about every possible device, but also the trojan capabilities. On several documents, the CIA mentions “Antivirus defeat” - which are a bunch of ways they can bypass personal security software while executing on the victim’s machine. Some of this includes placing the executable in the recycle bin (Comodo defeat) and mutating the executable’s resources so that it passes heuristic check (Avira defeat, F-Secure defeat, BitDefender defeat).
In researching deeper, it has become clear that there are ways to improve on the DLL hijacking methods employed by the CIA in a manner that is more generic and adaptable to different scenarios.
Current State of the Art
It is interesting to examine how CIA trojans startup at boot. I found several documents referring to this, using Group policy startup, services and other methods. But one method seemed to stand out from the rest - using DLL hijacking. The CIA seems to be keen on this method, as they have a list of popular software where they found DLL hijack methods (Fine dining). It may be safe to say they use this method to disguise some data theft operation as a normal operation - this makes sense since the CIA uses operatives.
Consider the following: An operative is in the field, collecting data for an upcoming operation. For instance, the first requirement is finding out what type of phones, wifi routers, or other connectable devices are available at a target organization or with a target person. To complete this, code is written for that scanning operation, and then the operative needs to execute it while undercover. It makes sense that the operative would need some cover on his machine.
For example, they load all of the code into an innocent process, such as a VLC player. Then when VLC starts (by the operative), the code executes, and it hijacks a DLL used by VLC. This method also makes sense for target machines. VLC might already be configured as trusted by the protection software, and since there were no modifications to any file in it, it will still be trusted. A good example is the “Rain maker” module:
“RainMaker v1.0 is a survey and file collection tool built for a FINO QRC operation. IOC/FINO is looking to expand asset-assisted operations. The intended CONOPS involves using an asset to gain access to a target network. The asset has the ability to plug in a personal thumbdrive to the network. In this scenario, the asset will have "downloaded" the portable version of VLC player (2.1.5) and will listen to music during work hours. While she is listening to music, the tool will execute the survey and a prioritized file collection. All collected data will be stored to the root of the removable media it is executing from. When the asset next meets with the case officer, the thumbdrive is retrieved and the collection is processed."
From the WikiLeaks documents, it looks like the CIA uses this method a lot. Also, since the functionality of the hijacked DLL is still needed, they would need to proxy all functions exported by the DLL. This is apparent from the way they describe some of the DLL hijacks they found. For instance in the Opera hijack, they state the DLL is ideal for hijacking, since it only exports one function. This means they would only need to proxy one method.
And so finally I reach my point - DLL proxying can be made easier, if only you could a write a DLL that is generic in what it proxies. If one could write a DLL that proxies any other DLL, it could simply be dropped anywhere (with a specific name, of course), and be loaded. And this is where i think the CIA did not investigate enough - since this can easily be achieved.
A better way - The Generic DLL
The main idea is this: When a process loads a DLL, it will use the LoadLibrary API. This API returns the base address where the DLL was loaded. So when proxying, the process receives the base address of the proxying DLL, and that is why all of the functions from the original DLL need to be exported:
In order to build a generic proxy DLL, one must make sure the base address of the original dll is returned to the loading process. That way, there is no need to proxy anything, and stop being the middleman:
How can this magic happen? It’s actually pretty easy. All that is needed is to walk the stack and find the function call to LoadLibrary, specifically - the return address from it. Then write a different address there that points to this small piece of code that sets the return value and then jumps into ADDR. That’s it. The calling process will receive whatever is set in the return value as the base address.
The code used to swap the return value is really simple, and looks like this:
mov eax, ORIGINAL_BASE_ADDR
Doing it this way gives a few advantages:
- Simplicity - Don’t care about the amount of exported functions
- Robustness - No need to create a different version per-dll hijack method
- Stickiness - Can easily look for DLL hijacking methods, since no versioning is required
To summarize, the CIA does its best to give its operatives a good cover. Still, executing malicious code requires a cover, and DLL hijacking provides a good way to both keep the integrity of the executing software and to execute the malicious code within it. This approach should also work for trojans, which can be dropped on “innocent” machines, and loaded into target processes. Using this method might require proxying the exports of the proxied dll - which can be solved by creating a generic “invisible” DLL.
Preempt Research Team Blog