Moker, Part 1: Dissecting a New APT Under the Microscope
Recently, we came across Moker, an advanced malware residing in a sensitive network of a customer. Since the malware did not try to access an external server, but rather tamper with the system inner workings, we decided to give this malware a second look. (This kind of work is part of developing complete endpoint security software.)
Indeed, we found that there is more to this malware than meets the eye.
First, it was obvious that the malware authors placed many anti-research measures, beyond those of the so-called usual anti-debugging techniques.
Second, once we started analyzing the malware itself, we were also able to analyze its capabilities and the advanced techniques it uses to remain stealthy, hook itself into the operating system, and its sophisticated inter-process communication.
We decided to call this malware Moker as it’s the file description that the malware author gave to the malware’s executable file.
In this first of a two-part post we’ll present the challenges that Moker placed in front of researchers to avoid detection and anti-dissection; and show how we overcame these measures one-by-one until we arrived at the stripped-down malware sample.
In an upcoming second blog entry, we’ll present the comprehensive list and different advanced techniques that Moker utilized. Since we’re still analyzing the malware, we’ll present the technical details within the next few days.
Challenge #1: initial anti-debugging and unpacking
We run the malware inside our virtual environment to first understand what type of executable we are looking at. In fact, we are able to recognize that the malware (or at least its packer), is a Visual 5 or 6 binary:
Understanding the type of binary, we run the sample inside the appropriate debugger but very quickly the program crashes on Access Violation.
The malware somehow knows that it is running inside the context of a debugger and jumps to some junk code.
The next step is to look for the appropriate debugger state flag – the PEB!BeingDebugged flag.
The corresponding byte is in the Process Environment Block (PEB). The byte is read by the API IsDebuggerPresent, and can be read manually by accessing:
Since this byte has no other meaning apart from the debug status, we are able to safely reset it to zero.
Run again. Crash again. On a different address this time.
Our packer has another anti-debugging trick up its sleeve. This time it turns out to be a slightly less common method (though still in use): the use of PEB!NtGlobalFlags. Its corresponding DWORD can be read using an API, or by directly accessing this address:
Reset the DWORD to zero. Run. No crash this time. However, the process terminated.
This fact alone means little. Anti-debugging can still be present and the process could have called ExitProcess or TerminateProcess before it does what it is designed to do.
In this specific case, however, anti-debugging is defeated.
Challenge #2: Process Hollowing
Beginning to understand what the process is doing, let’s set breakpoints at some interesting APIs, one of these being process creation.
Sure enough, a breakpoint at CreateProcessW is hit.
As indicated by the code above, the Moker sample tries to run its own executable without arguments, and with the CREATE_SUSPENDED flag. This means that when the call returns, a new process will be created in a suspended state. The process will remain suspended until killed or until one of its process’ threads is resumed.
Continuing to run Moker, we see that on the created process at its base address (0x400000) the sample uses UnmapViewOfSection and MapViewOfSection. It then calls NtResumeThread, but let’s wait with that one for now.
As we can see, at this stage we have a process running, but its code is not the original code in the file. In fact, the sample completely overwrites the new process’ PE header, giving it a new entry point and a whole section of new code.
Challenge #3: Planned exceptions, or anti-debugging revisited
Before resuming the process and letting it run, let’s create a dump in order to analyze it.
Dump. Fix sections.
As a first, we need to look at the import table to get a general idea about our unpacking status.
Since the import table seems normal, we can open it with IDA.
When we open the dumped code in IDA, we see something strange. IDA finds the start address and parses the code, but the code cannot run very far as it attempts to run “in al,dx“ at 4CEA08 – a privileged instruction. Since this is a user-mode program, it cannot natively run this instruction without generating an exception.
The only thing we can run is the call prior to “in al,dx” – sub_4CEC99. What’s in that call? A small function that registers a Vectored Exception Handler. IDA has already identified that and named a “Handler” function on the list.
At this stage, when trying to step through the program with a debugger, the program attempts to execute the privileged instruction and an exception is raised. When we return from the exception Handler, the program calls NtContinue and the debugger loses track of the program.
This is an interesting anti-debugging technique that our new in-memory module uses.
It was time to investigate that Handler.
We found out that the Handler reads the byte at the address where the exception occuredand then enters a state machine.
This set of rules reads one or more bytes further, depending on the first byte’s value, then alters the CONTEXT fields of the thread in order to simulate a call instruction.
A return address will also be inserted to the stack – to the precise location where our special opcode ends.
The rules are:
- E4 <byte> – Call a Windows API from the array of API addresses by index <byte>.
- ED <word> – Call a local function by offset Base+<word>
- EC <word> – Call a specific function with an offset Base+<word> as a parameter.
This allows us to find system calls and local functions. This is enough to figure out the intentions of this binary but the analysis cannot be complete without knowing what the EC “call” does.
Challenge #4: Decrypted code
The EC opcode throws an exception to the Handler, as expected. The Handler then changes _eip in the CONTEXT struct of the thread to make the program jump to a function with an offset as a parameter.
The data at this offset does not look useful at its raw form.
Now that we know where the function is, there is no problem running it with a debugger and letting it decrypt the data blob into code and jump to it. However, the algorithm was simple enough to write a decoder script for it.
Finally, we were able to decode the whole program.
We use IDA’s structs and enums to make the exception-handler-calls more readable:
Challenge #5: Process injection
As usual, the malware searches through processes, with known APIs and injects itself into Explorer.exe as well as to the following three typical Windows’ background processes:
The injected thread tries to load a library using LoadLibraryW with a file inside the user’s temp folder, the name is similar to this:
Notice the “.” at the end. Naming a file as anything that ends with a dot causes it to be hidden in Windows Explorer. This is done to prevent users from finding this file by listing its folder’s contents.
Challenge #6: Elevation of privileges
To recall, in Windows, some system operations are only available to programs that request elevation. Requesting elevation requires Administrator rights and also pops up the User Account Control (UAC) mechanism that asks the user for permissions to elevate (a.k.a “Allow this program to make changes to this computer?”).
How was Moker able to ensure that it gains system-privileges, without requiring the user’s consent?
- Leeches on to an elevated program. In order to enable proper functioning of the Windows system, there are exceptional programs that are always granted elevation permission – without a user prompt. One of these exceptional processes that Moker found is the Microsoft System Preparation Tool that resides in C:\Windows\system32\sysprep.
- Elevates the privilege of a DLL. There is a Windows design vulnerability which enables loading unauthorized DLLs by authorized applications. This vulnerability is found in the way Windows loads DLLs upon request. When an application loads a DLL by its name, Windows first looks through the application’s current folder, and then proceeds to search at system directories (and other paths). In order to avoid a predicted chaos using this technique, some DLLs are always loaded from the system directory regardless of any other same named DLLs found in its own path. Monitoring sysprep shows it loading one DLL which does not follow this restriction: ActionQueue.dll.
Putting it all together, Moker writes a file named “ActionQueue.dll” into the “sysprep” directory and then runs sysprep so that the DLL is able to run with elevated privileges.
Challenge #7: Downloading the payload
We have skipped another part of the story where Moker loaded itself into the sysprep process and injects itself into other processes. That actually happened earlier (challenge #5).
By analyzing the running code, we realize that we actually have a downloader in our hands.
The downloader itself uses one of its injected threads to communicate with some unknown server. Interestingly, at the time of analysis, the address for the server was empty. This could suggest that:
- The executable was changed since it was first installed
- The payload is loaded in different ways, not only via the network
- There is another layer of protection protecting specifically that part of information
At this point let’s try to emulate a server response, just to see its program flow.
It uses InternetReadFile, reads the response to a buffer, and saves it to the registry as-is.
This leads us to understand that the payload is in the registry.
Setting a breakpoint at RegQueryValueEx takes us the next step.
At this stage the program reads the registry value, manipulates it (decrypts it), validates that it contains a valid PE header (“MZ”, “PE”), and then loads it as a library.
Extracting the registry value from the infected machine and feeding it to the decryption code results in a valid DLL with relatively readable code.
Moker is finally installed, without any external connections.
Coming Up: analyzing Moker’s capabilities
As this stage, we are ready to look under the hood of Moker.
A first look reveals that Moker features RAT capabilities, a few different techniques to obfuscate strings, a rather sophisticated inter-process communication and synchronization between its components (including the downloader from previous parts).
A distinct feature is its ability to start the Remote Desktop service and allow external access to the machine using Remote Desktop clients (like Windows client or Linux’ ‘rdesktop’).
Since we’re still analyzing the malware, we’ll present the technical details within the next few days. In the meanwhile, you can read a high-level overview of Moker’s capabilities.
This is the sort of expertise you get with enSilo’s endpoint security software.
Check us out today!