In order to give you a better service Airbus uses cookies. By continuing to browse the site you are agreeing to our use of cookies. I agree

To opt out of Google Analytics data collection, click here

Thanks. We have set a cookie so that Google Analytics data collections will be disabled on your next visit.

Analysing the Hancitor Maldoc



Recently we have seen several phishing attempts using macro enabled word attachments to load the Hancitor download trojan. The macros in these documents use routine windows API functions with a callback parameter in order to run shellcode directly in memory without the need to drop further files to disk. This entry follows the analysis of this method and may be useful for those new to the reverse engineering field.

Analysis Walkthrough

Static Analysis

This particular sample comes in the form of an OLE word document. Sandbox analysis or use of the python OLE tools from Didier Stevens will reveal that the document contains heavily obfuscated VBA macros including a Document_Open routine which will run as soon as macros are enabled for the document. The level of obfuscation means that the quickest way to reveal the actual function of the macros will be to run them in a controlled environment and follow the execution in Word’s debugger.

Opening the Document and Accessing the Macro Code

On the version of Office I was using, it was not possible to open the document for editing without first trusting the content. This posed a problem as I did not want the macros to run until I had a chance to examine the code further and set some initial breakpoints. Even though I was using a clean Virtual Machine for the analysis I would rather avoid infection if at all possible.


In order to circumvent this it is first necessary to change the default Trust Centre settings within Word to allow all macros to run. Although this seems counter-intutive it means that by holding down the shift key whilst opening the document, either from the File-Open menu or by double clicking in Explorer, the document will open correctly but no macros will run. If you use this version of office for anything other than malware analysis then please ensure that you change the setting back once you have finished.

Once the document has been opened pressing Alt-F11 will transfer you to the Visual Basic for Applications (VBA) editor.


Stage 1 – Analysing the Macro Code

As we can see from the Project viewer in the window above the document contains three separate code containers:

  1. The Document Itself
  2. A separate module named presbyope
  3. A form named natal

Quickly clicking through reveals that both the document and the module contain heavily obfuscated code, while the windows form contains no code. The form itself is a single dialog containing a tab view and two tabs, but no buttons or menus or anything that would normaly perform events. Interestingly the first window that opens is the presbyope module and as we can see above this imports, and renames some interesting Windows API functions, including some interesting memory manipulation functions.


From experience we know that many malware samples use VirtualAllocEx in order to create a buffer which will later be used to execute shellcode or even full processes. In this case though the other process hollowing functions such as StartProcess, UnmapViewOfSection etc are not present so it looks like we will only be looking at the Word Process itself. Searching the code for calls to “madid” we find that there is only one.

Examining the code either side this can be viewed as:

ShellcodeBuffer = VirtualAllocEx(-1, 7386, 0x1000, 0x40)

A quick look at the MSDN documentation reveals that 0x1000 is equivalent to MEM_COMMIT and 0x40 to PAGE_EXECUTE_READWRITE, meaning that the buffer will be allocated on use and the memory pages will be marked as executable.

Widening our view further this call occurs within a function named “vasopressin”, which also includes several calls to the function “bilaterally” which as we saw previously is actually the Windows API function RtlMoveMemory. Removing the junk code and renaming the variables renders this function as:

Function vasopressin(PayloadString);
Dim PayLoadPtr As Long;
RtlMoveMemory PayloadPtr, ByVal VarPtr(PayloadString) + 8, 4;
Dim Result As Long;
ProcessId= -1;
StartingAddress= 0;
NewBuffer = VirtualAllocEx(ByVal ProcessId, ByVal StartingAddress, 7386, 4096, 64);
RtlMoveMemory Result, ByVal VarPtr(NewBuffer) + 8, 4;
RtlMoveMemory ByVal Result, ByVal PayloadPtr, 5538;
vasopressin = Result;
End Function;

This function takes in a single parameter in the form of a string, in practice simply an array of bytes.  It then creates a new area of executable memory and copies the payload into it.  The return value is a pointer to this new “function”.
If we look at where this code is called from we can see that it is called only once, from procedure “sauciness”.  This function uses several properties of the “natal” form in order to construct the payload string which is passed to “vasopressin”.  It then calculates an offset into the shellcode payload based upon whether or not the machine is running 64 bit windows, and passes this offset as the first parameter to the EnumCalendarInfoW API function.
Deobfuscated this function appears:

