AutoIT Malware. A detailed analysis

 

This is a sample that came to my hands by a spam campaign, and caught in a corporate honeypot. Make a comment under this post with your email if you want a sample.

Sorry for some false positive AV alarms while browsing this post.. It was due to some code listings. I removed the AutoIT script, but it can be found here: https://www.dropbox.com/s/xu1ra236lx8n5dc/clean.au3?dl=0 .

~ Due to big amount of requests, I uploaded the sample here too. Pass is “malware” ~
Here is an overview of what you’re going to see in this post:

1) First malware file: .exe
– recognition of the executable’s type (WinRAR SFX)

2) Drops: update.exe + 3 files
– recognition of the dropped PE (AutoIT), and obfuscated AutoIT script
– making a custom python script of script de-obfuscation
– Clear AutoIT script analysis, methods and some thoughts about it.

3) LoadPE method (by the AutoIT script) using an encrypted drop
– making a custom script to decrypt the drop (RC2 encrypted usign CryptoAPI)
– analysis of the final malware. What data does it collect, which format, how does it send them and where.
– reveal some console log messages of the app by just changing it’s IMAGE_SUBSYSTEM byte from PE Header

..so let’s go..

 

1) First malware file

The mail attachment, contained this file. An executable with a custom icon. After a fast static analysis, it is recognised to be a WinRAR SFX executable with some dummy comments.

 

Mail attachment is a WinRAR SFX

Mail attachment is a WinRAR SFX

WinRAR SFX Contents

WinRAR SFX Contents

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Executing the SFX, drops those 4 files in %userprofile%yzvf382a42256 with hidden and system attributes. Then, the update.exe file is being executed.
Notice the BIG file in the sfx file.. 331MB file with .PBS extension

 

2) Drops: update.exe and other 3 files..

First of all, with a fast static analysis (strings and resources) update.exe seems to be the AutoIT script interpreter. For those who know about AutoIT, the executable’s icon witnesses the AutoIT existence.

VirusTotal gives a result of 1/55. File checksums:

File: update.exe
CRC-32: fe38fa90
 MD4: acf237cc711fefbac32631546d878a0a
 MD5: 6a93a4071cc7c22628af40a4d872f49b
 SHA-1: ba916e686aa0cae19ab907bdab94924ada92b5f4

So there is an interpreter, and there must be the source file to execute.. Searching the 3 files, the AutoIT script file is jqanjzruzb.PBS … The 331MB file. Opening the file we can see (after the time of editor’s stack time 😛 ) that the script is there.. but we can’t clearly see and analyse the source cos of many tab characters, and dummy comments! Author probably used that method as a type of obfuscation for the script file.

I made a python script to “deobfuscate” that AutoIT script source of 331MB .. It counts and removes the tab chars, recognises and removes the “dummy comment” and some dummy new lines.. Python script receives as argument 1) the AutoIT obfuscated file (the big one) and 2) the new file of the clear/deobfuscated script. Then the result is a clear AutoIT source script. The python script that deobfuscates the file, is this:

import sys, os

def progress(n, total):
	sys.stdout.write("r[+] Cleaned: %d%%" % (n*100/total))
	sys.stdout.flush()
def remove_from_list(string_to_remove, list):
	while True:
		try:
			list.remove(string_to_remove)
			# print ".",
		except:
			# print "done"
			break
def clean_from_dummystring_newlines(dummyfilename, newfilename):
	f = open(dummyfilename)
	with f as lines:
		content = lines.readlines()
	f.close()

	for mem in content:
		string_to_remove  = mem
		print "n[+] dummy string to be removed, seems to be: "+string_to_remove
		break

	if content.count(string_to_remove) > 10:
		# print "String to be removed, seems to be: ""+string_to_remove+"""
		remove_from_list(string_to_remove, content)
	if content.count(' n') > 5:
		print "[+] Removing " \n""
		remove_from_list(" n", content)

	f = open(newfilename, 'wb')
	f.write(''.join(content))
	f.close()

info = os.stat(sys.argv[1])		# get file size
filesz = info.st_size

f = open(sys.argv[1], 'rb')		#.. now open file to read
l = open(sys.argv[2], 'wb')

b = f.read(1)
datatowrite = ""

