A deeper look into a wild VBA Macro

This Sample comes from Brad Duncan @malware_traffic from his SANS ICS Diary located Here and the Files on His blog Here.

For this session I will be using “2019-01-23-example-of-attached-Word-doc-1-of-7” word document.

I ended up looking at this from different directions so that is what I want to try and show here.

The first thing I always do is to look at the file in a hex editor to verify what type of file I am dealing with. Never trust a file extension.


As we can see by the 8 byte file header we are dealing with a OLE file vs. say the XML or the Zipped style or RTF form of a document.

My next step is usually to drop the file it into Office Libre to see if it will even open.

Here is what the Document looks like.


Next let’s look and see if there are any macros available. Some times no macros are detected using this program so alternate methods / programs need to be tried to verify there are no Macros.

So when this first loads even before the “AutoOpen()” Sub, it does a “GetTickCount” call to the Windows API.


Since we are here lets take a closer look at this function.


The “#If VBA7 Then” is what caught my eye. According to This question on StackOverflow it is checking for 64 bit Office on a 64 bit system.

Another Odd thing I noticed was when you click from the Module1 tab at the bottom to the ThisDocument tab then back the function name changes to the AutoOpen one.


So now we can use the “Save Basic” button to save this Module1 as a “.bas” file to take a closer look.

But lets go further Now that I have the Decalage @decalage2 and Didier Stevens @DidierStevens tools installed lets see what they tell us.

We start with Olevba


As we can see here it outputs the macro for us and also gives us more information about what happened when it was checking it including the decoded IP Address.

Not all of the Information in the box is “Always” correct. So you may need to verify.

Now lets take a look with Oledump.py We start with the basic command to see what streams are in here.


We can see in stream 7 there is a upper case “M”. That lets us know that there is code in the macro. So lets look at that.


That looks like the data is compressed so lets add the –v switch to decompress this stream.


Now that is much better. We can now output that to a text file and take a closer look in our favorite text/ code editor tool.

Lets look at 1 more method before we dig in deeper to how the rest of the code works.

I’ll use 7Zip to decompress the document and we see the folder/ file system.


Lets dig into the Macros folder and see what we have.


We have files and a folder. In the VBA folder we have .


Now here is what I’m looking for. Lets take a look at module1 in a hex editor.


We can see here that there is some plain text but this “Stream” is compressed.

Before I learned how to use oledump.py I had wondered how you extract the data in this file /stream.

I had read This article in that past but didn’t understand every thing it was telling me.

But using the code provided there and with some modifications I was able to build a tool to decompress the single stream. I wrote the tool mainly to “Try” and understand how the encoding/ compression worked.


So that now gives me 1 more way to extract the macro(s) from the document.

I also Installed and Ran Vipermonkey today to see how that worked since I have never tried it before.



As we can see here it also extracted the script but seemed to have a problem with the VBA7 code.

Here is a list of the commands I used for olevba and oledump.

All commands are run from opening a CMD prompt in the folder where the document was located. (Shift + right click on folder , select Open command window here)


Let’s dig into this code some more because it is crazy.

The first part of the code you can see in the screenshot of my tool above is just a large block of junk comment data.

If we start checking for references of declared variables before the the “AutoOpen()”  we can find that there are several that are never used so they are most likely just junk filler to make it harder to read.


This code does a series of converting the “Val” and “Len” values all of the way thru this code.  Even once we convert those values we still have to do the math for each line.

So I wrote a tool to understand how the “Val” works. This Link will give you and Idea.


As we can see it will input that string and return the numerical value. Basically cleans all non numerical values. But this value could have also been “&H” for Hex or “&o” for Octal.

We know “Len” is the length of the string so somewhat easy. The hard part is to parse this code and do the replacements for the numeric value.

My tool still has a bug or 2 but will parse this well enough for us to get a better Idea of what this is doing.



Now that some of the extra obfuscation is out of the way we can look closer at what we have.

