Custom Views

The upcoming 0.9.9 version of the Profiler will partially expose the use of custom views. These views are used internally by the Profiler to create complex graphical UIs using short XML strings. While at the moment extensions can use PySide to create complex UIs, it’s better to avoid it if possible, since it involves an extra dependency and also because PySide might not be ported to Qt 5 in the future.

But let’s see a code snippet:

from Pro.UI import *

ctx = proContext()
v = ctx.createView(ProView.Type_Custom, "Debug Directory")
v.setup("<ui><vsplitter><table id='0'/><hex id='1'/></vsplitter></ui>")
ctx.addView(v)

These few lines will display the following view:

Empty custom view

Controls can be organized in layouts (hlayout/vlayout), splitters (hsplitter/vsplitter) and tabs (tab). These elements are called containers. Available controls are: label, pie, plot, table, tree, hex, text and media.

More controls will be available in the future and not all of the current ones can be used as it is. Some controls make sense only in combination with a callback to be notified about changes of the state of the control. The notification system will be made available to Python as well in the future, but it made sense to release a partial solution in the meantime, because many views don’t require notifications and only need a way to display information at the end of an operation.

Let’s see for example how to make use of the UI above to display information.

Custom view

This code replicates the Debug Directory UI in Portable Executables.

from Pro.UI import *

ctx = proContext()
obj = ctx.currentScanProvider().getObject()
dbgdir = obj.DebugDirectory().MakeSingle()
dbgdata = ctx.currentScanProvider().getObjectStream()
dbgdata.setRange(*obj.DebugDirectoryData(dbgdir))

v = ctx.createView(ProView.Type_Custom, "Debug Directory")
v.setup("<ui><vsplitter><table id='0'/><hex id='1'/></vsplitter></ui>")
v.getView(0).setStruct(dbgdir)
v.getView(1).setData(dbgdata)
ctx.addView(v)

Elements in a view can have attributes. We’ve only seen the id attribute used to identify the embedded controls. There are two kind of attributes: shared attributes and individual ones. Only controls have these shared attributes: width, height, min-width, max-width, fixed-width and fixed-height. If a c is prefixed to the width/height word, then the size can be expressed in characters. e.g.: fixed-cwidth=’10’. Additionally, since version 1.3, there’s also wfixed and hfixed. Both are booleans which, if true, set the fixed size policy.