list1 = []
i = 0
k = 0
print "n[+] cleaning the tab chars.."
while b != '':			# read file till EOF.. 🙂
	while b == 't':	# tabs are the chars i want to ignore...
		i += 1
		k += 1
		b = f.read(1)
	if i>0:
		# print "There were "+str(i)+" tabs.."
		if i<10:		# writeable tabs
			for j in range (0,i):
				datatowrite = 't'
				l.write(datatowrite)
		i = 0
	progress(k, filesz)					# give progress status
	if b == 'n':						# write n to file...
		# print "NL"
		k += 1
		datatowrite = 'n'
		l.write(datatowrite)
	elif b == 'r':						# write r to file
		# print "CR"
		k += 1
		datatowrite = 'r'
		l.write(datatowrite)
	else:
		while b >= ' ' and b <= '}':	# printable char? write it..
			k += 1
			list1.append(b)
			b = f.read(1)
		# print "".join(list1)
		datatowrite = ''.join(list1)	# write to file
		l.write(datatowrite)
		list1 = []
	b = f.read(1)
f.close()
l.close()

# Now clean a bit more.. clear the 1) dummy comment strings and 2) the dummy new lines.
clean_from_dummystring_newlines(sys.argv[2], sys.argv[2])
print "Done!"

 

The script file before deobfuscation is 331MB and looks like this in the AutoIT editor (notice the scrollbar):

AutoIT script with tabs.In the original state

AutoIT script with tabs.In the original state

 

 

 

 

 

 

 

 

 

This is how the deobfuscation is done (i call the script clean_script.py) and lasts about 6 minutes:

python cleaner command line args

python cleaner command line args

 

 

 

 

After the "clean" operation, the clean file is 55kbyte in size! And has the following contents:

File has been removed due to false positives from AVs! Sorry..
Uploaded here for everyone who is interested:
https://www.dropbox.com/s/xu1ra236lx8n5dc/clean.au3?dl=0

..a bit of AutoIT script analysis

There is a lot of source code in this script, lot of functions, and huge functionality. The most important sections, is where the script "decides" which will be it's functionality, how does it protect itself (persistence, process protection), what is it's main functionality and how does it communicate with the cybercriminals.

First of all we have to analyse the other dropped files...! There are total 4 files dropped by the SFX. The one is the update.exe (AutoIT interpreter) the other is the above script, and the other two not mentioned yet.. Well here they are:

1) oziryzkvvcpm.AWX - which has a small size, looks like an INI file.. probably some settings recognised by the AutoIT script.
2) sgym.VQA - a binary with random data.. Maybe another encrypted malware executable/payload !

The INI file looks like this:

[8472254]
7345448=2738636
[5152433]
7790268=6953219
[5242747]
1024020=8930731
[9537477]
9537477=yzvf382a42256

If you notice the AutoIT script, you'll see these lines concerning the main script functionality:

.....
.....
Local $startup = IniRead($uniscriptdir & "oziryzkvvcpm.AWX", "5242747", "1024020", "NotFound")
If $startup = "8930731" Then
	startup()
Else
EndIf
Local $antis = IniRead($uniscriptdir & "oziryzkvvcpm.AWX", "antis1", "antis2", "NotFound")
If $antis = "antis3" Then
	antis()
Else
EndIf
.....
$protectprocess = IniRead($uniscriptdir & "oziryzkvvcpm.AWX", "8472254", "7345448", "NotFound")
If $protectprocess = "2738636" Then
	AdlibRegister("anti_hook", 500)
.....
Local $persistence = IniRead($uniscriptdir & "oziryzkvvcpm.AWX", "5152433", "7790268", "NotFound")
If $persistence = "6953219" Then
	checkvbs()
	AdlibRegister("persistence", 500)
Else
EndIf
......
Func submain()
	$skey = IniRead($uniscriptdir & "oziryzkvvcpm.AWX", "9537477", "9537477", "NotFound")
	$sapppath1 = FileGetShortName(@ScriptDir & "sgym.VQA")
	$sapppath = FileRead(FileOpen($sapppath1, 16))
	$sarquive = _crypt_decryptdata($sapppath, $skey, $calg_rc2)
	Local $commandline = IniRead($uniscriptdir & "oziryzkvvcpm.AWX", "commandline1", "commandline2", "NotFound")
	If $commandline = "commandline3" Then
	_runpe($sarquive," command-replace")
	Else
	_runpe($sarquive)
	EndIf