After going thru and doing the math by hand we see this. The part with “****” next to them is where the two main values  are reset to a new value.


At the end of the lines I also calculated the values for the “Left”, “Mid”, and “Right” values. These get used to get the sub string from those functions and the output gets appended onto the final string that get run in the “Shell” command at the end.

If we zoom in on these values we can see they are only taking a few characters from each string.

The first number (green text) is the position to start taking from, and the second is the length to take.


If we keep scrolling down we can see the IP that gets called out to.


We also see towards the bottom this interesting code.


We can see where it will possibly insert a break or clear formatting.

The GetTickcount  to me seems like this might be some type of anti debugging or just another time waster. ( Without verifying , you would think the tick count would always be greater. Tick count Explanation)

If it is less than 1.2 then it will change the the output value to the garbage string to that will get run by the “Shell” and fail.

Now the “Shell” which will run what got put back together.Shell

The first part of that before the “+” is just junk code. It doesn’t do anything that I could find. In the Shell it is passing the rebuilt string and the numeric value that gets passed. (I didn’t do the math all of the way thru. )

Now that we have a real good idea of how this works how do we output this so we can see what the final string is before it gets executed ?

I tried to open it up in Office Libre and modify the Macro code but that didn’t work.

After building a new Clean VM I installed a copy of Office personal in there.

Lets see what it looks like in the real office.


We already have a pretty good idea of how this macro works so lets open this up and make some changes then save them.

I’m not sure if it would make any difference but lets comment out the section looking for is wow64.


Lets also make a change to the GetTickcount to make sure it is not an issue.


We change the value to greater than the “1.2008” that gets checked later on.

And the final Change to the “Shell” lets replace that with a MsgBox call instead.


And after saving the changes and clicking “Enable Content” we get this.


We can then left click on the MsgBox and hit Ctl+C to copy the data and then paste it into notepad.


One strange thing that happened was, when I clicked “OK”  the Document looked like this afterwards.


What Happened here ?


It looks like there is code here for clearing the formatting and the image.

Up higher it looks like this would work for an Excel sheet also.

And when we go to close it it just ask us if we want to save the changes.


So the macro calls out to the IP with random 7 Character string and “.jpg”

The function will choose a value between 97 and 122 which is the ASCII code range for lower case letters. For each random Number it will convert it to a lower case letter (ASCII Char code) and add that to the final value for a final length of 7.

So that is that for the Decoding part.

The next problem was after enabling that content it would not “Un-Enable” no matter what the settings were.

So what is the Problem with that ?

After enabling the content once it now becomes a “Trusted Document” , the problem is how do you Un-Trust it again ?

We have to go to File –> Options –> Trust Center –-> Trust Center Settings (Button) –> Trusted Documents –> Clear all Trusted Documents …… (Button “Clear”)


I’m not finding a way to see a List of what is trusted or even that there are any trusted documents. Perhaps there is a screen I’m not seeing somewhere.

Also I don’t know if this is a bug or not, but the “Allow documents on a network to be trusted” seem to automaticity recheck itself after I Uncheck it close the document and reopen it.

So I used the Mantra “When in doubt run Procmon” to locate where these are.


I first set a filter for “Category is write” then looked for the string “Trust” once I found this registry key I added a filter for “Begins with” on the registry key and removed the other filter and got the above view.

And If we look at it in the registry.


And if we Dump the Key.


I did a hash calc of the document after it was saved so I have another question, what it the hash they are using ?


I’ll also Have to Figure out the Time format too.

Once we clear these (By clicking the Clear Button)  this key will be deleted and the Documents will no longer be trusted.

Well that’s it for this one. I hope you learned as much as I did.

About pcsxcetrasupport3

My part time Business, I mainly do system building and system repair. Over the last several years I have been building system utility's in vb script , HTA applications and VB.Net to be able to better find the information I need to better understand the systems problems in order to get the systems repaired and back to my customers quicker.
This entry was posted in Malware, Programming, VBScript and tagged , . Bookmark the permalink.