11 minutes
SpyEye Malware Analysis
PS: If anyone still have a copy of the SpyEye builder, send me a copy. Thank you !
Executive Summary
SpyEye is a spyware and banking Trojan that was sold as a kit in dark market forums. During its activity period, it has been widely spread and very dangerous. It presented itself as a competitor to the well-know Zeus. This malware is capable of keylogging, form grabbing, ftp and pop3 credential stealing and input fields injection.
Technical Analysis
Static analysis
Characteristics
File type : 32-bit PE Executable
Hash :
- MD5: 4FCF540BD465177EE03E6D798AD162F0
- SHA256: 2cc636f4a1e76bd05ddc3c4cbdc8b2b848424d0114
Interesting Strings
Let’s start first by checking the strings we could extract from the sample. We could easily have a good initial idea as to what functionalities this malware provides.
Strings
__CLEANSWEEP__
LdrLoadDll
4C027B88159814E410BB0F23FB0F7DC6
urlmon.dll
shlwapi.dll
wininet.dll
TranslateMessage
user32.dll
HttpSendRequestW
HttpSendRequestA
InternetCloseHandle
PR_Write
send
wsock32.dll
mpr.dll
ws2_32.dll
msvcrt.dll
nspr4.dll
*%s*
__CLEANSWEEP__
%s%s
LdrLoadDll
NtResumeThread
NtEnumerateValueKey
NtVdmControl
NtQueryDirectoryFile
POST %s HTTP/1.1
Host: %s
Connection: close
Content-Type: multipart/form-data; boundary=%s
Content-Length: %d
55377776816118
--%s--
--%s
Content-Disclass: form-data; name="%s"
User-Agent:
language_id
os_version
%d.%d.%d
tick_time
timezone
local_time
bot_version
bot_guid
keys
func_data
hooked_func
process_name
CONNECT
OPTIONS
TRACE
DELETE
POST
HEAD
LdrLoadDll
%s!%s!%08X
%08X
User
Admin
ONLINE
ccrc=
cpu=
rep=
tid=
stat=
ver=
guid=
KNOCK-COMPLETE
KNOCK-ERROR
KNOCK
LOAD-COMPLETE
LOAD-ERROR
LOAD
COMPLETE
ERROR
data from server is: %s
ACTIVE
FILL
UPDATE_CONFIG
PATH
UPDATE
A%s%s\%s
%s\ntdll.dll
__CLEANSWEEP_RELOADCFG__
__CLEANSWEEP_UNINSTALL__
TASK IS OK
Empty link
Error: Empty report. Unknown error. 0o
Error: Thread is really sloppy
Error: Cannot create thead. 0o
TASK IS OK :
%s?page=%s
Software\Microsoft\Internet Explorer
Version
nInternet Explorer
Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\2
name
class
style
innerHTML
innerText
*call*event*
call_event
onclick
target
_top
href
American Express
Visa
MasterCard
Discover
Fatal error! Runtime exception! 0_0
Unknown answer. 0_o (title of page: "%s")
Cannot find title on Second page. 0_o
Unknown title: "%s". 0_o
*Order Submitted*
*Order Complete*
body
*Order Error*
text
title
*Continue*
table
*Error *
Cannot find submit stuff on first page. 0_o
Cannot find Copies stuff on first page. 0_o
Copies
Cannot find CardExpire stuff on first page. 0_o
CardExpire
Cannot find CardNumber stuff on first page. 0_o
CardNumber
Cannot find CardType stuff on first page. 0_o
CardType
Cannot find Phone stuff on first page. 0_o
Phone
Cannot find EMail stuff on first page. 0_o
EMail
Cannot find BillingCountry stuff on first page. 0_o
select
BillingCountry
Cannot find BillingPostal stuff on first page. 0_o
BillingPostal
Cannot find BillingState stuff on first page. 0_o
BillingState
Cannot find BillingCity stuff on first page. 0_o
BillingCity
Cannot find BillingAddress stuff on first page. 0_o
BillingAddress
Cannot find Company stuff on first page. 0_o
Company
Cannot find Name stuff on first page. 0_o
input
Name
value
Smth wrong with navigate to BILLING-PAGE. 0_o
Smth wrong with navigate to BILLING-PAGE (err code: %d). 0_o
Smth wrong with navigate to REF-PAGE (err code: %d). 0_o
Cannot increase history
link
Cannot detect card type. 0_o
"(%s")
Smth wrong with input-data. 0_o
4C027B88159814E410BB0F23FB0F7DC6
4C027B88159814E410BB0F23FB0F7DC6
4C027B88159814E410BB0F23FB0F7DC6
Internet Explorer
config.datUT
(UTC%s%2.2f) %s
\BaseNamedObjects\__CLEANSWEEP_REPALREADYSENDED__
@onbeforeunload
%s\ntdll.dll
cleansweep.exe
%s%s
%s\%s
CONFIG
\??\%s:\%s\%s
config.bin
LdrLoadDll
kernel32.dll
ntdll.
NTDLL.
IAT
The number of imported functions is very suspicious. Considering the number of extracted strings and the regularity of the sections, the binary is not packed. Thus, the very low number of imported functions could be an indicator of dynamic API loading which we’ll discuss in the Detailed Specifics section.
Imported Functions
memset
lstrcmpiA
wcscat
wcscpy
strstr
strlen
_strlwr
strcpy
Behavioural analysis
Initial execution
The entry point of the malware basically gets the OS version and exits if it’s older than Windows 2000. Else, a covert execution of the main function is done using EnumTimeFormatsA.
The main function is pretty simple. It makes sure that only one instance of the malware is running on the victim by checking for a Mutex. If it exists, the function exits. Else, It is created and execution continues. It then starts dropping the main payload which is formed of a stage2 executable and a config.bin configuration file (contained in the .rsrc section).
The stage2 executable and the configuration file are dropped in a newly created directory named cleansweep.exe (which is also the name of the executable ) in the root of the primary volume. The filetime of the dropped directory and its file is set to match the creation time of ntdll.dll.
Stage2 Execution
After dropping all the necessary files to the right directory, the stage1 dropper (Or the injected code if successful) runs the stage2 executable named cleansweep.exe . It first checks as usual for the OS version and exits if it’s older than Windows 2000 . Then, it creates a Mutex to make sure that the victim is only infected once (This is important considering that SpyEye is sold as a kit to prevent attackers infecting the same machine). The implant considers two cases, it’s either ran from the standard directory or not. If not, a new executable is downloaded from the C2 named cleansweepupd.exe which serves as an updater for the implant.
Let’s now consider the normal execution flow ie. the implant being ran from its default location. The initial operations of this main function are simple : It first checks if an updater executable exists and deletes it, parses the config file to extract the C2 server and then, being run from the default location, runs the function that contains the primary malicious functionalities (Using process injection discussed later).
Starting from this function, things start getting a little more complicated. This is because it hides behind it all the capabilities implemented in this implant and because it’s divided to various threads each one taking care of a certain functionality. As usual, It creates a Mutex but it doesn’t check if it already exists. This is because various injected versions could be ran at the same time and the Mutex is only used to prevent further infection. A thread listening for an uninstall Mutex is also set up to make sure the main Mutex is closed in case of uninstall.
Then, a persistence function is ran to make sure the malware survives system shutdown (this is to be discussed later).
Having these details set up, the malware then starts an initialisation sequence that is injected in every possible process. This function is so important as it sets the API hooks and then creates another listening thread that:
- Listens for a configuration reload Mutex, and if it exists, re-parses the config file considering a new version has been downloaded.
- As usual, listens for for the uninstall Mutex and if it exists, it exits the loop, closes the concerned Mutex and then unregisters the API hooks. You’ll notice this is a recurring pattern for every thread and Mutex.
After having the initialisation function injected in every possible process, main C2 communication is finally established. It initially sends victim metadata and identifying information and then launches an infinite loop that processes server commands. This is also made using the same pattern, the C2 communication is ran in a separate thread and an uninstall listener is created to kill that thread in case of uninstall.
And finally, the malware checks if it’s injected inside explorer.exe, if that’s the case, it creates a thread the attempts to inject the initialisation function in new processes and another uninstall listening thread to terminate it.
Persistence
For persistence, the malware uses a pretty simple technique. It sets itself as a startup executable using the Run registry key.
Capabilities
Form grabbing
One of the most important capabilities of this malware is form grabbing. This is implemented through hooking of nearly all the network functions (even firefox’s PR_Write) usually used by browsers to intercept forms as they’re being sent and grab their content.
Keylogging
By hooking the translateMessageA function, the malware have the ability to log every keystroke before it gets processed by the concerned window procedure. This could result in various vulnerabilities such as credential stealing and personal information leaks.
FTP and POP3 Credential stealing
The malware hooks the send API and checks if the protocol used is either ftp or pop3, if that’s the case, it logs the credentials and the URL and sends them back to the C2 server.
Detailed specifics
Process injection
Process injection is a very important technique for this malware. In fact, various components rely heavily on it. The dropper attempts to use it to run the dropping function and runs it itself if it fails. The stage 2 executable could only execute its main function through injection, else it simply exits. Later on, the initialisation function that contains API hooking and configuration reload listener is injected in every possible process, and this is what allows many capabilities to be feasible. I think the idea is clear, without process injection, this malware is useless in its current format. So, how does it implement it. First, a snapshot of all the system processes is taken. Then, it starts iterating over each process of this snapshot. It checks first if this process is one of 3 system processes or if it’s the malware itself, if that’s the case, it gets ignored. Else, it attempts to open the process using ntOpenProcess first or OpenProcess if the latter fails. If one of these succeeds, the function the attempts injecting the intended function. To simplify it, this is done by allocating a region in the victim memory using VirtualAllocEx, setting the right permissios usinf VirtualProtectEx and then copying the necessary code using VirtualWriteMemory. Finally, the Relocation table is fixed according to the newly injected code. And if this succeeds, a thread running the injected function is created using CreateRemoteThread.
API Hashing
Just like process injection, this malware relies heavily on API Hashing. In fact, nearly all imported function are dynamically loaded using this method, that’s why the IAT is suspiciously small. Twp API hashing functions are used in this malware : One for loading ntdll and kernel32 functions and the other for loading functions existing in the rest of the listed libraries. Their implementation is not that different and is simple. They both get a hash and a selection number as parameters. The selection number decides what DLL contains the wanted API. If the function is contained within ntdll.dll, the algorithm is directly executed. Else, LdrLoadDll is first dynamically loaded from ntdll.dll to load the needed DLL, and then the algorithm is executed to get the function address. The address of ntdll.dll is taken by parsing the PEB . Now for the algorithm itself : It first takes the handle of the module to load from and the function name hash. Then, it starts iterating over both the name pointer table and the pointer table (which are considered to be parallel arrays). It hashes and compares the name contained in the name pointer table with the supplied parameter, and if it matches, it calculates the function’s address using the ordinal table’s value and returns it. A Ghidra script is attached in the appendix to resolve API loaded by this method.
String Obfuscation
All the noticeable strings used in this malware are obfuscated and dynamically generated at runtime using a simple algorithm. each string is mapped to a value, this value is used to find the index of the string’s length in a predefined array and its obfuscated value in another array. Having both these values, the obfuscated string is retrieved and deobfuscated using a simple algorithm: Each character is subtracted with its preceding byte to retrieve its original value. A Ghidra script is attached in teh appendix to deobfuscate the strings.
API Hooking
Nearly all the capabilities implemented in the stage2 executable are based on function hooking. Keylogging is done by hooking TranslateMessageA, ftp and pop3 credential stealing is done by hooking send, form grabbing is done by hooking PR_Write in nspr4.dll for firefox and many other internet apis.
The hooking itself is pretty straightforward, the first 5 bytes of the hooked function are stolen, saved to a trampoline function in the hook and replaced by a jump to the malicious function, after it finishes its execution, the malicious function returns to the stolen bytes using the trampoline to allow the program to continue its normal execution flow. We could see the example of hooking TranslateMEssage in these photos :
Data Exfiltration
Various function hooks rely on data interception and exfiltration. This is made by calling an exfiltration function at the end of the interception that sends the process name, function name, data to be exfiltrated and logged keystrokes back to the C2 server.
MITRE ATT&CK Matrix
Appendix
Indicators of Compromise
Host-based
Type | IoC |
---|---|
File | cleansweep.exe |
File | cleansweepupd.exe |
File | config.bin |
Directory | cleansweep.exe |
Registry | [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run] “cleansweep.exe” : “C:\cleansweep.exe\cleansweep.exe” |
Mutex | __CLEANSWEEP__ |
Mutex | __CLEANSWEEP_RELOADCFG__ |
Mutex | __CLEANSWEEP_UNINSTALL__ |
Network-based
Type | IoC |
---|---|
Domain | www[.]microsoft-windows-security[.]com |
Domain | www[.]secureantibot[.]net |
URL | hxxp://www[.]microsoft-windows-security[.]com/software/updater3/bt_version_checker.php |
URL | hxxp://www[.]secureantibot[.]net/software/updater3/bt_version_checker.php |
HTTP Header | Content-Type: multipart/form-data; boundary=55377776816118 |
Yara rules
Ghidra scripts
Malware SpyEye Banking Trojan Zeus Card Fraud Process Injection API Hooking
2303 Words
30-05-2023 22:42