EndFunc
....

Above you see the code that is responsible for reading the INI file oziryzkvvcpm.AWX which decides for the AutoIT functionality. The example above, shows what does those INI sections mean.

- The 5242747 section means persistence. The malware calls the startup function which adds the classic registry key for system startup (HKCU64SoftwareMicrosoftWindowsCurrentVersionRunOnce) and a shortcut to Start menu -> Programs -> Startup.
- The antis1 section is not present in the INI file, meaning that the antis function will not be executed. It means anti-protections. Like VM protections etc. It is an example of the many functionalities, which is not used in this malware!
- The 8472254 section means bsod anti-hook/process protection method! This functionality, sets the AutoIT executable as a critical section, and if it is killed, we have a bsod. This method is used for process protection by lot of malware authors. Detailed method can be seen here.
- The 5152433 section means that the AutoIT executable will check for the vbs script (which is dropped by this AutoIT script, and used to run the update.exe giving as argument the AutoIT script) existence, and also checks/adds the registry persistence keys.
- The 9537477 section contains a decryption key! If you follow the function _crypt_decryptdata you'll recognise that there are calls to Windows CryptoAPI and decrypts the sgym.VQA file using RC2 algorithm, and key the string "yzvf382a42256" taken from the ini file (which is also the name of the malware's folder). The decrypted file is probably a PE cos later in code, it injects it in memory (LoadPE method) of another process (RegSvcs.exe, RegAsm.exe, etc)

Let's make sure that the final file sgym.VQA is an encrypted executable.. The fast way to recognise that, is Ollydbg. We have to break in the correct point (breakpoint on CryptDecrypt function of advapi32.dll) of the process update.exe (the interpreter of the above AutoIT script AFTER the malware is running.) while the malware is running (update.exe with "jqanjzruzb.PBS" argument)

Notice: Our goal is to reverse the malware.. NOT the AutoIT interpreter!

This is the point where Olly breaks while the AutoIT script is running, and CryptDecrypt is called to decrypt the potential encrypted malware from sgym.VQA file:

When olly breaks on CryptDecrypt API

When olly breaks on CryptDecrypt API

 

 

 

 

 

 

 

The 5th argument of CryptDecrypt is the most interesting, it is the buffer containing the crypted data. Also the 6th arg contains the length of the encrypted data, and after the function returns, it will contain the length of the decrypted data. When we have a break (before the decryption) the size is 0x6F008 what means 454664 in decimal, which is the exact size of the sgym.VQA file. We are sure that it will be decrypted after the call! After pressing CTRL-F9 in Ollydbg :

After CryptDecrypt Decrypts the data..

After CryptDecrypt Decrypts the data..

 

 

 

 

 

 

 

 

 

 

And yes it's a PE..! The first thing is to dump it from Olly memory. It will work that way. It is a .NET executable.. I made an AutoIT script which will decrypt the sgym.VQA file from disk. I ripped some code from the malware's AutoIT script, and read some functions from the official AutoIT site for their functions and finally made the decryption script. It reads the encrypted filename given in a global var, and writes the decrypted file data in a filename given in a global var too. In order to run the script you have to download AutoIT from here and give the correct in/out filenames in globals to the following script (change "encrypted.bin" to "sgym.VQA" to match this case) :

Global Const $calg_rc2 = 26114
Global Const $calg_rc2 = 26114
Global Const $prov_rsa_full = 1
Global Const $crypt_exportable = 1
Global Const $calg_md5 = 32771
Global Const $crypt_userdata = 1
Global Const $prov_rsa_aes = 24
Global $__g_acryptinternaldata[3]
Global Const $crypt_verifycontext = -268435456
Global Const $calg_userkey = 0
Global $skey = "yzvf382a42256"
Global $encrypted_filename = "encrypted.bin"
Global $decrypted_filename = "decrypted.bin"

submain()

Func __crypt_dllhandleset($hadvapi32)
	$__g_acryptinternaldata[1] = $hadvapi32
EndFunc
Func __crypt_refcount()
	Return $__g_acryptinternaldata[0]
EndFunc
Func __crypt_refcountinc()
	$__g_acryptinternaldata[0] += 1
