AutoIt3 nested dolls

I recently came across a post on Twitter referring to an AutoIt3 sample that apparently could not be decompiled using Exe2Aut and myAuToExe.

It triggered my interest.

It turns out that the file could be decompiled using Exe2Aut, but it is an AutoIt nested doll and has some mildly interesting anti-reversing features that require a bit more work than usual. Since these AutoIt3 nested dolls are becoming more and more common I describe below the process of breaking these apart and to do so I am using a sample I referred to earlier.

Note, I do not provide full analysis of the sample and files dropped or loaded inline and am mainly focusing on the AutoIt layers.

The sample in question is 597029DCB2738C17BE6D79814CDAF229.

Loading it into Exe2Aut actually works, but the resulting is a short Autoit3 script which is obfuscated.

$ee = "eWEpCwslF"
$dd = "OYTdreHl"
$test = "FileW"
$ketbha = "jZU"
...
$n = "GbVu"
Execute($test)

[full decompiled script is here]

AutoIt is an interpreted language and based on the code above we see that the script we have extracted using Exe2Aut builds another script (a snippet really).

In order to get the new script, we can analyze the code manually and figure out the content of the variable $test prior to execution (good luck with that!), or we can cheat and replace Execute statement shown above with a call to a FileWrite function:

FileWrite ("var_test", $test)

When you execute the script like this under AutoIt, you will get the interpreter to write the content of the $test variable to a ‘var_test’ file.

The content of the ‘var_test’ file is like this:
picSince the code is a bit messy, we can beautify it a bit:

pic2What happens here is as follows:

  • A new temporary file is created using a name stored in a variable $ee
  • The content of a new file comes from the original file
  • The content of a newly created file is found inside the original file by locating a marker (the marker is represented by a data stored in a variable $dd)
  • The function StringInStr is being used to find the aforementioned marker
  • The content stored in the original file contains a second marker ‘PLXL1’ which is replaced (before writing) with ‘AU3!EA06’ – replacing ‘PLXL1’ with ‘AU3!EA06’ suggests that the newly created temporary file is in fact a compiled AutoIt script (yet another one)
  • Function StringMid is used to extract the final content
  • In the end, the newly created file is executed using the ShellExecute function
    • Notably, it is actually executing itself and passing to itself the name of a newly created temporary file as a command line parameter together with the /AutoIt3ExecuteScript argument
    • In case you are not aware of this, AutoIt3 executable files contain an interpreter /as a stub/ followed by the compiled script
    • So, passing arguments to itselfs makes the stub interpreter execute external script instead of the one embedded inside the executable
  • The AutoIt3ExecuteScript command line argument is yet another confirmation that the newly created file is most likely an an AutoIt script

At this stage we know that the newly created file is an AutoIt script (and it is in a compiled form). We can find the values of the $dd and $ee variables (and even @TempDir) by adding the following commands to the first script we modified:

FileWrite("var_test",$test)
FileWrite("var_ee",$ee)
FileWrite("var_dd",$dd)
FileWrite("var_tempdir",@TempDir)

Once executed, you will get their values in respective files.

The values of $dd and $ee can also be extracted from the top of the first script we extracted (while they are not built dynamically like $test it is important to note that in more obfuscated scripts they could, and it’s safer to write their final values at the end of all initialization/obfuscation since there could be some code interpreted in the mean time that would change these values during the run-time).

Or, we can simply run the malicious file inside the VM and extract the dropped script from the %TEMP% folder (%TEMP%\eWEpCwslF).

The dropped file is a binary with some random data at the top (just a junk data as an attempt to hide its file type) and the ‘AU3!EA06’ marker clearly visible:

pic3Since it’s a compiled script, we can take this data and convert it into an AutoIt executable. We just append it at the end of the AutoIt3.exe interpreter (stub). This way we can run it through Exe2Aut and decompile the binary script into its source code.

This works like a charm, and the new extracted script looks like this:

pic4

The resulting file is a large 1.2Mb AutoIt script.

