The era of anti-analysis methods based on simple tricks such as the well-known ‘IsDebuggerPresent’ API and other similar functions mostly belongs to the past. These APIs are still used for simple and quick Ring3 debuggers detection, but malware authors don’t know less than we do. Most of the anti-reversing tricks implemented through straight forward usage of such Windows APIs are generally very easy to bypass even without specific knowledge, with the use of a debugger plugin that will perform the appropriate patches on runtime.
Furthermore, malware authors are mostly interested in bypassing AV scans rather than the analyst himself. If that is achieved before the malware arrives into a lab then the mission has been accomplished. In this article we will be discussing about one of those exotic methods used nowadays to redirect the execution flow in specific code blocks. In our case, this is done by abusing Windows OS defined structures/procedures used by window-management related APIs dedicated to window creation and processing of the incoming messages.
Each window belongs to a windows class that describes the attributes of that window such as its style, icon and a window procedure. The window procedure it is a callback function that processes all the messages sent to a window belonging to a specific window class, so that all windows belonging to that class make use of the same window procedure.
Furthermore, the default window procedure called through the DefWindowProc function it is used in order to provide default processing for window messages that the application does not process.
In order to register a window class the application can call either the RegisterClass or the RegisterClassEx APIs. Both of them receive only one parameter which is a pointer to a WNDCLASS or a WNDCLASSEX structure respectively that contains information related to the window class that will be registered through a subsequent call to one of the two APIs just mentioned.
These two structures have minor differences between them, but what we are mostly interested into it is one of the members that they have in common and that is the lpfnWndProc. This member is a pointer to the function that will be used to process the messages sent to all the different windows belonging to the same window class. These windows are created by a subsequent call to the CreateWindow or CreateWindowEx APIs.
Let’s have a look at this code snippet taken from a malware:
We notice the call to the RegisterClassEx API (Figure 2) and the pointer to the WNDCLASSEX structure passed to it as a parameter (Figure 3).
By examining the contents of the WNDCLASSEX structure we can find the pointer member lpfnWndProc (Figure 4) to the window procedure that will be later triggered once CreateWindowEx API will be called.
This information is very important since the function at address 0x004042FF will be used by the malware to control various operations of its execution flow as we will demonstrate later in this article.
Once the malware has registered its own window class it will then make a call to the CreateWindowEx API in order to finally create the window that belongs to the rogue window class previously registered.
Let’s also take a look at the decoded parameters passed to the CreateWindowEx API:
From the figure above we can notice the window name and the class name of the window that is about to be created. Keep also in mind that when the CreateWindowEx API is going to be called the window procedure will also be triggered for the first time.
Once we enter the window procedure we immediately notice that the value in EAX will be compared to some predefined constant values. This value in EAX represents the message type (Msg) sent initially to the window during creation and later on while the rest of the message processing will start taking place. We are going to see this in detail later. However, it is important to mention that the first time a callback to this function is triggered the Msg will be processed by the DefWindowProc API since the author doesn’t take that first Msg in consideration as well others that are going to follow.
We can notice that the first Msg that was sent is the WM_GETMINMAXINFO, about which the window procedure doesn’t care and for this reason will pass it to the default window procedure for further processing. Two more messages will follow that will have exactly the same luck and these are WM_NCCREATE, and WM_NCCALCSIZE.
The next message that follows is the WM_CREATE and this time the malware will attempt to create a button type window using again the CreateWindowEx API, but using an invalid hMenu handle parameter which will make the API to fail. There will be one more attempt using all valid parameters this time and a window belonging to the ‘Button’ system class will be created. Since this call was successful, also a callback to the window procedure is triggered passing again the message to the DefWindowProc API. It will then follow an attempt to create a window belonging to the ‘edit’ system class (Figure 8) which will also fail due to an invalid window handle parameter.
All the information given until this point is mainly for giving an overview of the messages processing.
The interesting part is just about to start…
A call to a short decryption routine follows (Figure 9). As you can notice it basically uses addition to decrypt a block of data just 20 bytes long.
Remember that first call to the CreateWindowEx API (Figure 2)? The execution will return back to this code block so let’s take a look at it.
We notice that the next API to be called is the ShowWindow one, which also will trigger a callback to the window procedure by sending a WM_SHOWWINDOW message. This message will also be sent to the default window procedure. Keep in mind that we are only interested in those messages processed by the window procedure registered through the RegisterClassEx API.
Until this point we have seen an overview of the window class registration, window creation and the window procedure itself. From this point on things are getting dodgy enough to trigger our interest along with the window procedure.
The previous call to the ShowWindow API triggers a series of messages. The first message that the window procedure is interested into is the WM_SIZE (0×05), which will lead the execution to the code block show in the next figure.
What happens here is quite interesting, also based on what is going to follow. We see that there is a call to the GetWindowRect API which retrieves the dimensions of the specified window based on screen coordinates relative to the upper-left corner of the screen.
Those values are stored in a RECT structure:
By doing some simple math with the coordinates retrieved, an additional message-specific constant is generated that is used as a parameter to the SendMesssage API that will be called afterwards (Figure 13). Remember, this will also trigger a callback to the window procedure.
So let’s see the parameters passed to SendMessage the first time this happens:
As shown in the figure above a WM_COMMAND message will be sent to the main window of the application. We are also quite interested in the message-specific information (will be calling this MSI for brevity) previously generated (0x1F).
Do nothing. Returns to loop shown in Figure 12.
Message sent using as MSI a handle to the button window previously created. In this case the malware will make use of the MoveWindow API in order to change the coordinates of the main window instead.
This will cause a callback that will lead the execution to the code block shown in Figure 13, and as a result another WM_COMMAND message will be sent with a new MSI (0×32) based on the new window coordinates.
The following figure shows the code block used by the window procedure to process messages that match the above criteria.
At first a call will be performed to the decryption routine we already talked about (Figure 9).
We can notice two decrypted strings, “jal” and “VirtualProtect”. Once we return back from the decryption routine, there is another one (0x004047C4 – 0x004047D5) that will also decrypt a short block of data.
By taking a look at Figure 16 we can also notice the next message that will be sent.
In this case, there are two calls to the dynamic APIs importing routines that parse the exports table of kernel32.dll. The two APIs the malware is interested into knowing their addresses are the VirtualProtect and the VirtualAlloc APIs. Notice also the next message that is going to be sent.
This type of message will lead the execution flow into a block that will attempt to reserve a memory block starting at address 0×04000000. If this is successful it will send the next message to the window using WM_COMMAND / MSI: 0×36. If the attempt fails it will send a message using WM_COMMAND / MSI: 0×35. The code block that will process this message will attempt again to reserve a memory block but this time will let the OS to find an available block. So we won’t look more into that.
This message-specific processing routine will finally commit the memory block previously requested and it will then give to it PAGE_EXECUTE_READWRITE access rights. Let’s see what happens when the next message is sent.
The first time we reach the code block responsible for parsing this specific message, nothing interesting will happen. However, the next message that we are going to analyse will be sent.
The first subroutine called through the Call EAX instruction will be used to copy a block of code to the previously allocated memory block (see: WM_COMMAND / MSI: 0×36).
The second subroutine starting at address 0x00403DE8 will apply a XOR based decryption algorithm over the data copied and it will also send a WM_COMMAND / MSI: 0×39 message, before returning back to the caller. So at this point we interrupt the analysis of this subroutine in order to analyse the code processing the next incoming message.
The interesting part of this message processing code block is actually the fact that it will send another message to the application using WM_USER / MSI: 0xB3
This routine mainly does some data transfer, but nothing too important to dig into.
The first JNZ actually created a loop over the SendMessage API call that sends the WM_USER / MSI: 0xB3 that leads to the code block we previously saw in figure 24. All this together creates a nice and complicated decryption loop of which the execution flow travels across messages sent to the main window of the malware.
Going back to the code block shown in figure 22, we see another call to the dynamic imports function (call 0×00405660). The function that this time the malware is interested into is the DestroyWindow, which will then call through the Call EAX instruction and using as a parameter the handle of the main window. This will trigger another callback to the window procedure that will lead into calling the PostQuitMessage API.
Once the execution flow has finished with all the callbacks triggered we finally return to the loop shown in figure 12. This time though we will not loop anymore since the window has now been destroyed.
This will bring the execution into calling the function at address 0x00403DD9 (Figure 26) and from there the execution will RET over the decrypted shellcode written in the allocated memory block.
During this article we analysed a quite complicated and exotic way to control the execution flow by abusing Windows structures and window procedures. The complexity of this highly sophisticated technique brings AV evasion and anti-emulation techniques to a whole new level.
Written by: Kyriakos Economou of Portcullis.
Come and join Portcullis’ own Linkedin group, The Portcullis Arms.