EndFunc
Func __crypt_contextset($hcryptcontext)
	$__g_acryptinternaldata[2] = $hcryptcontext
EndFunc
Func __crypt_context()
	Return $__g_acryptinternaldata[2]
EndFunc
Func __crypt_dllhandle()
	Return $__g_acryptinternaldata[1]
EndFunc
Func _crypt_startup()
	If __crypt_refcount() = 0 Then
		Local $hadvapi32 = DllOpen("Advapi32.dll")
		If @error Then Return SetError(1, 0, False)
		__crypt_dllhandleset($hadvapi32)
		Local $aret
		Local $iproviderid = $prov_rsa_aes
		If @OSVersion = "WIN_2000" Then $iproviderid = $prov_rsa_full
		$aret = DllCall(__crypt_dllhandle(), "bool", "CryptAcquireContext", "handle*", 0, "ptr", 0, "ptr", 0, "dword", $iproviderid, "dword", $crypt_verifycontext)
		If @error OR NOT $aret[0] Then
			DllClose(__crypt_dllhandle())
			Return SetError(2, 0, False)
		Else
			__crypt_contextset($aret[1])
		EndIf
	EndIf
	__crypt_refcountinc()
	Return True
EndFunc
Func _crypt_derivekey($vpassword, $ialg_id, $ihash_alg_id = $calg_md5)
	Local $aret
	Local $hcrypthash
	Local $hbuff
	Local $ierror
	Local $vreturn
	_crypt_startup()
	Do
		$aret = DllCall(__crypt_dllhandle(), "bool", "CryptCreateHash", "handle", __crypt_context(), "uint", $ihash_alg_id, "ptr", 0, "dword", 0, "handle*", 0)
		If @error OR NOT $aret[0] Then
			$ierror = 1
			$vreturn = -1
			ExitLoop
		EndIf
		$hcrypthash = $aret[5]
		$hbuff = DllStructCreate("byte[" & BinaryLen($vpassword) & "]")
		DllStructSetData($hbuff, 1, $vpassword)
		$aret = DllCall(__crypt_dllhandle(), "bool", "CryptHashData", "handle", $hcrypthash, "struct*", $hbuff, "dword", DllStructGetSize($hbuff), "dword", $crypt_userdata)
		If @error OR NOT $aret[0] Then
			$ierror = 2
			$vreturn = -1
			ExitLoop
		EndIf
		$aret = DllCall(__crypt_dllhandle(), "bool", "CryptDeriveKey", "handle", __crypt_context(), "uint", $ialg_id, "handle", $hcrypthash, "dword", $crypt_exportable, "handle*", 0)
		If @error OR NOT $aret[0] Then
			$ierror = 3
			$vreturn = -1
			ExitLoop
		EndIf
		$ierror = 0
		$vreturn = $aret[5]
	Until True
	If $hcrypthash <> 0 Then DllCall(__crypt_dllhandle(), "bool", "CryptDestroyHash", "handle", $hcrypthash)
	Return SetError($ierror, 0, $vreturn)
EndFunc
Func _crypt_decryptdata($vdata, $vcryptkey, $ialg_id, $ffinal = True)
	Local $hbuff
	Local $ierror
	Local $vreturn
	Local $htempstruct
	Local $iplaintextsize
	Local $aret
	_crypt_startup()
	Do
		If $ialg_id <> $calg_userkey Then
			$vcryptkey = _crypt_derivekey($vcryptkey, $ialg_id)
			If @error Then
				$ierror = 1
				$vreturn = -1
				ExitLoop
			EndIf
		EndIf
		$hbuff = DllStructCreate("byte[" & BinaryLen($vdata) + 1000 & "]")
		DllStructSetData($hbuff, 1, $vdata)
		$aret = DllCall(__crypt_dllhandle(), "bool", "CryptDecrypt", "handle", $vcryptkey, "handle", 0, "bool", $ffinal, "dword", 0, "struct*", $hbuff, "dword*", BinaryLen($vdata))
		If @error OR NOT $aret[0] Then
			$ierror = 2
			$vreturn = -1
			ExitLoop
		EndIf
		$iplaintextsize = $aret[6]
		$htempstruct = DllStructCreate("byte[" & $iplaintextsize & "]", DllStructGetPtr($hbuff))
		$ierror = 0
		$vreturn = DllStructGetData($htempstruct, 1)
	Until True
	Return $vreturn
