Introduction
This is a journal and walk through of how I analyzed Andromeda malware version 2.09. The sample was obtained from VirusTotal website. This is the hash of Andromeda version 2.09 obtained from HashMyFiles application:
MD5: 3f2762d18c1abc67e21a7f9ad4fa67fd
SHA1: 503a9d89608521c5f375184e1ddf2199f420f426
TABLE OF CONTENT
- Introduction
- Application Needed for Malware Analysis
- Analysis Part 1
- Analysis Part 2
- Analysis Part 3
- Analysis Part 4
- Analysis Part 5
- Analysis Part 6
- Analysis Part 7
- Analysis Part 8
- Conclusion
- References
- Programs that are used in this project
Applications Needed for Malware Analysis
- VirtualBox [i]
- Windows 7 which has these applications installed:
Static Analysis:
- Strings [ii]: Extracts the strings from executable
- HxD [iii]: Hex Editor
- PeID [iv] or Detect It Easy [v]: detects the type of packer or compiler which was used to build the executable
- PE Bear [vi]: browsing the PE header file
- Resource Hacker [vii]: view and extract resource section of PE file
- HashMyFiles [viii]: create different hash for files, a unique file signature
- IDA pro [ix], Cutter [x], or Ghidra [xi]: Disassembler
Dynamic Analysis:
- Procmon [xii]: Monitors all file system activity in real-time
- Process Hacker 2 [xiii]: Windows task manager
- Microsoft Network Monitor [xiv]: Monitors network activity
- FakeNet [xiv]: Simulates a real network on the installed PC
- x64dbg [xv], OllyDbg [xvi], Immunity Debugger [xvii], or WinDbg [xviii]: Debugger for Windows executables.
- VirusTotal [xix]: gives a report of what actually the executable does
- Hybrid-Analysis [xx]: gives a report of what actually the executable does
- BlobRunner [xxi]: Application to quickly debug shellcode extracted during malware analysis.
- Python 2.7 [xxii]
Analysis Part 1
First, I ran the 209.ex__ inside the virtual machine while Process Monitor, Process Hacker, Regshot, FakeNet and Microsoft Network Monitor were running. This is just a basic dynamic analysis to understand what is happening when I execute Andromeda inside VirtualBox.
Process Monitor shows that Andromeda accesses the “C:\Windows\SysWOW64\*.dll”. It seems like asterisk is a wild card to open any dll files inside “C:\Windows\SysWOW64\”. Other than this there is nothing much to report about Andromeda activity.
Process Hacker shows that Andromeda stands idle for some time, then creates a child process, and closes the parent process.
But the child process remains idle, and doesn’t do anything at all (There is no CPU or I/O load at all).
It seems like that I’m missing something here, because the child process in the above picture has a different process ID than the child process that I’ve mentioned before.
There is no useful information in Regshot, FakeNet and Microsoft Network Monitor application regarding Andromeda.
I also used VirusTotal and hybrid-analysis websites to see the behavior of Andromeda.
In VirusTotal, Andromeda reaches to these websites for what it seems DNS resolution, but nothing has been resolved:
Hybrid-analysis shows another network communication that VirusTotal doesn’t show. It connects to 64.70.19.203 IP address from port 80 by TCP protocol under the hxxp://happysingh.ws domain. msiexec.exe is the process that makes this connection.
VirusTotal shows that Andromeda opens lots of DLL files. It’s probably to import methods from these DLLs:
VirusTotal also shows the file “msslenb.exe” is being copied to different directories. Also, it shows that the attributes of the file have been changed:
VirusTotal also shows some registry key changes, and a set of new value in “\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\Explorer\Run”. The new value has been set to make sure that Andromeda keeps running after system’s restart. Other value changes are there to make sure that malware runs stealthy
VirusTotal also shows some services being opened by Andromeda which are related to Windows security. Andromeda probably is going to terminate these services
At the end of VirusTotal report, I see the Process Tree report. It seems like that I missed to see some of the child processes when I was monitoring the Andromeda with process hacker application. Also, it seems like that Andromeda being spawned in different explorer.exe processes.
Analysis Part 2
Now that we’ve got a rough idea of what Andromeda is doing. Let’s continue with basic static analysis:
I first opened the file (209.ex__) in DIE (Detect it Easy) to see what sort of binary the file is. It is compiled with “Microsoft Visual C/C++ (2005)” and linked with “Microsoft Linker (8.0 or 11.0) [EXE32]”.
MD5: 3f2762d18c1abc67e21a7f9ad4fa67fd
SHA1: 503a9d89608521c5f375184e1ddf2199f420f426
Using entropy feature of Detect It Easy application (to see if there is any usage of cryptography), we see that the entropy is really high around the .rsrc section of the file (with entropy of 7.5418) This indicates that there is a high probability that the resource section of the file is encrypted.
We check the executable inside Resource Hacker to see what’s going on inside the resource section:
It’s probably another PE executable which is encrypted and the malware will decrypt it, but I’m not sure until I analyze it inside Ida Pro and x64dbg.
The real purpose of .rsrc section is to store icons, images, menus and strings. but malware usually stores strings (configurations) or another binary file inside their own resource section in order to hide the real intention of the executable.
Checking the file inside PE-bear, we see no import functions related to resource manipulation.
Using strings.exe on 209.ex__ shows some interesting strings inside this binary:
These strings are related to resource functions from Windows API. It seems like that the malware uses LoadLibrary and GetProcAddress methods to get a handle for these APIs (I’m not sure yet) by using their strings. There are other functions beneath them (Figure 16) that gives me an idea of what this executable is going to do, but let’s not just jump to conclusion yet.
Analysis Part 3
I use IDA Pro to analyze the executable. But keep in mind that the code is compiled with C++, therefore the first argument of functions is probably inside ECX or ESI register. In the main function, there are a lot of Sleep methods before the custom methods. The first custom function sub_430EA0 takes as argument a variable and 64h (100 in decimal). In the function malware uses LoadLibraryA method to get a handle of Kernel32.dll library. So, it could import the LoadResource, FindResourceA, LockResource, SizeofResource (Figure 15) with the help of GetProcAddress method, locally. If you check the executable with Resource Hacker program again, you see that 64h or 100d (sub_430EA0 second argument) is the name of resource that its content was all gibberish. I renamed the function get_resource_file.
At the end of this function the size of resource will be put inside memory location pointed by [edx+74h] and the handle to the resource section will be put inside [edx+78h]. EDX register is in fact a placeholder for the first argument of this function which I renamed to var_object_resource.
After this the main function uses the same var_object_resource as an input for function sub_430D00. This function is repeated 3 times in the main. This function uses loop as a means to iterate the resource section.
The existence of string:
(“AJNHxijchiHXU iuHXUHCIuhXUIHC^&TWS&*Y9uhiuhidhsid”) which I renamed as KEY and instruction xor ecx,edx (ECX register as memory address resource section and EDX register as memory address for KEY string) implies that this is a decryption/decoder function for resource section.
Further analysis in x64dbg shows that this is indeed a decryption function for resource section. I renamed the function to decode_resource. I was wondering why there are 3 decode_resource function in main. After some research, I’ve found out that this is xor-encrypt-xor method. Since the core functionality of decode_resource depends on xor instruction, and xor cipher is a reversible cipher, then only one decode_resource function was necessary. Xor-encrypt-xor would have worked here if they used some other algorithm for the middle decryption/encryption scheme. Then, two XOR cipher would work fine as post and pre-whitening of encrypted content of resource section.
Since I knew from the analysis of get_resource_file function in IDA Pro that [var_Object_resource+78h] is resource memory section. I used x64dbg to see the result of resource memory section.
You could see the result of the resource decryption in x64dbg which is now a new PE executable. The MZ and “This program cannot be run in DOS mode” strings are the proofs.
After the decryption process the executable gets a handle to its own file path. The main function has another subroutine called sub_431020. The argument to this function is: var_Object_Resource, file path handle, and resource memory section.
Sub_431020 is really long, but seeing the methods that it uses: SetThreadContext, WriteProcessMemory, VirtualAlloc, ResumeThread, ReadProcessMemory, CreateProcessA, GetThreadContext, NtUnmapViewOfSection. It is safe to assume that it uses the process replacement method, to replace the child process that it creates with the content of resource section which is another PE file. I renamed sub_431020 to create_process_for_resource.
Since I knew that [var_Object_Resource+78] is the memory location of resource section. I put a breakpoint in x64dbg application after the xor-encrypt-xor methods at 0x00430C37 (mov ecx,dword ptr ds:[eax+78]) to dump the memory section to a file which ECX register is pointing to (Figure 23).
Analysis Part 4
The extracted PE file has some unnecessary bits before MZ header. I used HxD (Hex Editor) to remove them from the file. This PE file (result of decrypted/decoded resource section) is indeed a new PE file because it has different MD5 and SHA1 hashes compared to the original executable:
MD5: 5be834905e74c503ac3591c5779890a5
SHA1: 9b3abd6f03605644287249696dbbc9dc7145607f
The file is compiled with Microsoft Visual C/C++ (2005) and linked with Microsoft Linker (8.0 or 11.0) [EXE32].
Opening the file inside PE-bear, we see that it has the same imported function as the first executable. It also has a .rsrc (resource) section.
I used the strings command and saw the familiar methods regarding the resource manipulation.
The entropy of resource section is really high too:
Checking the resource section with Resource Hacker, we see the same gibberish here as the first executable:
These two files (original executable and decrypted resource section) are really similar, but they are not the same file (Figure 25).
Analysis Part 5
I opened the file inside IDA Pro. The whole structure of the main PE file is exactly like the first PE file, with some minor changes. The main function is less cramped. There is no local variable that holds resource object (var_Object_Resource). Now it’s a global variable that is being held by the EBX register. It has the same sub routine for getting the resource, and somehow the same 3 subroutines for decrypting the resource section by XOR instruction. And finally uses the same Windows API methods for creating a child process with the content of resource section.
I used the same method here with the help of x64dbg to dump the content of resource section after the decryption routines.
I just want to point out that these two executable encrypt/decrypt Windows API method names with xor instruction inside a function. This happens inside the last custom function for creating the child process for the decrypted resource section, but the plaintext of each function name is visible inside IDA Pro. So this anti-reverse engineering has no use at all.
Analysis Part 6
I used HxD hex editor to remove the extra bits from the beginning of the decrypted resource section.
The third file is really small only 20 KBs, compared to 209.ex__ (576 KBs) and resource_decoded.ex___ (108 KBs).
It also has different hash compared to the previous files:
MD5: 4261bb4f43fdd9e02e93f501ad38f2a3
SHA1: a6d86ccbb9ae98731c6666b1f8ad3e06ed645783
I opened the file in Detect It Easy. The file is only linked with Microsoft Linker (9.0) [EXE32]. There is no compilation involved.
The file has two section: .text and .rdata. Both .text and .rdata section have high entropy. This is just getting more and more complicated.
I opened the file inside the PE-bear. There is no import section. The executable doesn’t use any Windows API methods. I don’t know, but that is why there was no need to compile the file to create the object file in the first place. That may explain why there was only Microsoft Linker for creating the 3rd executable (Figure 36).
I used the strings program to see if there are any interesting string inside the file, but there is nothing. I’m starting to think that this is a shellcode.
Analysis Part 7
I opened the file inside IDA Pro. The start function uses the fs:30 to access the 0x30 offset of FS segment register which holds the Thread Environment Block (TEB). The binary then uses PEB (Process Environment Block) structure to access the ntdll.dll base. This method of getting to DLL files is only used in shellcodes.
At first, I wanted to use BlobRunner from OALabs to debug the binary, but after some attempts, I’ve figured out that the binary is too large for the section that the BlobRunner is allocating. I just opened the binary inside x64dbg, and it worked!
Since the file has the characteristics of shellcode, I used IDA Pro and x64dbg alongside each other. After start function acquires the ntdll.dll base, it calls the sub_D171E function. By doing so, it gets the address (here the address is 0x000D16EA of bytes right after sub_D171E function, and stores it inside ESI (pop esi). It seems like these bytes are hashes that the Andromeda is going to use later.
It seems like that sub_D171E function uses the ntdll.dll base and string hash as argument for sub_D1204 and stores the result of sub_D1204 into [ebp-40]. Sub_D1204 uses the IMAGE_EXPORT_DIRECTORY to get access to the exported function of ntdll.dll. By doing so, it gets access to AddressOfNames, AddressOfFunctions, AddressOfNameOrdinals, and NumberOfNames from ntdll.dll file.
It then uses AddressOfNames array to hash the function name string with XOR, and ROL instruction in hash_string function
and compares it to the second input of function which is the hash symbol.
Basically, the sub_D1204 finds address of functions that gets as the hash symbol (function second argument). I renamed the function to find_symbol_by_hash .
The function sub_D171E stores the result of find_symbol_by_hash inside edi or [ebp-40].
These are the addresses that are stored inside EDI register or [ebp-40]:
Some of these functions are not documented at all by Microsoft which makes the analysis of Andromeda a lot harder.
There is only one function remains (sub_D12CB) inside the sub_D171E which takes its own PE file header, loaded function addresses, and Kernel32.BaseThreadInitThunk as input:
The sub_D12CB is really long and complicated. I will do my best to describe exactly what it does. It took me a lot of trials and errors, researching the undocumented Windows API function, analyzing assembly instruction, and debugging the function inside the x64dbg to understand how this function operates.
First it disables the ProcessDefaultHardErrorMode to prevent the user from seeing any pop-up error in the system by calling ZwSetInformationProcess.
Then, It allocates a memory section for read and write.
It copies [rdata+0x28] section into the allocated memory section with read and write permission. Then, it decodes/decrypts the copied [rdata+0x28] section with RC4 algorithm.
At first, I thought that the decryption algorithm for rdata section is a simple XOR algorithm, since RC4 function uses XOR instruction in its core functionality. But after some research about Andromeda analysis, I found out that research papers about Andromeda analysis mention the RC4 algorithm for decrypting the payload [1] - [3] When I looked at the code from perspective of these research papers, and searching the RC4 algorithm, the use of RC4 algorithm became clear:
This is just a side note: Through my analysis, I noticed that different part of rdata section is being used in malware, but I wasn’t 100 percent sure about the structure of rdata. After some research I’ve found out that Avast draw a perfect picture of rdata section [3]:
- RC4 key for payload decryption (first 16 bytes).
- Payload size (dword).
- Payload CRC32 hash (dword).
- Heap allocation size for decompressed payload data (dword).
- Entry point of decompressed payload (dword).
- Pointer to decompressed payload data section (dword).
- Size of decompressed payload data section (dword). This value is unused by loader.
After the decryption of rdata section, it allocates a new memory section for read, write, and execution. And decompresses the new decrypted/decoded .rdata section into this new memory.
In order to execute the rdata section which is decrypted and then decompressed, it needs to be mapped into memory. This is the job of Windows dynamic loader, but the decrypted and decompressed rdata section is not an ordinary PE file. Sub_D12CB will do this job by the help of LdrProcessRelocationBlock and NtAllocateVirtualMemory in a loop, until each section of new rdata is mapped into memory. I didn’t know the real purpose of these two methods, until I remembered the video clip by OALabs. [5]
The decrypted and decompressed .rdata section has the hashed strings (Strings that are computed with the same XOR and ROL instruction) for DLLs and functions that resource_decode_2.bin wants to import.
It queries the \Windows\SysWOW64\*.dll with ZwOpenFile and NtQueryDirectory to find the DLLs that matches the hashed string inside the new rdata, and loads them with LdrLoadDll method.
Then, it finds the function addresses with find_symbol_by_hash function and hashes from the decrypted rdata to add them to the newly allocated section with read, write, and execution permission. It doesn’t build an import table. It just adds the addresses with a jump instruction. (I didn’t know about the jump address table, until I debugged the payload in x64dbg)
Here is the list of functions that Andromeda uses, and because it’s a lot of functions. I am certain that this is indeed the payload of Andromeda. The list of imported function is really massive. Based on this list alone, you could say that this is indeed the payload of Andromeda malware. This List is written in this journal based on placement order in memory section:
advapi32.dll
AdjustTokenPrivileges
ConvertStringSidToSidA
GetSidSubAuthority
GetSidSubAuthorityCount
GetTokenInformation
LookupPrivilegeValueA
OpenProcessToken
ChangeServiceConfigA
ControlService
RegOpenKeyExW
RegNotifyChangeKeyValue
RegCreateKeyExW
ConvertStringSecurityDescriptorToSecurityDescriptorA
RegSetKeySecurity
RegFlushKey
RegCloseKey
OpenSCManagerA
OpenServiceA
CloseServiceHandle
CheckTokenMembership
crypt32.dll
CryptBinaryToStringA
CryptProtectData
CryptUnprotectData
CryptStringToBinaryA
dnsapi.dll
DnsWriteQuestionToBuffer_W
DnsExtractRecordsFromMessage_W
DnsFree
kernel32.dll
GetProcAddress
GetModuleHandleA
LocalFree
GetLasError
GetVersionExW
GetVolumeInformationA
GetWindowsDirectoryA
CloseHandle
GetCurrentProcess
VirtualProtect
Module32Next
lstrcatA
lstrlen
Module32First
CreateToolhelp32Snapshot
ntdll.dll
RtlExitUserThread
kernel32.dll
Process32Next
Process32First
ExitProcess
DisconnectNamedPipe
ReadFile
ConnectNamedPipe
CreateNamedPipeW
ntdll.dll
RtlSizeHeap
kernel32.dll
CreateFileA
CreateThread
LoadLibraryA
SetEvent
OpenEventW
WaitForSingleObject
CreateEventW
SetEnvironmentVariableW
GetShortPathNameW
GetModuleFileNameW
GetEnvironmentVariableW
UnmapViewOfFile
MapViewOfFile
CreateFileMappingA
OpenProcess
MultiByteToWideChar
CreateProcessW
CreateFileW
GetTickCount
ExpandEnvironmentStringsW
SetFilePointer
DeleteFileW
SetFileAttributesW
MoveFileExW
lstrcpyA
SetFileTime
GetFileTime
ResumeThread
TerminateProcess
wow64GetThreadContext
lstrcatW
GetWindowsDirectoryW
QueueUserAPC
CreateRemoteThread
lstrcmpi
GetCurrentProcessId
FreeLibrary
VirtualAlloc
GetFileSize
GetModuleHandle
lstrlenW
FindCloseChangeNotification
FindFirstChangeNotification
lstrcpyW
TerminateThread
GetExitCodeProcess
HeapFree
ntdll.dll
RtlReAllocateHeap
kernel32.dll
GetProcessHeap
ntdll.dll
RtlAllocateHeap
kernel32.dll
Sleep
WriteFile
shell32.dll
ShellExecuteExW
shlwapi.dll
StrCmpNW
SHGetValueW
StrRChrW
StrCmpNIW
SHSetValueW
SHDeleteValueW
StrChrW
StrToIntW
SHSetValueA
SHDeleteKeyA
StrChrA
user32.dll
wsprintfA
wsprintfW
SendMessageA
FindWindowA
mouse_event
winhttp.dll
WinHttpOpenRequest
WinHttpConnect
WinHttpSetOption
WinHttpOpen
WinHttpCrackUrl
WinHttpCloseHandle
WinHttpQueryHeaders
WinHttpReceiveResponse
WinHttpSendRequest
WinHttpReadData
ntdll.dll
ZwUnmapViewOfSection
RtlWalkHeap
RtlImageNtheader
RtlComputeCrc32
ZwQueryInformationProcess
LdrProcessRelocationBlock
RtlImageDirectoryEntryToData
NtMapViewOfSection
ole32.dll
CreateStreamOnHGlobal
CoInitialize
ws2_32.dll
WSAStartup
ntohl
closesocket
shutdown
getsockname
connect
gethostbyname
socket
htons
recvfrom
ioctlsocket
sendto
WSAEventSelect
WSACreateEvent
After importing every method that payload needs to use, it uses a call instruction (call eax) to jump to the real entry point of the payload (offset 0x1525), 0X7EF90000 is the memory section that was allocated for decompressing the decrypted rdata section:
Analysis Part 8
I followed the call with x64dbg. As you can see, x64dbg wasn’t able to identify Windows API methods.
It’s because Andromeda payload uses jump addresses instead of actually building the import table. This is done in order to make the analysis of Andromeda harder.
I dumped the 0x7EF90000 memory section from x64dbg to a file, in order to analyze it inside IDA Pro.
MD5: a43e8762c9e50007a9ea8139232ad6e8
SHA1: a45ee1c45c50ccf6d2e5c0217f0aaa3c3bf6ebe3
At first, I wanted to use Scylla or ImpRec 1.6 to build the function import table. But ImpRect would only accept original entry point (OEP), and Scylla would mess the structure of payload completely.
After so many trials and errors with Scylla and ImpRec. I decided to manually follow each jump to the real function with x64dbg (which took a lot of time), to write the jump addresses and function names. This is a small sample of what I’ve actually did:
I had to manually write these down for 154 methods that Andromeda is going to use.
This is how 0x7EF9000 memory section looks like in IDA Pro. Each dword_7EF9xxxx label points to an address in memory.
After writing down every Jump Table Real Address and Function Name (Refer to Table 2),I created a simple Python script with the help of idc library (from Ida Pro) to rename the IDA labels to their real function names.
This is the result of Python script:
Now I could easily analyze the payload inside IDA Pro.
At the beginning of Andromeda payload there is a function call, and if the result of that function call becomes true, the payload goes into an infinite loop. Remember at the beginning of journal, we used process hacker to monitor the Andromeda, and there was no CPU usage after executing it. I think this is the reason.
The sub_7EF912F4 function iterates the process names with the help of CreateToolhelp32Snapshot, Process32First, and Process32Next. It converts each process string name into a hash with RtlComputeCrc32 method, and compares it against an array of hashes. If any process name matches, function returns true.
Since I’m using VirtualBox as a virtual machine, “vboxtray.exe” and “vboxservice.exe” string make the function to return true. I named the function check_virtualization_software. At the end of check_virtualization_software, it seems like that malware also checks to see the volume information of “C:\Windows\” and compares it against 0x20C7DD84. if there is a match, then makes the result of return false.
This is a full list of what these hashes actually correspond to [1],[3]:
After making sure that it doesn’t run inside a virtual machine. In a function at (0x7EF90000 + 0DD5) loads KiFastSystemCall and replaces its instruction with
In another function, it gives itself SeDebugPrivilege, SeBackUpPrivilege, and SeRestorePrivilege privileges. It stores the volume serial number of Windows directory and operating system version in a global variable. Also, it checks whether it’s part of administrator group or not, by using “S-1–5–32–544” security identifier, and stores the result inside a global variable. At the end of function, it hooks NtOpenSection (ntdll.dll) and GetAddrInfoW (ws2_32.dll) by implementing jmp instruction at the beginning of NtOpenSection and GetAddrInfoW methods.
After this, payload tries to open a process with an ID which is XORed with Windows directory volume serial number and first 32 bits of Kernel32.BaseThreadInitThunk. If it wasn’t able to open it or the ERROR is ERROR_ACCESS_DENIED. Then payload tries some persistence functionality. My guess here is that Andromeda payload wants to see if it could open any process (random id number) with OpenProcess method. And if it can’t do this, then tries to be more persistence. But if it could open any process then it won’t even bother to be more persistence and to use two threads that I’m going to mention in the next paragraph.
It creates two threads. One makes sure that its registry value inside “HKEY_CURRENT_USER\software\microsoft\windows\currentversion\Run” never be deleted. Also, the provided security descriptor for Andromeda registry is “D:(A;;KA;;;WD)” string. The other thread makes sure that the Andromeda executable file never gets deleted. It also makes the executable Hidden and Super Hidden by making it part of system files, and setting “HKEY_CURRENT_USER\software\microsoft\windows\currentversion\explorer\advanced” of “ShowSuperHidden” and “Hidden” to 0 and 0x2000000 respectively.
Payload checks to see if it has the environment variable which is XORed with volume serial number of windows directory and string “src”.
If the process doesn’t have this environment variable. It creates the environment variable. Name of the environment variable is the string “src” which is XORed with volume serial number of Windows directory, and its value is the compacted path of Andromeda 3rd dropper (The one with shellcode characteristics).
Example:
Malware 3rd dropper path: “C:\1 MALWARE\209\resource_decoded_2.bin”
Name: “2995329464” Value: “C:\\1MALWA~1\\209\\RESOUR~1.BIN”
Andromeda won’t proceed with the rest of payload instructions. Instead, it finds the path of msiexec.exe:
And it creates two processes with the help of msiexec.exe and injects 3rd loader/dropper of Andromeda into each of them. One method uses MapViewOfFile, RtlImageNtheader, CreateFileMappingA, MapViewOfFile, CreateProcessW, NtMapViewOfSection, wow64GetThreadContext, ZwUnmapViewOfSection, and ResumeThread to create a child process and injects loader/dropper into an allocated section. It then, rewrites the entry point of newly msiexec.exe with push and ret instruction to jump to the injected section.
The other method uses CreateProcessW, NtMapViewOfSection, QueueUserAPC, and ResumeThread to create a new msiexec.exe process and gives the entry point of 3rd dropper as an input to QueueUserAPC.
These two injections drop the same injected payload, and have the exact same hash as the decrypted payload that I’m analyzing right now. So, it’s safe to assume that they have the same code structure, and there is no difference between them.
Before Payload does these two injections, it creates an event (volume serial number xored with “injc” string) with CreateEvent method. My guess is that this event works as a semaphore.
So, when I wanted to analyze the injected process there was a problem with the injected 3rd dropper (msiexec.exe). There were int 3 instruction at some part of the executable which completely ruined the calls instruction and other instruction as well. At first, I thought that maybe this is part of Andromeda anti-debugging scheme. But after some digging, I’ve found out that my breakpoints inside the 3rd dropper memory were the cause of problem, since the previous payload copies the memory of 3rd loader/dropper that I was analyzing inside x64dbg into the misexec.exe.
After the success of msieexec.exe injection, payload tries to load the “sbiedll.dll”. And if it succeeds, it exits the process. This DLL is part of “Sandboxie” application [6]. Payload still wants to make sure that it’s not running inside a virtual machine.
Payload wants to open three existing pipe files:
- \\.\pipe\[“kill” ^ volume_serial_number] my system example: \.\pipe\3650291639
- \\.\pipe\[“exit” ^ volume_serial_number] my system example: \.\pipe\3615621807
- \\.\pipe\[“[[\U” ^ volume_serial_number] my system example: \.\pipe\3919656846
By using CreateThread methods to write the name of each pipe file inside itself. since these files don’t exist, the CreateFileA method inside write_pipe_file_thread failes and won’t write these values inside each file, because CreateFileA method uses OPEN_EXISTING flag. The content of each file if the CreateFileA method would have been successful matches the name of each pipe file.
Just to be sure I used [System.IO.Directory]::GetFiles(“\\.\\pipe\\”) command in PowerShell, but there was no pipe file with the above names.
After this, payload tries some persistence action to remain in the infected system:
Payload either uses “C:\Users\[username]\AppData\Roaming” as the path to make a copy of resource_decoded_2.bin (3rd loader/dropper), and sets a registry value (new path of 3rd loader/dropper) in “HKEY_LOCAL_MACHINE\software\microsoft\windows\currentversion\Policies\Explorer\Run” or it uses “C:\ProgramData” to make a copy of 3rd dropper and sets a registry value (new path of 3rd dropper) in “HKEY_CURRENT_USER\software\microsoft\windows\currentversion\Run”. It all depends on whether the payload could set the new security descriptor “D:(A;;KA;;;WD)” on any of these registries, also it depends on if “ALLUSERSPROFILE” or “APPDATA” does exist in the environment variable.
Payload makes a new name for 3rd dropper (“ms%s.exe”) based on the volume serial number XORed with the string “0209” (version of Andromeda). The randomized name is only three characters long. For example, the 3rd dropper name for my system is “msxvq.exe”.
It sets the file attribute to FILE_ATTRIBUTE_HIDDEN || FILE_ATTRIBUTE_SYSTEM which makes it hidden from user. It sets the file time of “ms%s.exe” to ntdll.dll file time, and stores it inside one of environment variable paths (“ALLUSERSPROFILE” or “APPDATA”). The value of new registry which stores the “ms%s.exe” path is the result of “0209” which is XORed with volume serial number.
Even though I knew that it uses the 3rd dropper handle from Process Hacker program to create the new msixvq.exe file. Just to be sure, I used the HashMyFiles program to see if there is any difference between the msxvq.exe and 3rd loader/dropper (resource_decoded_2.bin)
Payload then tries to execute this new 3rd loader/dropper by requiring a handle to taskbar window, and using ShellExecuteExW method and “runas cmd.exe /c C:\Users\[user_name]\AppData\Roaming\msxvq.exe” string as input.
After trying to execute the new 3rd dropper, payload disables windows notification [7] by enabling “TaskbarNoNotification” value in “HKEY_LOCAL_MACHINE\ software\microsoft\windows\currentversion\policies\Explorer” registry and “HKEY_CURRENT_USER\ software\microsoft\windows\currentversion\policies\Explorer”.
Payload also disables the security and maintenance icon [8] by enabling registry value of “HideSCAHealth” in “HKEY_LOCAL_MACHINE\ software\microsoft\windows\currentversion\policies\Explorer”, and “HKEY_CURRENT_USER\ software\microsoft\windows\currentversion\policies\Explorer” registries.
After disabling “HideSCAHealth” registry values, payload uses OpenSCManagerA, OpenServiceA, ControlService, and ChangeServiceConfigA methods in a custom function to disable some of windows services that are related to windows security, firewall, and update.
These are the list of windows security services:
- wscsvc
- SharedAccess
- MpsSvc
- WinDefend
- wuauserv
After disabling windows services, payload disables EnablueLUA (HKEY_LOCAL_MACHINE\ software\microsoft\windows\currentversion\policies\system) value registry to make sure that Windows User Account Controls (UAC) won’t notify the user when Andromeda tries to make changes to the computer [9]. Payload also disables “ShowSuperHidden” (HKEY_CURRENT_USER\ software\microsoft\windows\currentversion\explorer\advanced) registry value which controls whether super-hidden (Hidden + System) files are displayed [10]. And enables “Hidden” (HKEY_CURRENT_USER\software\microsoft\windows\currentversion\explorer\advanced) registry value which makes the hidden files remain hidden. Payload disables task manager program by deleting its registry value from HKEY_LOCAL_MACHINE\software\microsoft\windows nt\currentversion\image file execution options\taskmgr.exe registry path. Fortunately, the task manager program registry value in my system is not in the path that Andromeda wants to delete.
Andromeda payload tries to be more persistence, and tries to inject its 3rd dropper into every process using CreateRemoteThread or RtlCreateUserThread methods based on windows version. But it exempts msiexec.exe (its own payload) and explorer.exe processes. Payload uses CreateToolhelp32Snapshot, Process32First, lstrcmpi, OpenProcess, NtMapViewOfSection, GetCurrentProcessId, CreateRemoteThread, RtlCreateUserThread, and Process32Next methods to achieve this feat.
Payload gets the base address of 3rd dropper with NtMapViewOfSection method, and uses either CreateRemoteThread or RtlCreateUserThread to create a thread that Andromeda 3rd dropper is injected into that thread.
After this process injection, Payload creates pipe file “[[\U]” string XORed with volume serial number in a thread that is always connected to the pipe file, and checks the content of pipe this pipe file.
If the content is the name of pipe file (“[[\U]” string XORed with volume serial number), then payload exits. I think this is a check for when Andromeda downloads a new binary and wants to creates a new version of itself. It opens the existing pipe file (recall the 3 threads that each one open a pipe file) and writes to it the name of pipe file (“[[\U” ^ volume serial number). Now the old Andromeda that checks the content of this file in an infinite loop in a thread sees the file content and exits.
There is only two more custom function remain at the end of Andromeda payload. And one of them is being created by CreateThread. This function is really long.
I’m assuming that this is probably the main function of andromeda payload. Also, C2 (Command and control) of Andromeda sample that I’m analyzing is not alive which makes the analysis of Payload from this point on a lot harder.
Main_Thread tries to connect to official websites (update.microsoft.com, microsoft.com, bing.com, google.com, and yahoo.com). By doing so, it acquires the IP address of system through accessing sockaddr structure in getsockname method [3]. And It stores the IP address in a global variable.
0x0A00020F will become 0A.00.02.0F. Therefore 10.0.0.2.15. I confirmed it by using CMD command:
> ipconfig | findstr /i “ipv4”
After this, payload fills the string format “id:%lu|bid:%lu|os:%lu|la:%lu|rg:%lu” with the necessary information about the infected system. It’s like that Andromeda uses this string format to register the bot to the server. This is the list of what every tag means according to the research papers that I’ve read [1], [2], [3], [4]:
Main_Thread tries to find the “aReport” export method by iterating each module in Andromeda payload. And afterwards calls the “aReport” method. According to Avast, this is one of Andromeda’s plugins [3].
Payload uses the same custom RC4 encryption in 3rd dropper to encrypt the message, and encrypts the message again with Base64 algorithm with the help of Windows API CryptBinaryToStringA method (The first CryptBinaryToStringA method in Figure 100 just gets the size of string for encryption. The second method encrypts the message with Base64).
After encrypting the system information, Main_thread uses a custom function to send the information and waits for the command from the Andromeda server. First, function Iterates the heap with RtlWalkHeap method to find volume serial number XORed with 0x706e6800.
Then, it uses winhttp.dll methods to create a URL from the specified buffer in that heap location. It uses “Mozilla/4.0” as browser agent, and “application/x-www-form-urlencoded” to post data.
As I mentioned before the C2 server of sample that I’m analyzing is dead, so any analysis from this point forward is only done from static analysis perspective.
The received data first gets checked by RtlComputeCrc32 method to make sure that it has a valid hash [1].
Then, it gets decrypted by RC4 followed by base64 decryption [1]. The RC4 key for the payload is actually volume serial number of infected system.
Also, Andromeda’s payload tries to see if it could find “aUpdate” export method and invokes it before trying to decode the received buffer by Base64 algorithm.
There is one last function in the Main_thread. This is where Andromeda decides what to do with the decrypted command. I tried my best to recognize the functionality of this part of Andromeda based on the research papers that I’ve read.
There are 5 cases on Andromeda verion 2.09: 1, 2, 3, 6, and 9.
Case 1 (Download EXE): Andromeda downloads an executable from server in a loop. It decrypts the received buffer with RC4 algorithm. It checks the validity of buffer by using RtlComputeCrc32 method, and decompress the buffer.
After decrypting and decompressing the received buffer, it names it “KB%08lu.exe” (%08lu = GetTickCount_func) and stores it inside temp directory. In the end, it executes it with CreateProcessW method.
Case 2 (install plug-in): Andromeda downloads an executable from server in a loop. It decrypts the received buffer with RC4 algorithm. It checks the validity of buffer by using RtlComputeCrc32 method, and decompresses the buffer.
It uses LdrProcessRelocationBlock method in a loop to load It into memory finds the “aStart” export method in the decrypted and loaded buffer and executes it.
Case 3 (Update bot): Andromeda downloads an executable from server in a loop. It decrypts the received buffer with RC4 algorithm. It checks the validity of buffer by using RtlComputeCrc32 method, and decompresses the buffer (Figure 105).
It deletes (DeleteFileW method) the previous 3rd loader/dropper, creates a new executable (CreateFileW, WriteFile methods) and executes (CreateProcessW method) it.
The new executable will probably open the pipe file “[[\U” XORed with volume serial number, and writes the “[[\U” XORed with volume serial number which makes the old process to be closed.
Case 6 (Delete plug-ins): It opens a handle to its own process and deletes the specified plugins in a loop.
Case 9 (Kill bot): It deletes its registry value from registry and deletes its file with DeleteFileW and MoveFileExW methods. MoveFileExW method has null for lpNewFileName and MOVEFILE_DELAY_UNTIL_REBOOT for dwFlags [11].
After each command gets executed, Andromeda sends a report to its server. This is a report message which will be filled by Andromeda’s payload: “id:%lu|tid:%lu|err:%lu|w32:%lu”.
Avast’s research paper has a table regarding each entry for the report’s message [3]:
After filling the message report with the required information, the message gets encrypted by RC4 followed by Base64 algorithm, and gets send to the server.
I did mention before the Main_thread analysis that there was another function besides Main_thread. The other custom function tries to find the “aStart” export method and executes it.
Conclusion
Andromeda 2.09 payload is packed with 3 loaders/droppers. The payload is encrypted with RC4 algorithm. The payload is injected into the 3rd loader/dropper and it uses a table of jump addresses for calling Windows method instead of properly creating an import table. This is done to confuse the disassembler (IDA Pro) and debugger (x64dbg). So the methods name won’t appear in neither of these applications.
Andromeda payload disables Windows error notification, and iterates over saved CRC32 process name hashes of virtual machine processes, and compares them against system process names of current system to see if it’s being deployed inside a virtual machine.
Andromeda copies itself to %ALLUSERPROFILE% or %APPDATA%, and completely hide itself. The payload is then, injected to two newly created msiexec.exe process and continues its action from these processes. It tries to load sbiedll.dll to check for Sandboxie virtual machine. And if the load was successful, it exits from the process. It injects its payload into any other process except explorer.exe and msiexec.exe. The payload disables Windows security services: wscsvc SharedAccess, MpsSvc, WinDefend, and wuauserv.
Andromeda stores general information regarding victim’s system by using a custom string format which is encrypted with RC4 and Base64 algorithms. By doing so, it registers the infected machine to the C2 server of Andromeda. Communication between server and Andromeda is encrypted with RC4, and uses a custom string format for this communication. Andromeda 2.09 has the ability to:
- Download another malware from server and execute it.
- Install new plug-ins to increase its capabilities like: Keylogger, Browser FormGrabber, Rootkit, Hidden TeamViewer remote control.
- Delete plug-ins.
- Update itself.
- Kill itself.
Host-Based Signature
- First loader/dropper file hash:
- MD5: 3f2762d18c1abc67e21a7f9ad4fa67fd
- SHA1: 503a9d89608521c5f375184e1ddf2199f420f426
- Existence of string key for decrypting resource section in first loader/dropper:
- “AJNHxijchiHXU iuHXUHCIuhXUIHC^&TWS&*Y9uhiuhidhsid”
- Existence of string key for function name encryption/decryption in first loader/dropper:
- “KJHIschiHSIdW”
- Second loader/dropper file hash:
- MD5: 5be834905e74c503ac3591c5779890a5
- SHA1: 9b3abd6f03605644287249696dbbc9dc7145607f
- Existence of same string key for decrypting resource section in second loader/dropper:
- “AJNHxijchiHXU iuHXUHCIuhXUIHC^&TWS&*Y9uhiuhidhsid”
- Existence of string key for function name encryption/decryption second loader/dropper:
- “OKJHX*Ucy76xT8cXCxcSDr”
- Third loader/dropper file hash:
- MD5: 4261bb4f43fdd9e02e93f501ad38f2a3
- SHA1: a6d86ccbb9ae98731c6666b1f8ad3e06ed645783
- Injected memory section (payload) of 3rd dropper process (in my case 0x7EF90000) hash:
- MD5: a43e8762c9e50007a9ea8139232ad6e8
- SHA1: a45ee1c45c50ccf6d2e5c0217f0aaa3c3bf6ebe3
- Hash Symbols of 3rd Loader/Dropper for Calling Function Addresses: 0x0AB48C65–0xDE604C6A — 0x925F5D71–0xEFD32EF6–0xB8E06C7D — 0x831D0FAA — 0xA62BF608–0x102DE0D9–0x7CD8E53D — 0x6815415A — 0xE7F9919F — 0x64C4ACE4
- CRC32 Hashes of Payload for Process Names: 0x99DD4432–0x2D859DB4–0x64340DCE — 0x63C54474–0x349C9C8B — 0x3446EBCE — 0x5BA9B1FE — 0x3CE2BEF3–0x3D46F02B — 0x77AE10F7–0xF344E95D — 0x2DBE6D6F — 0xA3D10244–0x1D72ED91–0x96936BBE — 0x278CDF58–0x3BFFF885–0x6D3323D9
- Existence of machine code (binary representation) of PUSH 0 and RET instruction inside payload for process injection inside msiexec.exe:
- 68 00 00 00 00 C3 00 00
- 68 00 00 00 00 = push 0x0
- C3 = ret
- Existence of MOV EDX, ESP — SYSENTER — RET instruction inside payload for transferring control to kernel (from ring 3 to ring 1)
- 8BD4 = mov edx, esp
- 0F34 = sysenter
- C3 = ret
- Calling Sandboxie application DLL by string: “sbiedll.dll”
- To see if payload is part of administrator group by using string: “S-1–5–32–544”
- Setting security descriptor of registry value to string: “D:(A;;KA;;;WD)”
- Creating new name for 3rd Loader/Dropper with String format: “ms%s.exe”
- Deleting Windows security services by using their strings: “wscsvc” — “SharedAccess” — “MpsSvc” — “WinDefend” — “wuauserv”
- Disabling task manager program by using string: “software\microsoft\windows nt\currentversion\image file execution options\taskmgr.exe”
- Infamous MD5 Hash in payload (go f%$# yourself): 754037e7be8f61cbb1b85ab46c7da77d
- Sending general information regarding victim’s system by using string format (bot registration to server): “id:%lu|bid:%lu|os:%lu|la:%lu|rg:%lu”
- Trying to call these export methods by using these strings: “aStart”, “aReport”, and “aUpdate”
- Downloading new malware by string format: “KB%08lu.exe”
- Sending report after every bot action by string format: “id:%lu|tid:%lu|err:%lu|w32:%lu”
Network-Based Signature
- 64.70.19.203 IP address from port 80 by TCP protocol under the hxxp://happysingh.ws
- Using “Mozilla/4.0” as browser agent, and “application/x-www-form-urlencoded” to post data.
References
- B. Sabouri, H. Xu, “A review of evolution of Andromeda over the years before we say goodbye”, 2018. [Online]. Available: https://www.virusbulletin.com/virusbulletin/2018/02/review-evolution-andromeda-over-years-we-say-goodbye/ [Accessed: 25- July- 2020].
- H. Xu, “A good look at the Andromeda botnet”, 2013. [Online]. Available: https://www.virusbulletin.com/virusbulletin/2013/05/good-look-andromeda-botnet [Accessed 28- July- 2020].
- Avast Threat Intelligence Team, “Andromeda under the microscope”, 2016. [Online]. Available: https://blog.avast.com/andromeda-under-the-microscope [Accessed: 26- July- 2020].
- S. De Souza, “Andromeda 2.7 features”, 2013 [Online] Available: https://www.virusbulletin.com/virusbulletin/2013/08/andromeda-2-7-features/ [[Accessed: 28- July- 2020]
- OALabs, Unpacking Princess Locker and Fixing Currupted PE Header (OALabs x MalwareAnalysisForHedgehogs), Apr 8, 2018, Accessed on: Sept, 7, 2020, [Streaming video]. Available: YouTube
- Process Library, “sbiedll.dll” [Online]. Available: https://www.processlibrary.com/en/directory/files/sbiedll/401139/ [Accessed: 16- Sept- 2020]
- Group Policy, “Turn off all balloon notifications” [Online]. Available: https://getadmx.com/?Category=Windows_10_2016&Policy=Microsoft.Policies.TaskBar2::TaskbarNoNotification [Accessed: 17- Sept- 2020]
- Group Policy, “Remove the Security and Maintenance icon” [Online]. Available: https://getadmx.com/?Category=Windows_10_2016&Policy=Microsoft.Policies.TaskBar2::HideSCAHealth [Accessed: 17- Sept- 2020]
- Microsoft, “EnableLUA” [Online]. Available: https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-lua-settings-enablelua [Accessed: 17- Sept- 2020]
- Superuser, “What is the difference between the ShowSuperHidden and SuperHidden registry values?” [Online]. Available: https://superuser.com/questions/1240383/what-is-the-difference-between-the-showsuperhidden-and-superhidden-registry-valu [Accessed: 17- Sept- 2020]
- Microsoft, “MoveFileExW function (winbase.h)” [Online]. Available: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexw [Accessed: 20- Sept- 2020]
Programs that are used in this project:
[i] — https://www.virtualbox.org/
[ii] — https://docs.microsoft.com/en-us/sysinternals/downloads/strings
[iii] — https://mh-nexus.de/en/hxd/
[iv] — https://www.aldeid.com/wiki/PEiD
[v] — http://ntinfo.biz/index.html
[vi] — https://hshrzd.wordpress.com/pe-bear/
[viii] — https://www.hex-rays.com/products/ida/
[ix] — https://cutter.re/
[x] — https://ghidra-sre.org/
[xi] — https://docs.microsoft.com/en-us/sysinternals/downloads/procmon
[xii] — https://processhacker.sourceforge.io/
[xiii] — https://docs.microsoft.com/en-us/windows/client-management/troubleshoot-tcpip-netmon
[xiv] — https://github.com/fireeye/flare-fakenet-ng
[xv] — https://x64dbg.com/
[xvi] — https://www.ollydbg.de/
[xvii] — https://www.immunityinc.com/products/debugger/
[xviii] — https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-download-tools
[xix] — https://www.virustotal.com
[xx] — https://www.hybrid-analysis.com/
[xxi] — https://github.com/OALabs/BlobRunner
[xxii] — https://www.python.org/downloads/release/python-2718/