Here’s a list of individual attributes for controls and containers.

  • ui
    • bgcolor (e.g. ffffff)
  • hlayout/vlayout (hl/vl)
    • margin
    • spacing
    • align (hcenter, vcenter, center, top, left, bottom, right)
  • hsplitter/vsplitter (hs/vs)
    • sizes/csizes (separated by -)
  • tab
    • index
    • titles (separated by 😉
  • label
    • bgcolor (e.g. ffffff)
    • select (bool)
    • margin
  • text
    • readonly (bool)
    • linenr (bool, show line number)
    • hline (bool, highlight current line)
    • hword (bool, highlight current word)
    • wrap (bool)
  • combo (since version 1.3)
    • edit (bool)
    • text (string, only if editable)
  • btn (since version 1.3)
    • text (string, only if editable)
  • check (since version 1.3)
    • checked (bool)
    • text (string, only if editable)
  • tline (text-line, since version 2.5)

While this post doesn’t present many usage examples, we’ll try to show additional ones in future posts.

Dissecting an ELF with C++ Types

While there are more interesting targets which could be manually analyzed with the new features provided in the Profiler, I decided to write a small post about ELF, also because official support for ELF will be added sooner or later.

Let’s start by importing the types contained in ‘elf.h’. You’ll probably find this header in ‘/usr/include’. Everything we’re interested in is in this file, so we can avoid importing other stuff. I added some predefines in order to avoid includes:

#define int8_t char
#define uint8_t unsigned char
#define int16_t short
#define uint16_t unsigned short
#define int32_t int
#define uint32_t unsigned int
#define int64_t long long
#define uint64_t unsigned long long

Then I pasted ‘elf.h’ into the Header Manager after the HEADER_START directive and clicked on ‘Import’.

ELF types import

We now have a header (elf) with all the types we need to start the manual analysis.

Since this is just a demonstration I didn’t do a full analysis of the ELF format. I limited the scope to finding the imported symbols and their strings.

ELF analysis

Every ELF starts with a _Elf64_Ehdr header (Elf32_Ehdr for 32-bit files, in this case it’s a 64-bit ELF). The header specifies the offset, number and size of the sections (we’ll just assume the standard 0x40 size here). The ‘name’ field of sections is just an index into a ‘SHT_STRTAB’ section whose index is specified by the header. The contents of a section are specified by its type, so finding the symbol table is pretty straight-forward. In this ELF we have a SHT_DYNSYM section. This section is just an array of _Elf64_Sym structures. Again, their ‘st_name’ field is just an index into another SHT_STRTAB section (the interval in the screenshot named ‘.dynstr’).

As already mentioned in the previous post, we can create a layout programmatically as well:

from Pro.Core import *
from Pro.UI import *

def buildElfLayout(obj, l):
    hname = "elf"
    hdr = CFFHeader()
    if hdr.LoadFromFile(hname) == False:
        return
    sopts = CFFSO_GCC | CFFSO_Pack1
    d = LayoutData()
    d.setTypeOptions(sopts)
    
    # add header
    ehdr = obj.MakeStruct(hdr, "_Elf64_Ehdr", 0, sopts)
    d.setColor(ntRgba(255, 0, 0, 70))
    d.setStruct(hname, "_Elf64_Ehdr")
    l.add(0, ehdr.Size(), d)

    # add sections (we assume that e_shentsize is 0x40)
    e_shoff = ehdr.Num("e_shoff")
    e_shnum = ehdr.Num("e_shnum")
    esects = obj.MakeStructArray(hdr, "_Elf64_Shdr", e_shoff, e_shnum, sopts)
    d.setStruct(hname, "_Elf64_Shdr")
    d.setArraySize(e_shnum)
    l.add(e_shoff, esects.TotalSize(), d)

hv = proContext().getCurrentView()
if hv.isValid() and hv.type() == ProView.Type_Hex:
    c = hv.getData()
    obj = CFFObject()
    obj.Load(c)
    lname = "ELF_ANALYSIS" # we could make the name unique
    l = proContext().getLayout(lname) 
    buildElfLayout(obj, l)
    # apply the layout to the current hex view
    hv.setLayoutName(lname)

Moreover, the imported types can be used to do other operations not related to layouts. For instance let’s write few lines of code to print out the symbol names for this ELF:

from Pro.Core import *

obj = proCoreContext().currentScanProvider().getObject()

hdr = CFFHeader()
if hdr.LoadFromFile("elf"):
    syms = obj.MakeStructArray(hdr, "_Elf64_Sym", 0x39A0, 2179, CFFSO_GCC | CFFSO_Pack1)
    it = syms.iterator()
    while it.hasNext():
        s = it.next()
        name_offs = s.Num(0) + 0x105E8 # .dynstr offset
        name = obj.ReadUInt8String(name_offs, 0x1000)[0].decode("utf-8")
        print(name)

The output will be:

endgrent
__ctype_toupper_loc
iswlower
sigprocmask
__snprintf_chk
getservent
wcscmp
putchar
strcasecmp
localtime
mblen
__vfprintf_chk
; etc.

Rememebr that the advantages of using CFFStructs rely not only in their dynamism or easiness in displaying them graphically, but also security. Contrary to a structure pointer in C, there’s no risk of crash when accessing members in a CFFStruct.

Today some final tests will be performed on the new version and if everything goes well, it will be released tomorrow or the day after. So stay tuned!

Disasm options & filters

The upcoming version 0.9.4 of the Profiler introduces improvements to several disasm engines: ActionScript3, Dalvik, Java, MSIL. In particular it adds options, so that the user can decide whether to include file offsets and opcodes in the output.

Disasm options

The code indentation can be changed as well.

Another important addition is that these engines have been exposed as filters. This is especially noteworthy since byte code can sometimes be injected or stored outside of a method body, so that it is necessary to be able to disassemble raw data.

Disasm filters

Of course these filters can be used from Python too.

from Pro.Core import *

sp = proContext().currentScanProvider()
c = sp.getObjectStream()
c.setRange(0x2570, 0x10)

fstr = ""
c = applyFilters(c, fstr)

s = c.read(0, c.size()).decode("utf-8")
print(s)

Output:

/* 00000000 1A 00 8A+ */ const-string v0,  // string@018a (394)
/* 00000004 12 01     */ const/4 v1, #int 0 // #0
/* 00000006 12 22     */ const/4 v2, #int 2 // #2
/* 00000008 70 52 42+ */ invoke-direct {v3, v4, v0, v1, v2},  // method@0042 (66)
/* 0000000E 0E 00     */ return-void

In the future it will be possible to output a filter directly to NTTextStream, avoiding the need to read from NTContainer.

Stay tuned!

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.

Exposing the Core (part 4, Hooks)

Hooks are an extremely powerful extension to the scanning engine of Cerbero Suite. They allow the user to do customize scans and do all sorts of things. Because there’s basically no limit to the applications, I’ll just try to give a brief introduction in this post. In the following post I’ll demonstrate their use with a real-world case.

Just like key providers introduced in the previous post, hooks have their INI configuration file as well (hooks.cfg). This can contain a minimal hook entry:

[Test Hook]
file = test_hooks.py
scanned = scanned

And the python code:

def scanned(sp, ud):
    print(sp.getObjectFormat())

scanned gets called after every file scan and prints out the format of the object. This function is not being called from the main thread, so it’s not possible to call UI functions. However, print is thread-safe and when doing a batch scan will just output to stdout.

Now let’s open Cerbero Suite and go to the new Extensions view.

Extensions view

You’ll notice that the box next to the name of the hook we just created is unchecked. This means that it’s disabled and hence won’t be called. We can enable it manually or we may even specify from the INI file to enable our extension by default:

[Test Hook]
file = test_hooks.py
scanned = scanned
enable = yes

We also specify the scan mode we are interested in:

; not specifying a mode equals to: mode = single|batch
mode = batch

Now the extension will be notified only when doing batch scans. To be even more selective, it’s possible to specify the file format(s) we are interested in:

; this is an optional field, you can omit it and the hook will be notified for any format
formats = PE|SWF

Ok, now let’s create a small sample which actually does something. Let’s say we want to perform a search among the disassembled code of Java Class files and include in the resulting report only those files which contain a particular string.

The configuration entry:

[Search Java Class]
file = test_hooks.py
scanned = searchJavaClass
mode = batch
formats = Class

And the code:

def searchJavaClass(sp, ud):
    from Pro.Core import NTTextBuffer
    cl = sp.getObject()
    out = NTTextBuffer()
    cl.Disassemble(out)
    # search string
    ret = out.buffer.find("HelloWorld") != -1
    sp.include(ret)

Let’s activate the extension by checking its box and then perform a custom scan only on files identified as Java Classes.

Class scan

The result will be:

Class report

The method ScanProvider::include(bool b) is what tells Cerbero Suite which files have to be included in the final report (its counterpart is ScanProvider::exclude(bool b)). Of course, there could be more than one hook active during a scan and a file can be both excluded and included. The logic is that include has priority over exclude and once a file has been included by a hook it can’t be excluded by another one.

Although the few lines above already have a purpose, it’s not quite handy having to change the code in order to perform different searches. Thus, hooks can optionally implement two more callbacks: init and end. Both these callbacks are called from the main UI thread (so that it’s safe to call UI functions). The first one is called before any scan operation is performed, while the latter after all of them have finished.

The syntax for for these callbacks is the following:

def init():
    print("init")
    return print  # returns what the other callbacks will get as their 'ud' argument

def end(ud):
    ud("end")

Instead of using ugly global variables, init can optionally return the user data passed on to the other callbacks. end is useful to perform cleanup operations. But in our sample above we don’t really need to clean up anything, we just need an input box to ask the user for a string to be searched. So we just need to add an init callback.

[Search Java Class]
file = test_hooks.py
init = initSearchJavaClass
scanned = searchJavaClass
mode = batch
formats = Class

And add the new logic to the code:

def initSearchJavaClass():
    from Pro.UI import ProInput
    return ProInput.askText("Insert string:")

def searchJavaClass(sp, ud):
    if ud == None:
        return
    from Pro.Core import NTTextBuffer
    cl = sp.getObject()
    out = NTTextBuffer()
    cl.Disassemble(out)
    # search string
    ret = out.buffer.find(ud) != -1
    sp.include(ret)

Of course, this sample could be improved endlessly by adding options, regular expressions, support for more file formats etc. But that is beyond the scope of this post which was just briefly introduce hooks.

The upcoming version of Cerbero Suite which includes all the improvements of the previous weeks is almost ready. Stay tuned!

Exposing the Core (part 3, Key Providers)

This post will be about key providers, which are the first kind of extension to the scan engine we’re going to see. Key providers are nothing else than a convenient way to provide keys through scripting to files which require a decryption key (e.g. an encrypted PDF).

Let’s take for instance an encrypted Zip file. If we’re not doing a batch scan, Cerbero Suite will ask the user with its dialog to enter a decryption key. While this dialog already has the ability to accept multiple keys and also remember them, there are things it can’t do. For example it is not suitable for trying out key dictionaries (copy and pasting them is inefficient) or to generate a key based on environmental factors (like the name of the file requiring the decryption).

This may sound all a bit complicated, but don’t worry. One of the main objectives of Cerbero Suite is to allow users to do things in the simplest way possible. Thus, showing a practical sample is the best way to demonstrate how it all works.

You’ll notice that the upcoming version of Cerbero Suite contains a keyp.cfg_sample in its config directory. This file can be used as template to create our first provider, just rename it to keyp.cfg. As all configuration files, this is an INI as well. This is what an entry for a key provider looks like:

[KeyProvider Test]
file = key_provider.py
callback = keyProvider
; this is an optional field, you can omit it and the provider will be used for any format
formats = Zip|PDF

Which is pretty much self explaining. It tells Cerbero Suite where our callback is located (the relative path defaults to the plugins/python directory) and it can also optionally specify the formats which may be used in conjunction with this provider. The Python code can be as simple as:

from Pro.Core import *

def keyProvider(obj, index):
    if index != 0:
        return None
    l = NTVariantList()
    l.append("password")
    return l

The provider returns a single key (‘password’). This means that when one of the specified file formats is encrypted, all registered key providers will be asked to provide decryption keys. If one key works, the file is automatically decrypted.

The returned list can contain even thousands of keys, it is up to the user to decide the amount returned. The index argument can be used to decide which bulk of keys must be returned, it starts at 0 and is incremented by l.size(). The key provider will be called until a match is found or it doesn’t return any more keys. Thus, be careful not to always return a key without checking the index, otherwise it’ll result in an endless loop.

When a string is appended to the list, then it will be converted internally by the conversion handlers to bytes (this means that a single string could, for instance, first be converted to UTF8 then to Ascii in order to obtain a match). Sometimes you want to return the exact bytes to be matched. In that case just append a bytearray object to the list.

The same sample could be transformed into a key generation based on variables:

from Pro.Core import *

def keyProvider(obj, index):
    if index != 0:
        return None
    name = obj.GetStream().name()
    # do some operations involving the file name
    variable_part = ...
    l = NTVariantList()
    l.append("static_part" + variable_part)
    return l

And this comes handy when we want to avoid typing in passwords for certain Zip archives which have a fixed decryption key schema.

So, to sum up key providers are powerful and easy-to-use extensions which allow us to test out key dictionaries on various file formats (those for which Cerbero Suite supports decryption) and to avoid the all too frequent hassle of having to type common passwords.

Exposing the Core (part 2)

The release date of the upcoming 0.9.3 version is drawing nearer. Several format classes have already been exposed to Python and in this post I’m going to show you some code snippets. Since it’s impossible to demonstrate all format classes (12 have already been exposed) and all their methods (a single class may contain dozens of methods), the purpose of the snippets below is only to give the reader an idea of what can be achieved.

The SDK organization has changed a bit: because of its increasing size it made sense to subdivide it into modules. Thus, there’s now the Pro.Core module, the Pro.UI one and one module for each format (e.g. Pro.PE).

PDF

This is how we can output to text the raw stream of a PDF:

from Pro.Core import *
from Pro.PDF import *

c = createContainerFromFile(fname)
pdf = PDFObject()
pdf.Load(c)
objtable = pdf.BuildObjectTable()
pdf.SetObjectTable(objtable)
oid = PDFObject.OBJID(3, 0)
ret, dict, content, info = pdf.ParseObject(objtable, oid)
out = NTTextBuffer()
out.printHex(content)
print(out.buffer)

Output:

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

0000   48 89 24 8D CD 0A 83 30  10 84 EF 81 BC C3 1C 93    H.$....0........
0010   8B 4D 52 63 E3 B5 D0 0A  42 A1 D0 DC C4 83 D4 F8    .MRc....B.......
0020   D3 D6 0A 2A F5 F5 BB B6  B0 CC 2E C3 37 3B 1A 2D    ...*........7;.-
0030   67 2A B2 C8 38 D3 C8 A1  F0 80 C6 8A 18 17 14 7B    g*..8..........{
0040   94 0A 35 67 BB EC 66 D0  CE 1B D1 83 34 75 48 92    ..5g..f.....4uH.
0050   04 46 C7 B0 0E 53 E0 EC  48 E3 09 3C 1B 4A FB 86    .F...S..H..<.J..
0060   18 43 AF 14 68 19 7D 88  1C 05 52 05 3F 50 D7 DF    .C..h.}...R.?P..
0070   C7 73 3B FD FD A7 2B 67  85 B8 CA 58 89 6A 5E 02    .s;...+g...X.j^.
0080   96 2E A0 E9 C3 AB 46 F5  AE 31 8C 52 5B F1 91 C6    ......F..1.R[...
0090   8A 20 95 C0 32 A2 0B 53  D8 CC 48 96 3E E7 EC 44    . ..2..S..H.>..D
00A0   CD 5F 01 06 00 88 1E 2A  AA 0D 0A                   ._.....*...    

Streams in PDFs are usually compressed. Here’s how we can decode the same stream:

from Pro.Core import *
from Pro.PDF import *

c = createContainerFromFile(fname)
pdf = PDFObject()
pdf.Load(c)
objtable = pdf.BuildObjectTable()
pdf.SetObjectTable(objtable)
oid = PDFObject.OBJID(3, 0)
ret, dict, content, info = pdf.ParseObject(objtable, oid)
content = pdf.DecodeObjectStream(content, dict, oid)
out = NTTextBuffer()
out.printHex(content)
print(out.buffer)

Output:

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

0000   31 20 67 0D 0A 30 2E 35  20 47 0D 0A 31 20 4A 20    1 g..0.5 G..1 J 
0010   30 20 6A 20 31 20 77 20  34 20 4D 20 5B 33 20 5D    0 j 1 w 4 M [3 ]
0020   30 20 64 0D 0A 2F 47 53  32 20 67 73 0D 0A 31 20    0 d../GS2 gs..1 
0030   69 20 0D 0A 31 39 38 20  36 36 36 20 32 31 34 20    i ..198 666 214 
0040   35 38 20 72 65 0D 0A 42  0D 0A 42 54 0D 0A 2F 46    58 re..B..BT../F
0050   32 20 31 20 54 66 0D 0A  31 32 20 30 20 30 20 31    2 1 Tf..12 0 0 1
0060   32 20 32 31 37 2E 38 38  20 36 39 30 20 54 6D 0D    2 217.88 690 Tm.
0070   0A 30 20 30 20 30 20 31  20 6B 0D 0A 30 20 54 63    .0 0 0 1 k..0 Tc
0080   0D 0A 30 20 54 77 0D 0A  5B 28 50 29 34 30 28 61    ..0 Tw..[(P)40(a
0090   73 74 65 20 74 68 65 20  66 69 65 6C 64 20 61 6E    ste the field an
00A0   64 20 6D 6F 29 31 35 28  76 29 32 35 28 65 29 30    d mo)15(v)25(e)0
00B0   28 20 74 6F 20 68 65 72  65 29 31 35 28 2E 29 5D    ( to here)15(.)]
00C0   54 4A 0D 0A 45 54 0D 0A                             TJ..ET..        

We might also want to iterate through the key/value pairs of a PDF dictionary. Thus, iterators have been implemented everywhere they could be applied. While they don’t yet support the standard Python syntax they are very easy to use:

from Pro.Core import *
from Pro.PDF import *

c = createContainerFromFile(fname)
pdf = PDFObject()
pdf.Load(c)
objtable = pdf.BuildObjectTable()
pdf.SetObjectTable(objtable)
oid = PDFObject.OBJID(3, 0)
ret, dict, content, info = pdf.ParseObject(objtable, oid)
it = dict.iterator()
while it.hasNext():
    k, v = it.next()
    print(k + " - " + v)

Output:

/Length - 171
/Filter - /FlateDecode

Iterating through the objects of a PDF amounts to the same logic:

from Pro.Core import *
from Pro.PDF import *

c = createContainerFromFile(fname)
pdf = PDFObject()
pdf.Load(c)
objtable = pdf.BuildObjectTable()
it = objtable.iterator()
while it.hasNext():
    k, v = it.next()
    # print out the object id
    print(str(k >> 32))

CFBF (DOC, XLS, PPT, MSI, etc.)

Iterating through the directories of a CFBF can be as simple as:

from Pro.Core import *
from Pro.CFBF import *

def visitor(obj, ud, dir_id, children):
    name = obj.DirectoryName(dir_id)
    print(name)
    return 0

c = createContainerFromFile(fname)
cfb = CFBObject()
cfb.Load(c)
dirs = cfb.BuildDirectoryTree()
cfb.SetDirectoryTree(dirs)
cfb.VisitDirectories(dirs, visitor, None)

Output:

Root Entry
\1CompObj
\1Ole
1Table
\5SummaryInformation
WordDocument
\5DocumentSummaryInformation

Retrieving a stream is equally easy:

from Pro.Core import *
from Pro.CFBF import *

c = createContainerFromFile(fname)
cfb = CFBObject()
cfb.Load(c)
dirs = cfb.BuildDirectoryTree()
cfb.SetDirectoryTree(dirs)
s = cfb.Stream(1)
b = s.read(0, s.size()) # read bytes
t = NTTextBuffer()
t.printHex(b)
print(t.buffer)

Output:

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

0000   01 00 FE FF 03 0A 00 00  FF FF FF FF 06 09 02 00    ................
0010   00 00 00 00 C0 00 00 00  00 00 00 46 18 00 00 00    ...........F....
0020   4D 69 63 72 6F 73 6F 66  74 20 57 6F 72 64 2D 44    Microsoft Word-D
0030   6F 6B 75 6D 65 6E 74 00  0A 00 00 00 4D 53 57 6F    okument.....MSWo
0040   72 64 44 6F 63 00 10 00  00 00 57 6F 72 64 2E 44    rdDoc.....Word.D
0050   6F 63 75 6D 65 6E 74 2E  38 00 F4 39 B2 71 00 00    ocument.8..9.q..
0060   00 00 00 00 00 00 00 00  00 00                      ..........      

SWF

Here’s how to output the disasm of an ActionScript2 Flash file:

from Pro.Core import *
from Pro.SWF import *

c = createContainerFromFile(fname)
swf = SWFObject()
swf.Load(c)
if swf.IsCompressed():
    swf.Decompress()
tl = swf.EnumerateTags()
swf.SetStoredTags(tl)
out = NTTextBuffer()
swf.AS2Disassemble(out)
print(out.buffer)

The same can be done for ActionScript3 using the ABCFileObject class.

Class

This is how to disassemble a Java Class file:

from Pro.Core import *
from Pro.Class import *

c = createContainerFromFile(fname)
cl = ClassObject()
cl.Load(c)
cl.ProcessClass()
out = NTTextBuffer()
cl.Disassemble(out)
print(out.buffer)

DEX

This is how to disassemble an Android DEX file class:

from Pro.Core import *
from Pro.DEX import *

c = createContainerFromFile(fname)
dex = DEXObject()
dex.Load(c)
# disassemble the last class
classes = dex.Classes()
token = classes.Count() - 1
out = NTTextBuffer()
dex.Disassemble(out, token)
print(out.buffer)

In the upcoming post(s) I’m going to put it all together and do some very interesting things.
So stay tuned as the best has yet to come!

Exposing the Core (part 1)

The main feature of the upcoming 0.9.3 version of the Profiler is the expansion of the public SDK. This basically means that a consistent subset of the internal classes will be exposed. Although it’s a subset, there’s no way to document all methods and functions. Fortunately, many of them should be quite intuitive.

Some of the most common important classes are:

  • NTContainer: this is a generic container which is used to encapsulate data such as files and memory. It’s an extremely important class, since it’s used extensively. Containers can for the time being be created through SDK functions such as: createContainerFromFile/newContainer.
  • NTBuffer/NTContainerBuffer/CFFBuffer/etc.: used to efficiently read iteratively small amounts of data from a source.
  • NTTextStream/NTTextBuffer/NTTextStringBuffer: used to output text. Indentation can be specified.
  • NTXml: used to parse XML. Fast and secure. This class is based on RapidXML.
  • CFFObject: the class from which every format class inherits (ZipObject, PEObject, etc). A very small subset of this class is exposed for now. This will change in the future.
  • CFFStruct: representation of a file format structure.
  • CFFFlags: representation of flags in a CFFStruct.

One of the new additions is that Python can now use filters as well. Do you remember the post about Widget and Views? Let’s use the same code base and change just a few lines:

from Pro import *
from PySide import QtCore, QtGui
 
class MixedWidget(QtGui.QSplitter):
    def __init__(self, parent=None):
        super(MixedWidget, self).__init__(parent)
 
        self.setWindowTitle("Mixed widget")
        self.setOrientation(QtCore.Qt.Vertical)
 
        self.model = QtGui.QDirModel()
        tree = QtGui.QTreeView()
        tree.setModel(self.model)
        self.addWidget(tree)
 
        ctx = proContext()
        self.hex = ctx.createView(ProView.Type_Hex, "")
        self.addWidget(self.hex.toWidget())
 
        tree.activated.connect(self.updateFile)
 
    def updateFile(self, idx):
        if self.model.isDir(idx) == True:
            self.hex.clear()
        else:
            # modified lines
            name = self.model.filePath(idx)
            c = createContainerFromFile(name)
            fstr = ""
            c = applyFilters(c, fstr)
            self.hex.setData(c)
            # end
 
 
ctx = proContext()
w = MixedWidget()
v = ctx.createViewFromWidget(w)
ctx.addView(v)

With just three of the modified lines we are xoring all opened files with the value 0xCC and then show the resulting data in the hex view. The Profiler provides a huge number of filters for any kind of operation and they can be chained, so we could easily compress and then encrypt a file with AES by just replacing one line in the sample above. The function applyFilters displays an optional default wait dialog to the user to interrupt the operation (if it is executing in the main thread). Please remember that the easiest way to obtain the needed filters XML string is to use the UI view and use the export command from the list (context menu->Export…).

NTBuffer generates an exception when a read operations fail. Thus, it should be used as follows:

ctx = proContext()
v = ctx.getCurrentView()
d = v.getData()
b = NTContainerBuffer(d, ENDIANNESS_LITTLE, 0)
print(str(hex(b.u8())))
try:
    b.read(10) # or b.u8(), b.u16(), etc.
except IndexError as e:
    print(str(e))

A small snippet to show how to use NTXml:

x = NTXml()
ret = x.parse("")
if ret == NTXml_ErrNone:
    n = x.findChild(None, "r")
    if n != None:
        n = x.findChild(n, "e")
        if n != None:
            a = x.findAttribute(n, "t")
            if a != None:
                print(x.value(a))

Along with the core, several of the file objects will be exposed. A text dump of a structure could be as easy as:

c = createContainerFromFile(fname)
pe = PEObject()
pe.Load(c)
out = NTTextStringBuffer()
pe.DosHeader().Dump(out) # CFFStruct::Dump
print(out.buffer)

Please notice that the code above misses several checks. We need to make sure that c is valid and Load succeds. I’ll omit these checks here to keep the code minimal.

You might say that printing out a single structure is an easy task. So let’s take a look at another cooler sample:

c = createContainerFromFile(fname)
pe = PEObject()
pe.Load(c)
out = NTTextStringBuffer()
tables = pe.MDTables("#~") # 'tables' references all .NET metadata tables
pe.DisassembleMSIL(out, 0x06000001) # .NET token (MethodDef | index)
print(out.buffer)

These few lines output an entire .NET method such as:

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
}

Nice, isn’t it? Remember we can change the indentation programmatically.

Of course, it will also be possible to get the object currently being analyzed and similar stuff. But we’ll see how to do that in another post.

If you’re wondering why the case convention for methods is not always the same, the reason is simple. CFFObject/CFFStruct/etc are based on older code which followed the Win32-like convention. Consequently all derived classes like PEObject follow this convention. All other classes use the camel-case convention.

Widgets and Views

The last release of the Profiler featured some significant improvements. So while it also included initial PySide support, there wasn’t much time to make it really nice. One of the missing things was the ability to mix internal Profiler views (such as the hex editor) with PySide widgets. With the upcoming 0.9.2 release it will be possible to create a view and obtain a PySide widget with just one method:

widget = view.toWidget()

This way one can make use of advanced internal views of the Profiler and combine them with other custom controls. Let’s see a practical example.

Mixed widget

The widget in the screenshot combines a QTreeView with a directory model and a hex view. When a file is activated in the tree, it is opened by the hex editor. To try it out, just press Ctrl+Alt+R and enter the following code:

from Pro import *
from PySide import QtCore, QtGui

class MixedWidget(QtGui.QSplitter):
    def __init__(self, parent=None):
        super(MixedWidget, self).__init__(parent)

        self.setWindowTitle("Mixed widget")
        self.setOrientation(QtCore.Qt.Vertical)

        self.model = QtGui.QDirModel()
        tree = QtGui.QTreeView()
        tree.setModel(self.model)
        self.addWidget(tree)

        ctx = proContext()
        self.hex = ctx.createView(ProView.Type_Hex, "")
        self.addWidget(self.hex.toWidget())

        tree.activated.connect(self.updateFile)

    def updateFile(self, idx):
        if self.model.isDir(idx) == True:
            self.hex.clear()
        else:
            name = self.model.filePath(idx)
            self.hex.setFileName(name)


ctx = proContext()
w = MixedWidget()
v = ctx.createViewFromWidget(w)
ctx.addView(v)

Amazingly little code snippet, right? Please note that the ProHexView setFileName method is also a new addition to the SDK.

PySide support

This is really a small addition which took just a couple of hours of work, but since it can come very handy, it’s worth dedicating a post to it. The upcoming 0.9.1 version of the Profiler adds explicit support for PySide. Thus, it will be possible to create Qt widgets and add them to the workspace.

Installing PySide

First of all, let’s install PySide. There are 3 ways to do this.

1) Install it from the qt-project page.

