Excel 4.0 XLM Extraction



Note: for those interested, yes, we’ve compiled a list of IOCs from a few thousand XLM Macro-enabled Microsoft Excel documents. These are listed at the end of the blogpost.

Over the last couple of years an alternative to Microsoft Office’s VBA macros has been increasingly gaining attention from malware authors looking to evade common detection methods. XLM macros - often referred to as Excel 4.0 macros - were the predecessor to VBA scripting in Office, available in early versions of the software up to Excel 4.0 (released in 1992). Subsequent versions no longer supported the creation of these macros, but continue to include the ability to execute them all the way up to current Office releases. 28 years on if a user opens a file containing them the scripts will still run, but many security products may not be looking for them, focusing instead on the more common VBA form.

Noticing this increase in activity, we have recently been working to implement extraction of IoCs from these XLM macros, and are pleased to say that this feature is now available on

(Another note: this blogpost doesn’t touch the payloads dropped by these XLM Macro documents, we’ll get back on that next week).


Unlike VBA macros, XLM versions are not bundled with the file as a separate object - they are written directly in the spreadsheet cells, much like Excel formulas. There are a few different ways in which these macros are hidden from prying eyes, ranging from the low-tech - make the text color white and paste an image over the top of the cells - to the more advanced - manipulating metadata for a sheet in the workbook to hide it, requiring the modification of a hex value in the file to make it visible again.

These approaches are covered extensively in blogposts published by others, such as Inquest’s analysis of 2 samples from early 2020 or Xavier Mertens’ blog on a similar example, so we won’t cover the details again here. Instead, this blogpost aims to provide details on how we have approached automated extraction of these macros, and what information that makes available through Triage analyses. It will also include examples, to highlight the uses of the new feature.

For reference, the following blogposts/tweets provide further details on malicious XLM in addition to those mentioned above:

XLM Macros 101

We start with the sample from Xavier’s blogpost. This one is relatively straightforward: the macros are just there and there’s no obfuscation. You can even fetch the URLs straight from the binary by just looking at hexdump:

0a 00 00 ff 98 00 17 06  00 75 72 6c 6d 6f 6e 17  |.........urlmon.|
12 00 55 52 4c 44 6f 77  6e 6c 6f 61 64 54 6f 46  |..URLDownloadToF|
69 6c 65 41 17 06 00 4a  4a 43 43 4a 4a 1e 00 00  |ileA...JJCCJJ...|
17 40 00 68 74 74 70 3a  2f 2f 73 61 6d 70 68 61  |.@.http://sampha|
6f 70 65 74 2e 63 6f 6d  2f 77 70 2d 63 6f 6e 74  ||
65 6e 74 2f 75 70 6c 6f  61 64 73 2f 32 30 32 30  |ent/uploads/2020|
2f 30 32 2f 69 64 6c 65  2f 31 31 31 31 31 31 2e  |/02/idle/111111.|
70 6e 67 17 1e 00 63 3a  5c 55 73 65 72 73 5c 50  |png...c:\Users\P|
75 62 6c 69 63 5c 61 73  64 32 61 73 66 66 33 32  |ublic\asd2asff32|
2e 65 78 65 1e 00 00 1e  00 00 42 08 96 00 06 00  |.exe......B.....|
cd 00 07 00 00 00 42 00  01 00 00 00 00 00 ff ff  |......B.........|

Basic XLM

In order to automatically and correctly extract the URLs, we wrote a Microsoft Excel Macro decompiler. The macro bytecode is a relatively straightforward stack machine. A snippet of the decompiled AST may look as follows:

  Name: "CALL"
  Args: [

The list of extracted macros as well as extracted IOCs (URLs) can be found at the following analysis:

For the curious reader: yes, in the Triage analysis above we also took the time to translate the decompiled formulas back to a textual representation for easy inspection, so the formulas listed in this report are the human readable version of what’s in the Excel document ;-)

Webquery and anti-sandboxing

The first sample from the Inquest blogpost is actually using Webquery to fetch macros from a remote server through a simple HTTP request, which is also interesting. However, it also employs macros to perform anti-sandboxing by closing the Office application as can be seen here:


(It should be noted that GET.WORKSPACE(19) returns true if and only if a mouse is present and GET.WORKSPACE(42) returns true if and only if sound can be played on the computer).

Crafting Macros at Runtime

