Earlier in this year, I published research of the rootkit that belong to famous state-sponsored cybergroup called “Equation Group”. Analyzed rootkit actually represents one of the Windows kernel mode network implant, which has been used by cybergroup as a network traffic sniffer on NDIS level. As we know from comprehensive research of Kaspersky Lab, Equation Group has an arsenal of various sophisticated malware, such as EQUATIONDRUG, DOUBLEFANTASY, TRIPLEFANTASY, GRAYFISH, etc. This arsenal of malware is pretty complex and sufficient for performing cyberattacks that allegedly have state-sponsored origins (NSA). As we know, not only Equation Group leverages kernel mode rootkits, for example, Sednit (APT28, Fancy Bear, Pawn Storm) and Strider cybergroups also resort to the same.
Unlike other malware families of Equation Group, GRAYFISH has on board Windows kernel rootkit for performing malicious operations in high privileged Ring 0 mode. Moreover, like other state-sponsored rootkits that were mentioned previously in my blog, GrayFish (or Trojan.Win32.GrayFish.b as Kaspersky called it) is pretty interesting for the analysis. As we can see from previous instances of such malware, their authors can choose non standard ways for rootkit development.
Typically, malware from cyberespionage platforms leverage kernel mode rootkits to achieve following advantages.
- Independent from user mode context method of files hiding, for example, with help of legacy FS filter (Stuxnet).
- Universal method of code injection based on Windows kernel callbacks (Stuxnet, EquationDrug). Also code injection into trusted Windows processes for masking malicious activity (Finfisher, EquationDrug).
- Execution of necessary user mode code directly in kernel mode (Remsec).
- To bypass Windows x64 kernel mode restrictions (DSE) with bootkit component (Sednit, GrayFish).
- To listen network traffic directly from physical network adapter (EquationDrug).
- To bypass FS/disk level sandboxes as well as other restrictions into a system with security products (Wingbird).
I found rootkit file in resource section of another module (DLL) that is also a part of GrayFish cyberespionage platform. Below you can see compilation date of this DLL. The driver is stored into resource section in non-encrypted state and can be dumped from section with help of Resource Hacker tool.
Despite DLL stores the rootkit file, it doesn’t load him into memory. I suppose that driver loader is located in another GrayFish module. However, code inside the library communicates with driver via DeviceIoControl API. The rootkit supports various IOCTL codes for performing necessary operations.
The rootkit has the following properties.
- It creates unnamed device object, but registers IRP dispatch functions.
- It dispatches IOCTL requests.
- It specializes in run-time patching of Windows kernel code.
- It has huge driver size (153 600 bytes).
- It сontains an inarticulate logic of work, which means that it developed for targeting on one specific goal, but later was modified for another.
In this way, if you try to load the rootkit manually, you will get BSOD or get the absence of any activity.
On first step of initialization, the rootkit builds its own buffer of NT kernel exports and its hashes in following format: +0 FuncHash; +4 FuncAddr. It contains internal function for extracting specific item (function address) from this table by hash of function (NT export) name.
The rootkit also retrieves pointers to dynamic imports in the following way. It uses functions hal!HalAllocateCommonBuffer or nt!MmIsAddressValid for retrieving start address of hal.dll (HAL) or ntoskrnl (NT). Name of both functions are encrypted into its body and are decrypted on stack.
Next imports the rootkit tries to get during initialization phase (hash -> API).
As we know, Equation Group is known as professional in cryptography, their malware from cyberespionage platform leverage various crypto methods and algorithms that we haven’t seen before in such scale. Looks like their love of encryption covers and kernel mode component too. The rootkit stores sensitive strings in encrypted state and doesn’t decrypt it inside loaded in memory image, instead it copies necessary data on stack and decrypts it. Before exiting the function, it encrypts string on stack again.
After got address of HalAllocateCommonBuffer (or MmIsAddressValid), the rootkit tries to find start address of hal.dll for further retrieving addresses of dynamic imports. Interesting to see that pointers to HAL or NT functions the rootkit stores in memory in encrypted state, as shown above (it XORed value of each ptr with its offset). Same situation with NT imports, all stored into rootkit image as encrypted.
The rootkit uses some sort of code and data obfuscation, although stores imports of kernel API in the clear state (PE IAT). For masking its activity from researchers eyes, the rootkit creates new driver object with name Drivermsvss, so after exiting from DriverEntry, original Windows kernel DriverObject will contain no information about created DeviceObject of rootkit as well as about its IRP_MJ handlers.
This method of hiding real DriverObject was used by Remsec rootkit authors. My part 2 of Remsec driver research contains information about this technique. The rootkit calls ObCreateObject for creating new DriverObject, ObInsertObject to create handle and ObMakeTemporaryObject for removing name of the object from its parent object manager directory Driver (hiding from researchers eyes).
In my case the rootkit choose Drivermountmgr.
During new driver object initialization, the rootkit copies some fields from Drivermountmgr into newly created DriverObject. It also copies value of DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] of MountMgr into IRP_MJ handlers of the new driver. Later, it rewrites these handler with pointer to one dispatch function.
Next step of the rootkit execution is really interesting. It tries to get handle (FileObject) on its own device object calling IRP_MJ_CREATE handler directly with IoCallDriver. But before doing this, it creates handle to reserved system device object DeviceNULL that belong to driver DriverNull. Further, it hijacks DeviceObject field into Null FileObject on rootkit device object and uses this FileObject for sending IRP_MJ_Create request.
- As mentioned above, the rootkit builds table of ntoskrnl exports that stores pointers to functions and hashes of names. Strange thing is that the rootkit uses this table only one time during dispatching IOCTL request.
- As mentioned above, the rootkit has function for retrieving ntoskrnl API by its function name hash. It also uses obfuscation of pointers to these functions. Another strange thing is that it uses this method only in specific code pieces, like it was written by one person and recently was ignored by another.
- It is unclear how user mode code connects to rootkit for sending IOCTL, because rootkit’s device object is unnamed.