Unpacking Grey Energy malware (Service Application DLL)
Recently I stumbled upon malware sample which was part of Grey Energy malware campaign targeting Ukraine energy infrastructure. I ran the hash of the file on virutotal and many of the antiviruses tagged it Grey Energy and I tried to do a little more internet research but didn’t find and analysis on it. As there was no post on this sample so I decided to write one.
In the post you will learn the following:
- How to debug Windows Service Application DLL
- Learn how to use a EBFE debugging technique
- Unpacking a DLL binary
- How to dump an unpacked in-memory executable
File hash : 15a6f734ca79efc027000dd12f4d3870ccc9f604517b0e700c05b961659308d1
Using some basic static analysis tool you can know that it’s a 64-bit Windows DLL.
Since it’s a DLL there we need to see the export table. There was only one function that was exported which is ServiceMain. This is the method is usually exported by Windows Service Application DLL. This is the function which is invoked when a request is made to the Windows Service Application.
Checking the Import section you can see the below DLL been imported. But as we see the further analysis, not all the DLL which are imported are in use.
If you know already know about Windows Services then I would advise you to skip this section. I will describe all the necessary stuff about Windows Service from malware authors perspective, but if you are interested to know more about it then you can refer to links in the reference section at the end of this post.
Windows Service Application is to create long-running background application which you can start automatically when the system boot/reboot and it doesn’t have any user interface. Services can be put in the various state like start, stop, paused, resume and restarted, all this is managed by Windows Service Controller(services.exe). These features make it ideal for use as malware which does all its working in the background and its also long running starts on reboot. Actual use cases of Services are like Web Server service, logging machine performance metric like CPU, RAM etc. Service executable can be a DLL program with a defined entry point.
A service may be written to run as either a stand-alone process or as a part of the Service Control Manager’s(svchost.exe) process (which creates a thread per service, and the service is allowed to create more threads). If the service runs in SC, the SC creates the thread for a service then loads its DLL, and calls the Service entry points to move the service through its states (first start, then eventually stop). Since creating a thread from the svchost.exe process(a system service) giving it system privileges which can be dangerous, but you can run the DLL in the specific security context of the user account that can be different from logged-on user.
To create a Service DLL you need to satisfy specific requirement which is as follows :
- Main Entry point: this is required to register your service by calling StartServiceCtrlDispatcher this will be the DLL entry point.
- Service Entry point: which is ServiceMain in the DLL export entry, task to this function is as following tasks:
- Initialize any necessary items which we deferred from the DLL Entry Point.
Register the service control handler which will handle Service Stop, Pause, Continue, Shutdown, etc control commands.
- Set Service Status to SERVICE_PENDING than to SERVICE_RUNNING. Set status to SERVICE_STOPPED on any errors and on exit.
- Perform startup tasks. Like creating threads/events/mutex/IPCs/etc.
- Initialize any necessary items which we deferred from the DLL Entry Point.
- Service Control Handler: The Service Control Handler was registered in your ServiceMain Entry point. Each service must have a handler to handle control requests from the SCM. This handler will be called in the context of the SCM and will hold the SCM until it returns from the handler. Service Handler is called on various events like start, stop, paused etc which is passed as the parameter to the handler function.
We start with doing static analysis on the DllEntry point this might be the first function which might get executed even before ServiceMain. Below is the disassembly of the DllEntry point.
Looking at the disassembly further there was some memory allocation and manipulating of that memory. There was another interesting function which is found was at address 0x2c0202bc, this function was called after allocation of memory which seems to be like a decryptor function, or at least preparing for so decryption. Below is the disassembly of this function.
As there are a couple of XOR operations whose value is picked from register rsp+0x68 and after some manipulation data is written to [rbx+rsi*2] translate to the same address. We can verify this in dynamic analysis. I am at this point little suspicious that the executable is packed as not many functions were recognized by both IDA and radare2 analysis.
Let us have look at the disassembly of the ServiceMain.
These instruction doesn’t seem to make any sense. This further confirms our doubt of packed executable. We can use radare2 entropy calculation function to check the entropy if each segment in the execute. If there is any segment with high entropy then it means that section holds the encrypted data. We can use radare2 iS entropy command to calculate the entropy of each segment, below is the result of the command.
As you can clearly see that .text segment has very high entropy compared to other segments. This confirms our suspicious of packed executable. In the next sections, we will try to setups debugging environment for Service Application as it is not as straight forward as other windows application and extract the unpacked executable using dynamic analysis.
If this would have been a normal DLL we could just used Immunity debugger to do debugging but Service Application DLL is different as they have to register themselves and declare their state as running within first few seconds of execution, and also before running the main entry point the Service Control Manager(SCM) should be aware that the Service is going to run and the DLL runs only in the context of the SCM.
So the challenge is that we cannot get hold of the DLL entry point with ad debugger. We could overcome this limitation if we could manage to pause the execution of the DLL entry point when the SCM run the DLL.
After doing some research I came across a technique called EBFE, you can read more about on this link. In this technique, we insert an infinite loop at the point we want to insert the breakpoint, once the thread executes this instruction it puts it in an infinite loop. EBFE is a jump instruction code which points to itself, this will put the executing thread in an infinite loop and then we all the time in the world to attach the debugger to the process and start debugging the process.
Next question is how will we know which subprocess spawned by SCM should we attach the debugger to? It’s actually very simple, once the CPU executes the infinite loop instruction the CPU consumption value will rise to very high-value something like 90-100%. We can use process explorer one of the System Internal tools to get the process ID of the process.
As you can see in the image above once the CPU executes EBFE instruction it goes in an infinite loop which increases the CPU consumption to 95-100% which is the indicator that our process is ready to be attached.
Now that we have figured out how to attach the debugger to Service Application, next thing is we have to place this instruction at a point which will get executed which is the entry point of the DLL. There are two points of interest at which we are can place EBFE are, ServiceMain(Service entry point) and DllEntry (DLL entry point). We will place this EBFE instruction on both of these functions. Before replacing the two-byte instruction you will have to take note of the original two bytes which you are replacing. Once the hit the infinite loop we will replace it with the original bytes and continue debugging.
Let us start with analyzing DllEntry point since out of those two functions only this function had some sensible code.
First, the memory is allocated for the size of the original executable, the way it allocates the memory is something weird, it specifies the base address of memory block it wants to allocate, if it fails then it iterates from 100000h at the interval of 10000h tries to allocate the memory. We will have to note down this address as the unpacked executable will be on this address.
then it changes the memory permission of the allocated memory and copies each segment (.text, .rdata, ) to newly allocated memory.
then it patches the current DLL entry point with the DllEntry point function in unpacked code. Before patching the memory address it changes the memory permission to writable then restore it back to Read and Execute.
It then iterates the Import Address Table(IAT) of the unpacked DLL and it loads the DLL present in the IAT and resolves the imported functions and patches it in the table.
this is the stage at with code is unpacked and the IAT is resolved next the code jump to the original DllEntry point for execution.
The memory address which we noted earlier in the address at which the executable is unpacked as you can see in the dump below.
We will use Scylla plugin which built-in in X64-dbg to dump the executable. You will have to specify the base address of the executable and the size of memory you want to use to recover the PE which you can see from the memory panel next to the address column and size of the debugger which is 23000 in our case and click the dump PE to save the executable file.
Unpacked binary basic information is as shown below
Import section of the unpacked binary
Some more of the import section which shows binary uses HTTP for communication with the C&C
We can see the registering of the service in ServiceMain function by calling RegisterServiceCtrlHandleW and SetServiceStatus, that means we can be sure it was indeed as Service Application.
We managed to unpack the Service Application DLL, this packer was specially designed DLLs was we observed the unpacking of the binary as then patching of the DllEntry point to the original code. It was not a special anti-debug technique used in unpacking which made it very trivial which good to learn for a beginner. We also learnt how to dump in-memory binary along the way.