It’s been a long time since my last post, but im back to bring you an interesting analysis of a malware delivered to multiple targets in Colombia, mostly used to steal money from bank accounts but with some interesting capabilities.

The analyzed sample was found in app.any.run and its named “COMPARENDO N__ 74987 LUGAR FECHA Y HORA”, a common title for phishing emails delivered with malware such as njrat, described in my last post. What caught my attention was that this sample did not seem to make too many actions as njrat, but rather seem to be injecting WerFault.exe and adding some COM objects to make persistency, so i decided to take a closer look and found some interesting things. Let’s begin by analysing the output from app.any.run

Dynamic Analysis:

The first thing to look at is that this malware only seem to be running 3 process, the initial process “COMPARENDO N__ 74987 LUGAR FECHA Y HORA.exe” which later spawns a child process “WerFault.exe” and a COM++ Object that create/modify a file.

process tree

The initial file is marked as malicious with a 100 out of 100 score yet no suspicious events such as connections to C&C are made. But looking at the path of WerFault.exe, that indeed is the one making connections to the C&C server, is a legit Windows tool started from System32 directory so we know for sure that COMPARENDO N__ 74987 LUGAR FECHA Y HORA.exe is doing some sort of process hollowing or process injection technique.

Another interesting thing about COMPARENDO N__ 74987 LUGAR FECHA Y HORA.exe process is that the only action been recorded by app.any.run analysis is the creation and modification of a file named Liebert.bmp but it shows as “not available” and no further details about this file can seem to be found.

liebert.bmp info

If we switch from the friendly event interface to the raw one toggling the slider, we can search for “Liebert.bmp” events and find 4 events that confirm the file its been created, write some data into it, read again and finally closed. But how comes app.any.run has not been able to read the content if some data has been written into it?. We will see later what the malware is really doing to “protect” its resources in order to avoid detection and making app.any.run unable to see the content of this file.

liebert.bmp events

Finally the COM process is creating the file Licensee.exe at the startup location to grant persistency. Licensee.exe is just a copy of the original file COMPARENDO N__ 74987 LUGAR FECHA Y HORA.exe as they both share the same sha1 hash 98190cef26809c35ab8a94acfdd59e66ed0d7814

com events

Local Static - Dynamic Analysis:

As explained in my last post I usually begin the analysis by checking the file with EXEInfo PE, after running the tool we find out its not packed and its a C++ compiled executable, so we can proceed to check it with a debugger and a disassembler such as IDA Pro and x32dbg

EXEInfo PE result

The functions detected by IDA Pro v7.2 reveal an interesting code. We find the app is using a lot of AFX functions, which are basically used in applications developed using the MFC library. Since we saw the malware does some sort of Process Hollowing with the “WerFault.exe” process, I decided to skip the analysis of all the functions and look into the imports of VirtualAlloc and VirtualProtect as these are the most common functions required to allocate the code in memory and inject it.

IDA Dissasembled functions

The VirtualAlloc function cross reference doesn’t lead to much information, its been called after some heap allocations but the memory is not filled and no near VirtualProtect call is made. So instead I decided to check the cross references of VirtualProtect and turns out there is an interesting set of instructions where a huge amount of vars are declared and filled, then we see the VirtualProtect call yet it is pointing to a different memory section. After the VirtualProtect call, there is an interesting call to EnumWindows.

Call to EnumWindows

According to Microsoft Documentation EnumWindows enumerates all top level windows on the screen and pass the result to an application defined callback function, but why would you want to use a user defined function? well if you load a shellcode into a specific memory region, change its privileges to allow execution with VirtualProtect and use its pointer as the first param to EnumWindows so it will get executed after EnumWindows gets all the top level windows.

So let’s dive a little deeper into the code that is been loaded. As there seems to be some operations been ran over the memory segment of the shellcode, I decided to opt for debugging as a faster way to see what’s the shellcode doing. First thing to note is that its using some anti debugging technique that causes IDA runtime analysis to break any breakpoints by moving them into other address. Later I found its some unintended behavior caused by “re-mapping” the PE during runtime.

EnumWindows params

Interestingly the user defined callback function pointer is pointing to the .rdata section. The .rdata segment is flagged as read only statically, but the VirtualProtect function call is actually changing the flags to execution during runtime to be able to run the shellcode.

Stepping into the EnumWindows function after skipping all the code of the legit EnumWindows function leads us to some interesting code. The real entry point to our shellcode is the call esi after a few other calls to user32.dll, where esi is going to be pointing to the user defined callback function located at .rdata.