We can observe the following:

  • It is using an anti-sandbox trick (detection of ‘snxhk.dll’ loaded in the process causes the script to exit)
  • It doesn’t like NIS.exe, NS.exe, avp.exe processes – if it detects any of these running, it just adds a Startup persistence mechanism (via a shortcut file) and moves itself to a randomly named location under %APPDATA% & exits
  • It is large so it most likely contains other files embedded in the source code
  • We can also notice that the $data variable is most likely a hexified data dump of a portable executable file (data starts with ‘0x4d5a’ i.e. ‘MZ’)
  • There are actually 2 data blocks like this in the script (look for ‘$data = ‘ in the source code to find beginning of these 2 blocks)

Using FileWrite again we can dump the content of 2 $data streams to 2 separate files (we just need to edit the source code). For any string starting with “0x” prefix you can use a Binary function offered by AutoIt3 to convert such ‘stringified’ hexadecimal dump into binary i.e.:

FileWrite("var_data1",Binary($data))
FileWrite("var_data2",Binary($data))

Another thing to mention. While analysing obfuscated AutoIt scripts it is important to look for snippets of code hidden in-between large portion of seemingly similar statements (and sometimes large portions of garbage comments). In this particular case, we can grep the $data statements out and this way we can spot some extra code actually hidden at the bottom of this 1.2MB AU3 file (on the screenshot below it is shown ‘as it is’ inside the script surrounded by lots of statements that modify the content of the $data variable /there are over 27000 similar lines in the script/):pic5

This chunk of code (function named ‘y’) is actually very important, because it contains a shellcode that loads and executes the payloads. Using the FileWrite trick we can extract the shellcode:

pic6and other variables referenced on the screenshot (here, all of them are listed one by one forming a sequence used to launch the shellcode):

DllStructCreate("byte[" & BinaryLen($runnshell) & "]")
DllStructCreate("byte[" & BinaryLen($data) & "]")
DllStructSetData($kskdfvwfe, 1, $runnshell)
DllStructSetData($csadskxnkjas, 1, $data)
DllCall("user32.dll", "int", "CallWindowProcW", "ptr", 
  DllStructGetPtr($kskdfvwfe), "wstr", ($rot), "ptr", 
  DllStructGetPtr($csadskxnkjas), "int", 0, "int", 0)

This code is is actually a very well-known CallWindowProcW-based shellcode loader. The $runshell and $data variables are passed to this API and when it is executed it calls a callback function identified by the code stored in the $runshell variable:

pic7At this stage the payloads stored in $data variable start (the portable executables stored inside the $data variable are executed via process hollowing of 2 child processes, each getting the respective of these 2 $data streams injected into it).

The steps described above can be repeated for many obfuscated AutoIt scripts. It is time consuming and probably only needed when you really really need to know exactly what is happening step by step… Your chances for getting this sort of detail from sandbox are low. But, important bit is not that sandboxes cannot get this sort of details – the typical sandbox will most likely not reach the execution of these 2 payloads thanks to very restrictive timeouts (AutoIt scripts are slow and sandbox needs to call it quits at some stage). The price you pay for ‘knowing’ is that it takes quite a bit of time to walk through all these nested steps manually.

And just in case you are wondering:

  • 1st $data is Delphi executable/XtremeRAT
  • 2nd $data stream is UPXd Visual Basic botkiller/avkiller/UACbypasser + it downloads a new file from buscandoempleointernacional[DOT]com[SLASH]javaupdates2016.exe [Warning: URL live at the time of writing] as per config in the resources

Enter Sandbox – part 6: The Nullsoft hypothesis and other installers’ conundrums

Monitoring system services, Native APIs, Windows APIs and COM is a good start, but the monitoring capabilities can be always extended. In this post I will focus on one particular category of monitoring which I believe is often overlooked.

I am talking about installers and their plug-ins – with a main focus on the Nullsoft Installer (although I will talk about various installers in general).

I wrote about, or at least mentioned installers a couple of times before:

The reason why monitoring installers can be interesting is that it may provide an extra insight in the working of a binary (mind you, my focus in this series is on manual in-depth analysis more than automated analysis /although the latter could still benefit from discussed topics too/).

