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.
The steps needed to write the script:
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 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
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.