Sub sauciness()
Set MyTab = natal.libet.BoundValue("Tab2")
TipText= MyTab.ControlTipText
Length = 7368
LongString = Right(TipText, Length)
Payload = presbyope.satire(LongString)
#If VBA6 And Win64 Then
Dim PayloadPtr As LongPtr
Dim PayloadPtr As Long
#End If
PayloadPtr = Payload
ShellCodePtr = vasopressin(PayloadPtr)
#If VBA6 And Win64 Then
Offset = 1280
#ElseIf Win32 Then
Offset = 3677
#End If
Dim FunctionPtr As Long
FunctionPtr = ShellcodePtr + Offset
ThrowAway = EnumCalendarInfoW(FunctionPtr, 2048, 1, 1)
End Sub
Checking the Microsoft documentation for EnumCalendarInfoW reveals that the first parameter is used to pass a callback function, which is used to process each information object as it is enumerated.  If the function returns a 1 then EnumCalendarInfoW will pass it the next information object; if it returns a 0 then control will pass back to the original caller.  Therefore as long as the shellcode exits with a 0 in the EAX register control will pass back to the macro and Word will continue to run normally.  Other HANCITOR samples examined have used the EnumDateFormats and CallWindowProc API calls to achieve the same result.

By setting a breakpoint on the call to EnumCalendarInfoW we can see the value of the address being passed as shown here.

Here the value is 18943581 or 0x1210E5D in Hex.

Stage 2 – Analysing the Shellcode

If we attach a debugger to word and go to this address we can see that it is indeed the start of a valid code block with a standard function preamble.
Looking at the memory map we can see that this memory area starts at 01210000 and is executable.
We can then save this memory location to disk and load it into IDA pro for static analysis.  The offset at which to start the analysis will be 0x0E5D as shown here.  During the load process we can specify the Loading Offset as 0x01210000 as shown here and in this way all offsets in IDA will be the same as those seen in the debugger.
Once the file has loaded we can go directly to the code at 0x0120E5D and press P in order to redefine the code as a function.  This allows the viewing of the code in Graph Mode.
Stepping through the code we first see several functions referenced and pointers saved to their addresses.  Here, for example, a pointer is saved to the API call IsBadReadPtr.  The GetProcAddress function is declared locally within the shellcode.
The shellcode then checks each memory mapped file looking for a specific “egg”.  In this case “BULLSHIT” (one of the other samples examined used “STARFALL”).  If found then the offset to the egg is stored and execution continues.
The next step is to call VirtualAlloc in order to create a new buffer to hold the payload, copy the payload into the buffer and then decipher it using a simple bitwise transform x => (x+3) ^ 14.  An earlier sample analysed used x => (x+3) ^ 11.
The shellcode next determines whether the process is a Wow64 Process or not and sets the name of the process to be created accordingly.  The process will be either %windir%\explorer.exe or %windir%\WOW64\svchost.exe.
Once this has been determined a process is started in the suspended state, hollowed out and then filled with the payload deciphered earlier.  Finally the new process is resumed and the shellcode exits.
In order to know what the Entry Point will be for the new process we can set a breakpoint on the call to SetThreadContext which occurs at 0x0121157B and examine the context structure passed to the new process.  The new entry point will be passed as EAX (offset 0xB0).  The screenshot below shows a hex dump of the context structure with the EAX field highlighted.  In this case the new entry point for the hollowed process will be 0x004020D0.
This can be confirmed by dumping the executable from it’s memory buffer, or carving it frrom the document, and running against it.
With the information gleaned so far it was possible to write a short python script (available here) which will scan for any potential “egg”, calculate the transform and extract the payload.  It also searches the payload for C2 URLs as these have been found to appear in plain text.  In the case of the file being analysed the output is:

Stage 3 – Examining the Payload

Examining the extracted payload with the file command shows that it is a standard windows executable, which can be analysed with IDA and OllyDbg.  Checking the hash of the file on VirusTotal shows that it has been submitted once before and, at the time of submission, was detected by 21/56 AV vendors as a trojan downloader.
Loading the executable into IDA shows that it is indeed a simple download trojan with no real features of interest. The executable is not packed or enciphered in anyway beyond that discussed here and uses the URLs shown above. New URLs can also be added by the C2.   Download modules can be either run in memory either as a thread of the trojan or as a newly hollowed process.  The downloader may also save modules to disk and it does drop a configuration file.
The diagram below shows the decompiled switch statement at the heart of the C2 loop.  All the main functions are visible.

Indicators of Compromise

File Hashes (MD5)
23f5344d5b0167b8b4662c862056adb0  – Word Doc
ddef86a97d892abbdc0f61407ec769fe  – Payload
b41f2365f8a44305bdc0e485100b3a0c – Word Doc
87cc7aecc62768b2de5b5778ce39cc1e  – Payload
f0905f5f10b3bd0744289b0c6ae00b49  – Word Doc
7d12e92a9025c881b9a53d8a8cabe074  – Payload
Extracted C2 URLs
Back to Blog