Skip to main content

Grinju Downloader: Anti-analysis (on steroids) | Part 1

 This malware takes anti-analysis and stealth techniques to a new level

Image for post
Malpedia Inventory: https://malpedia.caad.fkie.fraunhofer.de/details/vbs.grinju

I’ve come across some great anti-analysis code in malware over the years. This one takes the top spot. On that note, let’s get into it, this is a long one!

Since this malware employs a very complex structure, I’ve decided to divide the analysis into different sections. I’ll try to keep it as simple as possible but having said that, it really is a very complicated project. Hence, publishing in parts.

TLDR: 
This is a very well-thought and equally well-written malware. There’s no VBA that you can analyse. The values and formulas that are used are spread across the worksheets to thousands of rows. The functions, among other things, are used to close the file, corrupt it and also delete the dropped scripts to make analysis extremely hard. In fact, you cannot analyse this malware without altering the code it self. Along the way, you’ll also see some great functions that can be used for anti-analysis techniques.
I've tried to include as much detail as possible but if you think something is not clear or has been left out (mostly its 'how did you get there in the first place?'), please don't hesitate to reach out, either in the comments or just email me.

No Code

Well, that’s not an entirely true title… there is code, just not in the traditional sense when it comes to macro-based malware (which is both exciting to see and also a stroke of genius on the authors’ part — credit where its due). Also, I wanted to reference in the album title from one of my favourite bands :)

Image for post

So, more to that point, basically, if you were to go into the dev mode and look for the VBS code in there, you won’t find much. In fact, you’ll find nothing at all at first.

So where is all the code…? Glad you asked ;)

All the code is in the worksheet it self.

So how does it execute…?

Hmm… gather around, grab a coffee.

Back in the day when Excel wasn’t what it is today (think version 4.0), users were able to program stuff using macro functions. These functions could be placed in the workbook itself. The way to do that is by creating a ‘macro’ sheet and then simply adding these functions in the cells. Then you can autostart the first one and then follow the chain to completion (with enough ‘if’ statements to make sure you control the execution flow). That’s the short summary of how you can have an Excel file run malicious code without having any VBA-based objects in the project.

Analysing the file

Now that we have a basic understanding of how the malware operates, let’s get into the nitty-gritty.

To start with, it looks just like any other macro-based malware. There’s that excel file that opens up with a message asking the user to enable macros.

There are two sheets:

‘Sheet1’ is the main one that the users see when they open the file, with the ‘Enable macros..’ message at the top. It also has a lot of data that is used by the macro functions to execute the programs for this malware.

‘ij3Lv’ is the macro sheet. It has the macro functions that are run in order to execute the malware.

The problem

Well, the first problem is that if you enable macros and allow execution of the malware, it will complete the execution flow and then simply corrupt the file at which point you won’t be able to analyse the file any longer. Having said that, let’s look at the flow of execution here before we move forward.

  1. The malware runs the first set of macro functions in succession which writes a new set of macro functions to the worksheet
  2. On successful execution of the second set of macro functions, the malware does two things:
  3. It writes a VBS file to the disk
  4. It writes a text file to the disk
  5. It deletes the text file
  6. It corrupts the original excel file
  7. End of execution

Now that we have laid out a simple, basic version of the flow of execution of this malware, let’s get into the more detail.

Analysis Part 1

In this section, we’ll take a look at the start of the execution chain and how it is implemented.

The starting macro functions are embedded in the macro sheet ‘ij3Lv’.

They are well hidden, starting at ‘R3887C240’ — which means Row 3887 and Column 40. Even after you zoom out completely, you’ll need to scroll to the right to get to these cells. Having said that this is not the way to find them, you need to grab the reference to the cell from code itself.

Image for post
Zoomed out to 10% and then scrolled out to the right; look all the way to the right closely

Once you get to the functions, you can copy them into a code editor and start analysing them one by one.

Image for post
Zoomed back at 100%

This is what they look like in an editor:

Image for post

Now let’s get into the details. I’ll pick the most interesting parts, as there are way too many of them to analyse individually.

In order to analyse it without losing touch with reality, we’ll do that dynamically. We’ll run these individually and then capture the output to build a picture that gives an idea as to what is happening during the execution.

Let’s start with this function:

Image for post
=IF(AND(APP.MAXIMIZE(),GET.WORKSPACE(19),GET.WORKSPACE(13)>770,GET.WORKSPACE(14)>390,GET.WORKSPACE(31)=FALSE,GET.WORKSPACE(42)),,HALT())

These functions are very interesting as they can be used as anti-analysis techniques, not seen or published before.

Let’s have a look how:

APP.MAXIMISE() — this is a smart way of starting this function. It literally just maximises the current excel window that you’re working on (this malware).

GET.WORKSPACE(19) — If a mouse is present, it returns a value TRUE if not, it returns FALSE. Can be easily used to check for sandbox presence.