The first interesting set of functions called are ShGetSpecialFolderPathA() --> CreateFileW(). ShGetSpecialFolderPathA() is used to get the full path of the Start Up folder and then CreateFileW() is used to open a handler to the file Licensee.exe in the StartUp folder. If we go back to app.any.run report we will see that in fact the malware seems to establish persistence first before doing any process injection action.

A common approach to copy the file into the startup folder will be using WriteFile() function, but the authors of this malware seems to take a different approach in order to avoid detection by heuristic. The authors use COM objects to take the handle, create the file and fill it with malicious content. Before the malware call the required functions, it uses LdrLoadDll and GetProcAddress to dynamically link the required dlls and get the address of the functions, it’s also interesting as it avoids the classic LoadLibraryEx by using LdrLoadDll. The function call trace looks something like this

LdrLoadDll() --> LdrLoadDll() --> GetProcAddress() --> GetProcAddress()  --> GetProcAddress() --> GetProcAddress()

Now that the functions are mapped they proceed to call them in the following order

CoInitializeEx() --> CoCreateInstance() --> ShGetSpecialFolderPathW() --> ShCreateItemFormParsingName()

CoInitializeEx is used to start the COM Library then CoCreateInstance creates the instance of the class associated with the specific CLSID, in this case the malware used 3AD05575-8857-4850-9277-11B85BDB8E09 which is “Copy/Move/Rename/Delete/Link Object”, and finally ShGetSpecialFolderPathW and ShCreateItemFromParsingName are used to get the path to startup and create a shell interface object. Note that the COM object used by the malware is auto elevated and attempts to bypass UAC in order to have enough privileges to write into the Startup folder.

After the malware has granted its persistence by making a copy of itself at Startup folder named “Licensee.exe”, now it will attempt to inject itself into the memory and execute the RAT that will connect to the C2 and take control over the victim PC. In order to achieve this the malware first execute the following sequence of Windows API functions

NtCreateFile() --> NtCreateSection() --> ZwMapViewOfSection() --> ZwClose() --> ZwClose()

NtCreateFile is used to create a FileHandle for ntdll.dll, then NtCreateSection is called to create a new section using the previous file and finally ZwMapViewOfSection allows it to map the new section into memory. This turns out to be an interesting way to avoid hooks, because it ensures ntdll is loaded “manually” instead of using LoadLibrary or statically linking the library, which most antivirus solutions monitor using hooks.

Using the newly imported library the malware will now start the Transactional Hollowing. Interestingly, the malware will load first the paths of svchost.exe and wefault.exe but will only use one of them. After a quick analysis I could not determine when it was using svchost.exe or wefault.exe as there didn’t seem any flow that would lead to the svchost.exe string.

String construction of svchost.exe

The malware then initiates the WerFault.exe process using the following functions:

CreateProcessInternalW() --> NtQueryInformationProcess()

CreateProcessInternalW is a windows internal function from kernel32.dll that is undocumented as its suppoused to be only used by the operating system, yet after googling a little bit we find some information about the params of this function and its main goal. CreateProcessInternalW will then create WeFault.exe process in a suspended state and NtQueryInformationProcess is going to retrive the PEB.

ZwAllocateVirtualMemory() -->  RtlInitUnicodeString() --> RtlQueryEnvironmentVariable() --> RtlDosPathNameToNtPathName() --> NtCreateFile() --> NtCreateSection() --> ZwMapViewOfSection() --> NtClose() --> NtClose()

Now this other set of instructions are quiet interesting as they might be a little bit confusing.

RtlInitUnicodeString is used to get the path of WINDIR to a unicode charset in case the user is using a different language. RtlQueryEnvironmentVariable will retriever information of the user environment to get the username ??? . RtlDosPathNameToNtPathName is used to convert and fix the path of wefault to the NT format, NtCreateFile will open a handler to WeFault.exe NtCreateSection will create a new section for WerFault.exe ZwMapViewOfSection maps the newly section into wefault.exe process memory Finally NtClose to close the used handlers.

Now the malware will attempt to load a copy of ntdll into the newly WerFault.exe process. Before doing this, the malware will ensure to set the process to 32 bit and after the dll is loaded it will restore it back to 64 bit. The functions call trace looks like this.

IsWow64Process() --> Wow64DisableWow64FsRedirection() --> GetSystemDirectoryW() --> RtlDosPathNameToNtPathName() --> NtCreateFile() --> NtCreateSection() --> ZwMapViewOfSection() --> Wow64RevertWow64FsRedirection()

IsWow64Process allow it to know whether the program is being run at x64 or x86 system Wow64DisableFsRedirection will enforce the program to run as a 32bit program. GetSystemDirectoryW(eax,20A) will bring the full path of System32 directory RtlDosPathNameToNtPathName will get the nt path of ntdll.dll NtCreateFile will open a handle to ntdll NtCreateSection should create a new section to load again ntdll ZwMapViewOfSection will map the new ntdll Wow64RevertWow64FsRedirection will restore the program to x64

By doing this it will also ensure the newly injected process won’t be hooked by any antivirus, as its running a fresh copy of ntdll. After that an interesting set of instructions are called, and as of today I’m still missing the point of them, there seems to be some debugging protection as I step into the function i always end up in an exception for access violation. The function and the params are the following, if you manage to understand what this function does don’t hesitate to pm me and enlighten me with your analysis :D

sub_45E6B8(eax=0300C830,0,5,0,FFFFFFFF,FFFFFFFF,ecx=00312000,0,eax,0,200,0,0)
sub_45E6B8(edx=0311C830,0,5,0,FFFFFFFF,FFFFFFFF,eax=002AF000,0,eax=0019D3A0,0,320,0,0)
sub_45E6B8(ecx=0311C830,0,5,0,FFFFFFFF,FFFFFFFF,edx=EA2453C0,ecx=7FFC,eax=0019D850,0,58,0,0,0)
sub_45E6B8(ecx=0311C830,0,5,0,FFFFFFFF,FFFFFFFF,edx=00532EE0,0,eax=0019D8A8,0,88,0,0,0)
sub_45E6B8(eax=0311C830,0,5,0,FFFFFFFF,FFFFFFFF,ecx=00532AA4 L"Licensee.exe",0,eax=0019D6C0 L"C:\\Windows\\System32\\WerFault.exe",1A,0,0,0)

These functions are called in twice, then a couple of validations are made and a final call to sub_45E6B8 is made. I suspect this functions are called in order to decode the shellcode into a memory buffer, as the next set of functions will begging the transactions into the file Liebert.bmp. Let’s take a look at them

String construction of liebert.bmp

This subroutine starts by loading the string of TEMP and Liebert.bmp and the call to ZwAllocateVirtualMemory() to allocate some memory space in the current process and get the full path of Liebert.bmp at AppData\Local\Temp. The malware then start creating the transaction to lock the liebert.bmp file, restricting any process to access the file and read its content.

ZwCreateTransaction() --> RtlSetCurrentTransaction() --> RtlDosPathNameToNtPathName() --> NtCreateFile() --> RtlSetCurrentTransaction()

ZwCreateTransaction will create the transaction that will effectively block the access to the process file from the other process like AV RtlSetCurrentTransaction will enable the transaction NtCreateFile will open a handle to the Liebert.bmp file under the transaction RtlSetCurrentTransaction is used again to ensure the file still under transaction

At this point all the malware needs to do is dump all the malicious code into Liebert.bmp and inject it to WerFault.exe by creating a new section. These are the actual functions called to archive this:

NtWriteFile() --> NtCreateSection() --> ZwRollbackTransaction() --> ZwQuerySection() --> ZwClose() --> ZwClose()

NtWriteFile will copy all the code into Libert.bmp NtCreateSection will copy the content of Liebert.bmp into a new section ZwRollBackTransaction will rollback any operation made into Liebert.bmp, deleting it and making forensics hard ZwQuerySection to get information about the newly created section NtClose to close the handlers

From here now the only remaining actions are map the newly created section into WerFault.exe and resume the process.

ZwMapViewOfSection() --> NtProtectVirtualMemory() --> ZwWriteVirtualMemory() --> NtProtectVirtualMemory() --> ZwWriteVirtualMemory() --> NtResumeThread()

ZwMapViewOfSection() will map the new section into WerFault.exe process and the multiple calls to NtPRotectVirtualMemory and ZwWriteVirtualMemory will modify the protection and entry point values of Wefault.exe. Once it’s done the NtResumeThread will get the process running and a small clean routine will close the remaining open handlers and free any used virtual memory used.

Now the RAT is running on memory and we can see the WeFault.exe process making the connection to the Command and Control server :)

Conclusion:

While this technique is quite advanced, it has been spotted in the wild packed with different types of RATs which indicates the original authors sold the loader as a framework on the darkforums and the Colombian gang behind this sample just bought it to use it with REMCOS RAT. I made a quick search on different malware selling forums and didn’t seem to find this kind of loader as easy as the past tools analyzed in other blog posts, meaning this actors could be increasing their capacity and upgrading their tools with the money they have acquired using free tools from earlier attacks.


b1nary

Personal Malware Analysis Blog