EndFunc
Func submain()
	$sapppath = FileRead(FileOpen($encrypted_filename, 16))
	$sarquive = _crypt_decryptdata($sapppath, $skey, $calg_rc2)
	FileWrite(FileOpen($decrypted_filename, 10), $sarquive)
EndFunc

 

 

3) Analysis of the final decrypted PE

VirusTotal gives a result of 29/54 today. A static analysis results in an unpacked executable, compiled with .NET containing many interesting strings and .NET functions/classes (via IDA Pro) which gives us the impression of a monitoring tool cos of the extended functionality (ripper of many apps/browsers etc, keystroke hooker, ..).

Final PE VT results

Final PE VT results

 

 

 

 

 

 

 

 

 

 

checksums of the file:

CRC-32: 1c2ff510
   MD4: 05054bf759e18a9e11ed036a5f5818b9
   MD5: dae4bc7cf2df5e00e8f8cbdeba9b9976
 SHA-1: 8115c1b03e3d7372b74f415e50db0069a2bcc1fc

The tool is the commercial Keylogger named "Limitless Logger" and here seems to be it's site (author ended the product's support). Here is a video explaining the functionality of the tool by the tool's autor (Mephobia). In the video we can see it's whole functionality, which explains everything about the classes/functions we see in IDA . Here is a sample random shot from IDA showing the product's banner:

Limitless Logger in IDA

Limitless Logger in IDA

 

 

 

 

 

 

 
While I was exploring the tool's code, I noticed that there are plenty of console messages, even if the app is compiled for windows gui. For example:

A console WriteLine proof. The app has console messages

A console WriteLine proof. The app has console messages

 

 

 

 

 

 

 

 

In order to see those console messages, let's change the PE Header byte from Windows GUI to Console app as shown in the pic:

Changing the IMAGE_SUBSYSTEM byte so I can see the console messages

Changing the IMAGE_SUBSYSTEM byte so I can see the console messages

 

 

 

 

 

 

 

 

 

 

...and yes here they are... Limitless Logger has full console messages on every single step.. :

Console messages of Limitless Logger, after changing the IMAGE_SUBSYSTEM byte from PE Header

Console messages of Limitless Logger, after changing the IMAGE_SUBSYSTEM byte from PE Header

 

 

 

 

 

 

 

 

 

 

 

 

After setting ApateDNS pointing to a Linux INetSim honeypot (inetsim's SMTP had to be set up to port 587 instead of 25), I sniffed a whole conversation of the .Net tool's traffic and the SMTP server (the tool sends the data to the cybercriminal via mail - smtp to address "[email protected]"). Depending on the user's settings, the tool sends several feedbacks about the keystrokes of the user, screenshots, recovery data (saved passwords from several applications/browsers). This is a sample of the smtp communication data sniffed, and DNS requests made by the tool:

Limitless Keylogger TCP Stream 1

Limitless Keylogger TCP Stream 1

Limitless Keylogger TCP Stream 2

Limitless Keylogger TCP Stream 2

 

 

 

 

 

 

 

 

 

 

 

 

Limitless Keylogger DNS requests

Limitless Keylogger DNS requests

 

 

 

 

 

The tool, in the 1st tcp stream uses totaly base64 encoded data, what doesn't happen in the 2nd stream. The SMTP used is yandex.ru (also shown in the DNS reqs) without providing password 😀 .Also bot.whatismyipaddress.com is used so the tool can get our inet global ip address in plaintext format, and also the ebis.pro is used cos of web spam using our default browser (there is a setting for that, in the tool's video)

Between "Sleep()" there is a nag web page (the guy compiled the Limitless Logger to visit the site: www.ebis.pro/images/invoice_img.png) which is an invoice corresponding the body of the spam campaign ("..you have to pay a bill.. etc" :D) :

fake invoice nag page

fake invoice nag page

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Final Thoughts