GET.WORKSPACE(13) — usable workspace width, in points. In this case, the malware is checking if it’s greater than 770 or not. Again, can be used to check for sandboxes. Window size wouldn’t matter at this point as it has already been maximised at the start of this function.

GET.WORKSPACE(14) — usable workspace height, in points. Being used exactly as the function above, just for height in this case.

GET.WORKSPACE(31) — If running the macro in single-step mode, it returns TRUE. In this case, the author has already set it to FALSE, trying to hinder analysis.

GET.WORKSPACE(42) — If the computer is capable of playing sounds, this function returns TRUE! Anti-sandbox check.

Once all these options have been checked, the function is stopped (HALT).

Let’s move on to the next one:

Image for post

From this point on, the functions move on to extracting values from cells in Sheet1 and using them to construct values for the next set of functions that will be written to the workbook to be executed as the next step. Let’s see how that is done.

Functions use variables that are then assigned values from specific pre-populated cells. Function ‘SET.NAME’ is used for this purpose.

Eg:

gsiGGMo=R3915C240
gzDNqr=R3890C240
PMXOKD=R3979C240
esvmJMDoTkrH=R3910C240

When you go looking for these cells, you’ll find they have values in them, derived by using formulas (this is obfuscation on steroids, as you can’t just ctrl+F for these values as text).

Going through each call is out of scope for this publication so we’ll just look at the overall flow.

The entire program at this point runs in a loop, based on an ‘If’ statement. The values are incremented by one each time and if the condition returns ‘True’ the values are used to form the next set of instructions.

Another very interesting method that has been applied here, is using the character codes to build the commands!

Let’s take a look.

Image for post

In the above capture, note ‘CHAR(61.91)’ — this literally means: start building the value for “pdnPdPUK” with the character that corresponds to the code of ‘61’. 61 is the code for the Equals character ‘=’. Now look at the output below:

Image for post

This loop ends up building the value all the way to “=CLOSE(FALSE)”, which will be used as one of the functions to close the workbook without saving it (FALSE=don’t save).

Image for post

Once ALL the functions have been run successfully, this is the resulting code:

Image for post
In the next part, we’ll dive into the code step-by-step and discover more anti-analysis and stealth-exec techniques.

Comments

Popular posts from this blog

Major update: Emotet C2i Apr 2019

Emotet has updated the C2 comms in the latest release, going for URIs instead of IPs (root). Here’s a complete list of the current campaign: Emotet C2i: http://51.255.50.164:8080/window/child/ringin/ http://109.104.79.48:8080/cookies/tlb/ http://92.48.118.27:8080/rtm/pnp/ http://197.248.67.226:8080/enabled/forced/ http://181.170.93.38:8080/teapot/balloon/ http://69.163.33.82:8080/glitch/scripts/arizona/ http://192.155.90.90:7080/prov/odbc/arizona/ http://43.229.62.186:8080/teapot/ http://72.47.248.48:8080/sess/cone/ http://209.159.244.240:443/publish/vermont/tlb/ http://197.248.67.226:8080/codec/between/tlb/ http://176.58.93.123:8080/splash/ http://72.47.248.48:8080/sess/glitch/entries/ http://181.170.93.38:8080/schema/free/ http://69.163.33.82:8080/badge/symbols/results/ http://109.73.52.242:8080/results/prov/ http://68.191.37.107/iplk/vermont/sym/merge/ http://154.120.228.126:8080/xian/enabled/sym/merge/ http://136.49.87.106/usbccid/taskbar/enabled/ http://5.9.128.163:8080/json

Grinju Downloader: Anti-analysis (on steroids) | Part 2

  This malware takes anti-analysis and stealth techniques to a new level We took a look at this malware in the Part 1 of this publication. Now let’s carry on with the analysis and dig deeper into the various anti-analysis and stealth-exec features of this malware in Part2. Malpedia Inventory: https://malpedia.caad.fkie.fraunhofer.de/details/vbs.grinju Secondary Macro Code First of all, here’s the entire code that is dumped in the sheet once all the macro functions have been completed. Take a look at these lines and try to figure out what they are meant to do. Then we’ll take a look at the most important of these briefly before moving on to the next section. =CLOSE(FALSE) =FORMULA(LEN(APP.MAXIMIZE())+-459,Sheet1!R18690C129) =FORMULA(LEN(GET.WINDOW(7))+-131,Sheet1!R18691C129) =FORMULA(LEN(GET.WINDOW(20))+-893,Sheet1!R18692C129) =FORMULA(LEN(GET.WINDOW(23)=3)+433,Sheet1!R18693C129) =FORMULA(LEN(GET.WORKSPACE(31))+864,Sheet1!R18694C129) =FORMULA(LEN(GET.WORKSPACE(13)>770)+707,Sheet1!R18