dridex maldoc: The unholy union of VBA and XLM

Kirk Sayre (@bigmacjpg) posted some info on a dridex malicious document the other day. It was a real piece of work. To put it succinctly, the VBA script grabs data from cells in the spreadsheet, decodes them, and then runs them as an XLM command. Even better, all of the cells have white font (tricky, tricky).

Here’s the info Kirk dumped from the document:


And here’s the document itself:


First things first

Before we can start stepping through the macro, we see that it is unviewable.

Enter: EvilClippy. Much could be written here about how this tool works, but just read this article by Carrie Roberts (@OrOneEqualsOne) instead. It is fantastic.

We can make the project viewable by just using –uu. It will automatically make a new copy of the document, but the project has become viewable.


lncol() is the main Sub. Much of the other logic/decoding functions branch off this one.

Lines 90/91: pic, oks, and img become the names of the new folders created and the name of the downloaded file. More on them later.
Line 92: This for loop will cycle through rows A208 to A212.

Line 94: Send the information from cell A208 along with a random number from 1 through 4 to function Ami.

Creating the XLM String

Line 45: Take content from A208, send to function verud, and put results in array df.
Line 53: Convert cell content to decimal numbers.
Lines 46-47: Take each number in array, add f (remember, that random number from 1-4), and send to function zen.
Line 39: Convert decimal number back to ASCII.
Line 47: Add ASCII character to variable Ami. Convert the rest of the array in the same manner. Then head back to the main function…

Line 95: This line is important. It checks to see if the string you just decoded ends in a right parentheses “)”. If it does, continue on to line 96. If it doesn’t, run line 94 again until you get the desired output. This is why the random number from 1-4 is important. It will keep looping and decoding until the right output is created.

Here are all five of those decoded cells. But cells A209-A212 are not complete. Certain characters in those XLM strings will need to be replaced before they can be executed.

Replacing Characters in XLM String

Line 97: This line calls up function kio which will execute the XLM string (line 105). BUT before it does that, the string itself needs to be altered. That is the purpose of function vs.
Line 108: This function takes the semicolon, single quotation mark, dollar sign, and question mark and replaces them if they’re found in the string. Those strings become the names of the directories that are created as well as the URL from which the malware is downloaded.

Speaking of URLs…

These are the remaining strings still buried in the spreadsheet. They can be found in cells A593:D626.

Function mores() decodes these strings.

Line 23: Get a random row between 593 and 626.
Line 24-29: Start with column 1 and grab that cell information. If it is empty, try cells 2 through 4 until you get a cell with text in it.
Line 31: Send that found data to function Ami. Note that the value for f is the same as the column.

Once everything is laid out, it isn’t too complicated. But get ready for either more like this or adjustments to this layout.

Thanks for reading!

zLoader XLM Update: Macro code and behavior change

We’ve got ourselves a change to the zloader XLM code and also some document behavior. Here’s today’s sample:



Central Loop Mechanism

The decoding part of the central loop mechanism still exists as it did before. It grabs hex characters from elsewhere in the document, decodes them, and writes those strings to new cells. However in this case, the document only runs through two rounds of this decoding.

Round 1

The first round behaves pretty much the same as it did before. It checks to see if it’s in a sandbox, checks the registry, and if VBAWarnings is turned on, the code will go back to the loop and start round 2.

Round 2

This is where the main difference lies. A series of lines get written to a file called QP0L3.vbs and then executed.


The code in the .vbs file is nothing that special. It’s just an array of URLs going through a For Each loop. The file gets downloaded and then saved as an .html to the Temp folder.

Back to Round 2

At this point, the .html file is executed with what looks to be rundll32.exe.

And that’s pretty much it! Again, not a major change, but I thought it was a noteworthy one.

Thanks for reading!

Trickbot: ActiveDocument.Words is the word!

This Trickbot document hid a .dll in an interesting place. If you’d like to play along, you can find the document and dropped .dll here:

Document: https://app.any.run/tasks/96c149ce-b01a-4543-a8d4-2b98bb18b9c7
Document Password: INV15
SHA256: 052C9196DFE764F1FBD3850D706D10601235DC266D1151C93D34454A12206C28

Dropped File: C:\programdata\objStreamUTF8NoBOM.Vbe
Dropped File: C:\UTF8NoBOM\APSLVDFB.dll
Dropped .dll: https://app.any.run/tasks/5bc86667-aab3-4513-a433-3697d6a9d3eb

After supplying the provided password to open the document, I suggest that you remove it, save the document, and then use tools like oledump.py to extract the macro. Notice how it keeps making references to ActiveDocument.Range(Start and End) and ActiveDocument.Words.

The macro is pulling data from the current document, piecing them together, and then writing it out to this file and location:


Once that is done, the macro creates a Wscript.exe object and executes that .vbe file.

But where did it get all of that data? Where was it hiding in the document? Well, it wasn’t really ‘hiding’ in the typical places we see obfuscated commands (I’m looking at you, Emotet). In this case, it was hiding behind the the picture we see in the document itself. We can see the text below by deleting that picture and zooming in 400%.

You can fit an entire .dll on one page of a word document if you use 1 point font. Who knew?

The macro in the document takes the above characters, rearranges them, and writes them to objStreamUTF8NoBOM.Vbe. Here’s that .vbe file.

Near the bottom of objStreamUTF8NoBOM.Vbe, we can see the base64 decoding function. It gets copied to the following location:


The last two lines create a wscript.shell object and use regsvr32 to run the .dll.

And there you go! Thanks for reading!