The guy who made the spam campaign in order to infect a victim with all these, obviously did it in the AutoIT way cos of FUDing from a static analysis.. Update.exe is a legit interpreter, text files (autoit script) are not detectable by AVs, and so the completely random data do (sgym.VQA - the Limitless Logger RC2 crypted PE). The method had lot of probs.. AVs will detect the drop of the .vbs scripts and behaviour of the processes (update.exe, RegSvcs.exe, ..). The starting functionality of the malware is in a pseudo-obfuscated plaintext file, where it can easily get back in clear state and we can discover the whole functionality. Probably most of the parts of this AutoIT script, are taken from their forum where there are discussions about process injections etc, and there are exactly the same snippets of code (even the comments of the script are the same). Also there are lot of functions that are not used. For example the "antis" functions, where there were some anti-vm code. Also we can see that the guy if the case here, used an open relay smtp server (yandex.ru) which seems that changed policy, cos server can't let you relay messages in unencrypted format, even if the authentication is successful.

 

If we de-base64 the traffic send by the Limitless Logger via mail, and search the pattern in google, you can find some interesting things.. 😀

google-res-lk

Some bad guys forgot their keylogger logs in public!

 

 

 

 

 

Tagged , , , , , , , , , . Bookmark the permalink.

33 Responses to AutoIT Malware. A detailed analysis

  1. An0n says:

    Hi,

    Could you please to provide me the sample files ? Thanks

    Best Regards,

  2. Pingback: AutoIT Malware. A detailed analysis / 133tsec.c...

  3. Sanshis says:

    Excellent!!
    can i get these samples??

  4. r00tr4ptor says:

    wooow sick work man… 🙂
    a big ty for all guys on world who didn’t know or recognized ur big work!

    take care

  5. r00tr4ptor says:

    – for + from

  6. Devilin Pixy says:

    Hmmm, next to some well known video/chat services like Facebook and Skype as well as some lesser known ones, I noticed Steam/Runescape/UAC to be part of it.

    Very nice and interesting analysis.

  7. bkbilly says:

    hi, Can I also have a sample of the files?
    Thanks!

  8. Mahsa says:

    Nice work.
    Could I have the sample files please?

    Thanks in advance

  9. 0xm3110c says:

    Very interesting.. Could I have the sample files please?

  10. paul says:

    thanks for the mighty interesting read and research!!

  11. 0xm3110c says:

    @0xm3110c I didn’t see that was in the post. sry!

  12. FreeMoon says:

    Amazing work man!!!
    Very impressive!!
    If you’re interested about reversing mips ELF contact me, i have something interesting for you 🙂

  13. Michal Balito says:

    Thank you for sharing your interesting research to us, Could you provide me this sample file please.. ?? 🙂

  14. Pingback: Limitless Keylogger Optimized with AutoIT Infected thousands of Computers - Social News Dashboard

  15. Pingback: A new breed of Malware - AutoIT Malware. - BAS

  16. Pingback: AutoIT Malware infected thousands of computers worldwide | Security Affairs

  17. Pingback: Limitless Keylogger Optimized with AutoIT Infected thousands of Computers - Meta Thrunks Security Blog

  18. Pingback: Última amenaza Limitless Keylogger, un malware que afecta a miles de usuarios de Windows | NOTICIAS JURÍDICAS Y SEGURIDAD INFORMÁTICA

  19. execB33F says:

    I am researching this as well and would appreciate samples. Thanks!

  20. Pingback: AutoIt木马第二发:键盘记录木马分析 - FreeBuf.COM

  21. Pingback: AutoIt木马:键盘记录木马分析[转] | 进无止境

  22. Pingback: Limitless Keylogger Optimized with AutoIT - shell {&} co

  23. kai says:

    I’m a junior analyst and am trying to learn as much as I can! Thanks for the research! Can I get the sample as well? Thanks again!

  24. clikken03 says:

    Can you send me a copy of your finding please..

    Thank you.

  25. John says:

    Great job man!
    Can you please send me a sample ?
    Thanks!

  26. Pingback: ΑΠΟΚΛΕΙΣΤΙΚO: Έλληνας ανεξάρτητος αναλυτής “αποκωδικοποίησε” malware υποκλοπής δεδομένων! | Streetdailynews

  27. dev says:

    Great!
    Can you please send me a sample ?
    Thanks!

  28. pallavi says:

    Hi,
    Can you please provide sample for analysis

Leave a Reply

Your email address will not be published. Required fields are marked *