Latest available version: IDA and decompilers v8.4.240320 see all releases
Hex-Rays logo State-of-the-art binary code analysis tools
email icon

It is said that a picture is worth a thousand words, and similarly many reversers would agree that a graph is worth a thousand lists! 😉

Recently, we added graphing support into IDAPython and now Python scripts can build interactive graphs.
To demonstrate this new addition, we will write a small script that graphs the structured exception handlers of a given process.


sehgraph_small.png

Writing the script

The steps needed to write the script:

  1. For each thread in the process:
    1. Retrieve the linear address of FS:[0]
    2. Walk the exception registration record list and save the handler
  2. Build the graph:
    1. Allocate one node for each unique exception handler address
    2. Add edges between the last exception handler and the current exception handler (so to create the chain visually)
  3. Display the graph

Walking the exception registration records

In Win32, a new SEH is installed by filling an EXCEPTION_REGISTRATION_RECORD entry and linking it to the SEH chain (at FS:[0]).

typedef struct _EXCEPTION_REGISTRATION_RECORD
{
  struct _EXCEPTION_REGISTRATION_RECORD *Prev;
  PEXCEPTION_HANDLER       Handler;
} EXCEPTION_REGISTRATION_RECORD;

Before walking the exception registration records, we need to get the base address of the FS selector.
Fortunately, each debugger module provides a special callback in its debugger_t structure:

// Get information about the base of a segment register
//   tid        - thread id
//   sreg_value - value of the segment register
//   answer     - pointer to the answer. can't be NULL.
// 1-ok, 0-failed, -1-network error
int (idaapi *thread_get_sreg_base)(
  thid_t tid,
  int sreg_value,
  ea_t *answer);

To use this callback, we will pass the FS selector value:

def GetFsBase(tid):
    idc.SelectThread(tid)
    return idaapi.dbg_get_thread_sreg_base(tid, cpu.fs)

or in C:

ea_t fs_base;
dbg->thread_get_sreg_base(tid, fs_sel_value, &fs_base);

Now that we have the base, we can compute the linear address of the exception registration record list head by adding the base (fs_base) to the offset (which happens to be zero), thus: fs_base + 0
With this knowledge, we can write a small loop to walk this list and extract the handlers:

def GetExceptionChain(tid):
    fs_base = GetFsBase(tid)
    exc_rr = Dword(fs_base)
    result = []
    while exc_rr != 0xffffffff:
        prev    = Dword(exc_rr)
        handler = Dword(exc_rr + 4)
        exc_rr  = prev
        result.append(handler)
    return result

We do that for each thread:

    # Iterate through all function instructions and take only call instructions
    result = {}
    for tid in idautils.Threads():
        result[tid] = GetExceptionChain(tid)

Building the graph

Building the graph is even simpler and can be done by subclassing the GraphViewer class and implementing the OnRefresh() and OnGetText() events.
Here’s the simplified version of the graph building loop:

def OnRefresh(self):
  self.Clear() # clear previous nodes
  addr_id = {}
  for (tid, chain) in self.result.items():
    # Add the thread node
    id_parent = self.AddNode("Thread %X" % tid)
    # Add each handler
    for handler in chain:
      # Get the node id given the handler address
      # We use an addr -> id dictionary
      # so that similar addresses get similar node id
      if not addr_id.has_key(handler):
        id = self.AddNode( hex(handler) )
        addr_id[handler] = id # add this ID
      else:
        id = addr_id[handler]
      # Link handlers to each other
      self.AddEdge(id_parent, id)
      # Now the parent node is this handler
      id_parent = id
  return True

Putting it all together

The script will display the thread nodes and the handlers in different colors. Double clicking on a handler node will jump to it in an IDA-View and double clicking on a thread node will display the exception handlers in the message window. Here are some SEH graphs:

IDA/Graphical version (idag.exe):

Visual Studio 2008 (devenv.exe):

Please download the script from here (you need IDAPython r242 and above).
All comments and suggestions are welcome. You are also encouraged to share screenshots of interesting SEH graphs you run into.