And why is that interesting?

  • There are classes of malware that rely on installers as a main way of infection
  • There are plug-ins (DLLs) dropped and loaded by installers that do stuff that may explain why certain things work/don’t work
  • Some plug-ins offer decoding/decompression/decryption/anti-sandboxing capabilities – intercepting the function calls responsible for this functionality can sched some more light on the internal working of the malware (and help to write behavioral rules)
  • Some installers use encryption and passwords can be only intercepted by analyzing the internals of the installer/plug-ins
  • Some plug-ins use novelty techniques to do stuff – they leverage COM, .NET, WMI to retrieve information about the system, download payloads, etc. – some of these cannot be intercepted on the Native/Windows API level and even if they are, the context is lost
  • etc.

Before we talk about the dynamic analysis of installers let’s look at a typical installer first.

Static analysis of installers

A typical installer contains a stub followed by a compressed/encrypted data blob. The stub is a legitimate program written by whoever designed the installer. As such, its detection cannot be used as a reliable mechanism to detect the malware using the installer since the signature (at least, not w/o looking at the appended data) would ‘hit’ many legitimate applications sharing the very same stub. In other words, the actual malware is never ‘seen’ as it is hidden in the package handled by ‘the always-clean’ stub. Static analysis of such installer files is hard, because it requires someone to write an unpacker – one that is dedicated to that particular installer (or, more specifically – its particular version), test it and then it may hopefully manage to handle a class of installers.

The problem of course is that:

  • there are lots of different installers
  • there are lots of very similar installers, but created either as a result of evolution (subsequent versions, localized versions, ANSI/Unicode, etc.), or private/customized versions that are spin-offs of legitimate repos available online (these f.ex. wipe out markers and change bits here and there to make the unpacking impossible w/o manual effort)

The net result is that it’s hard for the unpacker to handle it all and static analysis may simply not work (again, unless someone uses a dedicated naive algorithmic detection that could work f.ex. like this: detect known stub, check size of appended data, if matches the range, check some specific values in the appended data region, then ‘detect’; of course, such detection is useless since it is not generic as it only matches 1-1. i.e. each file requires a dedicated signature).

Detection of dropped files makes it a bit easier for the AV that can pick them up during run-time, but there is really nothing that could prevent malware author from keeping the main payload inside the actual installer and making it simply run persistently on the system. Having only the installer to look at may be then a relatively difficult target for manual analysis.

Luckily, the RCE community has addressed unpacking of many popular installers and there are plenty of tools that help with a task of a decompilation; including, but not limited to:

  • 7Z decompiles many files, including SFX files; earlier versions of 7z decompile even some versions of the Nullsoft installers
  • InnoSetup installers can be decompiled by Inno Setup Unpacker
  • AutoIt executables (not really installers, but kinda similar) can be unpacked with Exe2Aut
  • There are many decompilers for less popular installers (it’s easy to find them online) – there is also a dedicated project that focuses on decompiling all the possible goodness called Universal Extractor – at this stage project seems to be stalled, but it’s still a very good tool for many installers
  • Many installers can be decompiled by the Plugins for Total Commander: InstallExplorer 0.9.2, InstallExporer Port
  • RARSFX can be decompiled using winrar/rar
  • etc.

There are also ways to extract some data from files f.ex.:

  • 7ZSFX files
    • <installer filename>  -sfxconfig foo – ‘sfxconfig’ is a command that allows to extract comments from the sfx file and save it to a ‘foo’ file – an example of an extracted config file that instructs SFX to execute malware.exe file after the installation is shown below (GUIMode = “2” – hides the GUI/silent mode/, “hidcon:” prefix is used to hide the console window)
      ;!@Install@!UTF-8!
      GUIMode="2"
      InstallPath="%APPDATA%"
      RunProgram="hidcon:%APPDATA%\malware.exe"
      ;!@InstallEnd@!
  • RAR SFX files
    • rar cw foo – ‘cw’ is a command that allows to extract comments from the .rar archive (including sfx) and save it to a ‘foo’ file – an example of a SFX file that instructs SFX to execute malware.exe file after the installation is shown below
      ;The comment below contains SFX script commands
      Setup=malware.exe

So, static analysis are often possible to certain extent and all the available tools can make it relatively painless. I think it would definitely interesting to see some of these commands and tools deployed by commercial sandboxes as well – the reporting capabilities would increase a lot.

Dynamic analysis of installers

Coming back to the dynamic analysis of installers – you may still wonder why would we even go this path if there are so many tools and tricks available on the static level.

Here is why – the example below shows some logs from my PoC monitor for some of the Nullsoft installer Plug-Ins:

Call::in (*(i,i,i,i)i.r1)
Call::out=
Call::in (USER32::GetWindowRect(ir2,ir1))
Call::out=131418
Call::in (USER32::MapWindowPoints(i0,ir0,ir1,i1))
Call::in (*1545016(i.r6,i.r7))
Call::in (USER32::GetClientRect(ir2,ir1))
Call::in (*1545016(i,i,i.r8,i.r9))
Call::in (*1545016(i,i,i.r3,i.r4))
Call::in (USER32::SetWindowPos(ir2,i,i,i,ir3,ir4,i6))
Call::in (USER32::CreateWindowEx(i0,t "Button",t "Make JeezBar my default search engine",i 0x40000000|0x10000000|0x04000000|0x00010000|0x00000000|0x00000C00|0x00000003|0x00002000,ir6,ir7,ir8,ir9,ir0,i666,i0,i0)i.r2)
Call::in (USER32::CreateWindowEx(i0,t "Button",t "Make JeezBar my home page",i 0x40000000|0x10000000|0x04000000|0x00010000|0x00000000|0x00000C00|0x00000003|0x00002000,ir6,ir7,ir8,ir9,ir0,i667,i0,i0)i.r3)
Call::in (USER32::CreateWindowEx(i0,t "Button",t "Restart IE (if running)",i 0x40000000|0x10000000|0x04000000|0x00010000|0x00000000|0x00000C00|0x00000003|0x00002000,ir6,ir7,ir8,ir9,ir0,i668,i0,i0)i.r4)
Another example:
Call::in (kernel32::GetTickCount()i .r0)
Call::out=4847734
get (szURL=hxxp://dyn.flingstone.com/trackedevent.aspx?ver=0.0.1.0&rnd=4847734)
Call::in (kernel32::CreateMutexA(i 0, i 0, t "thlp_mutex") ?e)
Call::out=SendRequest Error
Call::out=1706281
get (szURL=hxxp://dyn.flingstone.com/vic.aspx?ver=0.0.1.0&rnd=1706281)

As you can see, you can instantly discover the internal working of the Nullsoft Script used by the installer. None of these can be seen using standard API monitoring. If you do offline analysis, intercepting some of these calls may give you clues that otherwise would be very difficult to obtain (e.g. URLs, sequence of internal instructions, possible log messages, etc.).

Now, how would you go about monitoring these calls?

Since I mentioned I am going to talk about Nullsoft Installer I will focus only on this particular installer here.

At this moment of time, there are at least 430+ versions of Nullsoft Installer in my repository. These come in various forms and flavors – lots of various versions, localized, etc. there is probably more than I counted, since many of the custom ones are modified in a way that makes it harder to distinguish them in a generic fashion. In any case, it’s quite a variety.

What is common about all these varieties is that they share plug-ins; there are a couple of plug-ins that are very popular f.ex. system, or inetc, execcmd, nsprocess, etc., but this is just a tip of the iceberg…

After running some scripts and hacking things around I counted over 5K different Nullsoft plugins and it was quite a clumsy work, so I bet there is at least twice as much 🙂

Where do we take it from here? Pick up the most common ones, recognize them when they are loaded, hook their functions and … log them.

Just in case it was not obvious yet – note that despite sharing the same name you may find out that many of them are different between each other – some process ANSI, some Unicode. Some implement additional functionality and all they share is a name and… a list of exported functions.

In any case, for the most popular ones it may add an extra layer of information and help in creating behavioral rules as well as getting to understand the inner workings of the samples.