Make sure you select the package matching the current Python version used by the Profiler.

2) Install the package we compiled for you. It’s vanilla, directly from the original sources, but it has the advantage that it is guaranteed to work. In fact, at the time of writing the official package contains a bug (missing shiboken Python module) and so the first one is not really an option until it is not fixed.

Download
SHA1: 2024348E79890A167BB231098A6A16FC8BB02C9E

3) You can compile PySide yourself following the instructions at qt-project. At the end, use the installer created inside ‘c:\pyside-setup\dist’.

A code sample

Using it is even easier than the setup process. Basically ProContext has a new method called createViewFromWidget which takes as a parameter a widget created by PySide and returns a ProView which in turn can be added to the workspace.

Adding a widget to the workspace only takes the following line:

ctx.addView(ctx.createViewFromWidget(widget))

Therefore using an existing widget and adding it to the workspace is very easy. Let’s see a real-world widget like an official PySide sample: PySide/examples/effects/lighting.py. It’s sufficient to remove:

if __name__ == '__main__':

    import sys

    app = QtGui.QApplication(sys.argv)

    lighting = Lighting()
    lighting.setWindowTitle("Lighting and Shadows")
    lighting.resize(640, 480)
    lighting.show()

    sys.exit(app.exec_())

And add:

lighting = Lighting()
lighting.setWindowTitle("PySide widget")

ctx = proContext()
ctx.addView(ctx.createViewFromWidget(lighting))

Now we can add an action to execute the code or just insert it in the custom script box (Ctrl+Alt+R) and the view will be shown like this:

To set a custom icon for the view use setWindowIcon.

As usual stay tuned as the upcoming version is going to include some major additions and significant changes.