Of course XLM wouldn’t be a true scripting language if it weren’t for the ability to create XLM macros at runtime using the FORMULA method. Below you’ll find a small snippet of the FORMULA method where its string argument is being constructed dynamically through numerous concatenate statements (each being something like "A" & "B").

  Name: "FORMULA"
  Args: [
      Left: formula.ConcatStmt{
        Left: formula.ConcatStmt{
          Left: formula.ConcatStmt{
            Left: formula.ConcatStmt{
              Left: formula.ConcatStmt{
                Left: formula.ConcatStmt{
                  Left: formula.ConcatStmt{
                    Left: formula.ConcatStmt{
                      Left: formula.ConcatStmt{
                        Left: formula.ConcatStmt{
                          Left: formula.ConcatStmt{
                            Left: Ref{0 16}
                            Right: Ref{2 16}
                          Right: Ref{3 16}
                        Right: Ref{4 16}
                      Right: Ref{5 16}
                    Right: Ref{6 16}
                  Right: Ref{8 16}
                Right: Ref{9 16}
              Right: Ref{10 16}
            Right: Ref{11 16}
          Right: Ref{12 16}
        Right: Ref{13 16}
      Right: Ref{14 16}
    Ref{19 18}

(Mind you, this was basically the shortest FORMULA sequence we could find..)

Each Ref{Row Col} entry is a reference to another cell, so the above formula actually looks more like =FORMULA(Q1 & Q3 & Q4 & ...). Then, to make things better, those cells don’t contain strings, but instead also contain macros. In this example cell Q1 contains =CHAR(61) which translates to the "=" string (associated AST listed below).

  Name: "CHAR"
  Args: [

In the static analysis component of Triage we’ve essentially implemented a full deobfuscation layer on top of the macro decompiler, essentially optimizing away these obfuscation layers. Submitting the sample from the following tweet will therefore once again provide you with the related IOCs.

In fact, as can be seen in the analysis, Triage will provide the dynamically constructed macros too, allowing one to quickly inspect their overall behavior and identify potential anti-sandboxing techniques in use.

XLM Macros: Hardcore mode

Finally we move onto the last sample for today:

It’s similar to the sample discussed here:


For those reading carefully, you might notice that this time the CHAR argument is subtracting a number from a cell reference. In our AST this looks roughly as follows:

  Name: "CHAR"
  Args: [
      Left: Ref{1704 121}
      Right: 983

The XLM Macros in this document also have other interesting features like recursive references and references through the XLM Macro RUN method as well as cells that have their value populated twice. Once by what Microsoft called SST (probably meaning sorted string table) and once by a regular integer (which, of course, is stored internally as a floating point).

There are some other interesting “features” about these Excel documents and how their data is being stored, because Excel has a number of optimizations to reduce storage space, e.g., resulting in multiple cells with the same value being stored in a different manner than other data. Or formulas working on multiple cells. Or XLM Macros creating infinite loops through references. Or Excel featuring almost a dozen different ways to store strings depending on the data type that needs it, etc.. In other words: a joy to work on!

We’ll be working on generating more IOCs related to XLM Macro-enabled documents both by active research from our side as well as from people submitting relevant samples to our public cloud.

For now we’ve compiled the following list of IOCs based on a couple thousand XLM Macro-enabled documents:

    354 hxxps://rwtkoaqe[.]club/adfbr53g
    289 hxxp://fcowhcwsb[.]space/erg4ewr1
    262 hxxps://waitupdate[.]xyz/deg34g
    181 hxxps://pxdgcvnsb[.]xyz/aaeg4df12
    143 hxxps://veqejzkb[.]xyz/SDVe2f2fds
    136 hxxps://merystol[.]xyz/6ng688x8
    135 hxxps://cdncloudtech[.]xyz/deg34g
    130 hxxps://emmnebuc[.]xyz/SDVJKBsdkhv1
    127 hxxps://cdncloudtech[.]xyz/bag4hy
    122 hxxps://doolised[.]xyz/DSBVhsdv78f
    119 hxxps://pnxkntdl[.]xyz/KJSDBViad7
    111 hxxp://wrjmkdod[.]xyz/KDHBVsd7v8
     99 hxxps://fbknuele[.]pw/ajt1eg4fh3a
     93 hxxps://paxtontranter[.]xyz/rv24t2
     91 hxxps://amberlessard[.]xyz/brg2sv
     89 hxxps://tdvomds[.]pw/12341324rfefv
     89 hxxps://fbknuele[.]pw/aagaeg4df12
     72 hxxps://merystol[.]xyz/DVkjbsdv37
     71 hxxps://cworld[.]top/wp-front.php
     71 hxxps://assemble[.]sg/wp-front.php
     69 hxxps://tozcftdl[.]xyz/SDVjkhb7831r
     65 hxxps://wrjmkdod[.]xyz/SDFwef2fvbbe
     65 hxxps://pnxkntdl[.]xyz/KDSBVksdhv778a
     61 hxxps://efbzfyvsb[.]website/f2f23
     60 hxxps://ddfspwxrb[.]club/fb2g424g
     58 hxxps://amgdorie[.]online/avdv43g
     55 hxxps://rosannahtacey[.]xyz/vg43
     54 hxxps://hxzfvomd[.]buzz/asf2f1ff
     52 hxxps://ethelenecrace[.]xyz/fbb3
     51 hxxps://emmnebuc[.]xyz/vbdh72F
     50 hxxps://pjtcdnrd[.]pw/ckjbvkf732
     49 hxxps://pxdgcvnsb[.]xyz/ajt1eg4fh
     49 hxxps://pjtcdnrd[.]pw/fsgbfgbfsg43
     47 hxxp://tubolso[.]cl/wp-content/uploads/2020/02/white/444444.png
     47 hxxp://murreeweather[.]com/wp-content/white/444444.png
     47 hxxp://freespacemarketing[.]com/wp-content/uploads/2020/02/white/444444.png
     47 hxxp://batilservice[.]xyz/wp-content/uploads/2020/02/white/444444.png
     45 hxxps://tdvomds[.]pw/fgwg24g24g
     42 hxxps://amgdorie[.]online/avdv42g
     42 hxxp://kacper-formela[.]pl/wp-smart.php
     42 hxxp://braeswoodfarmersmarket[.]com/wp-smart.php
     36 hxxps://uenoeakd[.]site/grwrg24g2g
     34 hxxps://emmnebuc[.]xyz/DSKVJBdsj2
     29 hxxp://209[.]141.54.161/crypt.dl
     26 hxxp://uniluisgpaez[.]
     26 hxxps://wgyafqtc[.]online/fgwg24g24g
     26 hxxp://samphaopet[.]com/wp-content/uploads/2020/02/idle/111111.png
     26 hxxp://icietdemain[.]fr/contents/2020/02/idle/222222.png
     26 hxxp://careers[.]
     21 hxxps://narensyndicate[.]com/wp-crun.php
     21 hxxps://greentec-automation[.]com/wp-crun.php
     14 hxxps://studyshine[.]in/wp-cryn.php
     14 hxxps://arturkauf[.]pl/wp-cryn.php
     14 hxxp://march262020[.]club/files/bot.dl
     14 hxxp://lorrainehomeconsulting[.]com/wp-content/uploads/2020/02/trusty/187213.png
     14 hxxp://g2creditsolutions[.]com/trusty/444444.png
     12 hxxps://tdvomds[.]pw/1451345341fff
      9 hxxps://orruucsl[.]xyz/fdgareg34g
      7 hxxps://narensyndicate[.]com/wp-cran.php
      7 hxxps://greentec-automation[.]com/wp-cran.php
      7 hxxp://gengrasjeepram[.]com/sv.exe
      5 hxxps://wrjmkdod[.]xyz/vdjfvfs7871f
      5 hxxps://doolised[.]xyz/SDVJbsldkcvg1
      4 hxxps://gartnerkvartalet[.]no/wp-content/themes/calliope/wp-front.php
      4 hxxps://assemble[.]sg/wp-frunt.php
      3 hxxps://doolised[.]xyz/test
      3 hxxp://209[.]141.54.161/files/crypt.dl
      2 hxxps://wgyafqtc[.]online/sgfbsb4
      1 hxxps://nonnewspaper[.]com/bot.dl
      1 hxxps://merystol[.]xyz/qY3DRY3N
      1 hxxps://grpxmqnrb[.]pw/ehrj4g9g
      1 hxxp://fikima[.]com/axel.ex
      1 hxxp://fibercemper[.]com/wild.ex
      1 hxxp://209[.]141.54.161/crypt18.dl

This list contains the following IOCs as well as all related sample hashes, XLM Macros, and Webquery IOCs.


Sign up to Triage today and analyze XLM Macro files and many more file types and malware families the rest of the year.

Last but not least, in the future we’re also looking to provide access for our users to the AST that’s generated such that new obfuscation techniques can be studied not only by our team, but also by our users!

We hope you enjoyed this blogpost and stay tuned for more :-)

You may also like: