Developer Docs

Table of Contents

  1. Overview
  2. Installation
  3. Scripts and Tools
  4. Console (GUI) and Modules
  5. Developer Docs

Working with the Libraries

Overview

As a developer you have two options for building tools on top of the framework, you can either create a command line tool or you can go one step further and create a module for the console (GUI). Aside from existing scripts and examples, the best reference for developers building utilities on top of PaiMei is the generated Epydoc documentation:

pGRAPH

TODO: add docs and examples

PIDA

TODO: add docs and examples

PyDbg

TODO: add docs and examples

Utilities

TODO: add docs and examples

Creating GUI Modules

Overview

If you plan on creating a module for PaiMei, read through this document and refer to existing modules for examples. There are a few standards that should be met in order to maintain consistency across the framework. If you want your tool included in the default public release bundle, please contact me directly: pedram [dot] amini [at] gmail [dot] com. You should know in advance however that I am completely obsessive compulsive with my code ... so make it clean and please document ;-)

Structure

PaiMei will scan the images/icons directory on startup, looking for modules to load. If you create a new module and do not create an icon for it, your module will be ignored. The Photoshop template for icons is available in the docs directory, it is named Listbook Graphic Templates.psd. The core of the module itself must be implemented as a WxPanel and placed in the modules directory with the same name of the icon. All modules should be prefixed with "PAIMEI" and contain only lower-case letters in the name. For example, to add a module named 'explorer', create the following files:
    images\icons\PAIMEIexplorer.png
    modules\PAIMEIexplorer.py
Support files for your module should be placed under a subdirectory within modules with the name '_PAIMEI[module name]'. Following our example:
    modules\_PAIMEIexplorer\*

WxGlade

I recommend using WxGlade to build the basic structure / layout of your GUI module. Recall that the module you are creating must be implemented as a WxPanel. Launch WxGlade and create a new panel, naming both the panel and class 'PAIMEI[module_name]'. Select the option "Separate file for each class" and generate the Python code for your module. The panel you created will be implemented in 'PAIMEI[module name].py'. This is the file you will be editing / adding to. I've included the WxGlade project used to create some of the GUI panels and controls distributed with the first release of PaiMei in the top level docs directory, named PAIMEIwxglade.wxg.

Functions and Variables

All module variables that you wish to expose to the user should be declared as class level variables. Class variables must be documented such as to guide users who may be interacting with your module through the command line interface. To document the variable, add an entry to the 'documented_properties' dictionary. Example:
    documented_properties = {
        "pida_modules" : "Dictionary of loaded PIDA modules.",
    }
There are two class variables that you should declare in your module to access the global PaiMei namespace, self.list_book and self.main_frame:
    self.list_book  = kwds["parent"]             # handle to list book.
    self.main_frame = self.list_book.top         # handle to top most frame. 
    
These handles are necessary for accessing the namespace of other modules and, more importantly, accessing the top level MySQL, PyDbg and uDraw variables (through self.main_frame.xxxx). When creating new controls, you should pass self, which within the control should be assigned to self.top, so that individual controls can access these variables as well (through self.top.main_frame.xxxx

Interacting with the Status Bar

The PaiMei status bar is split into two halves. The left half is reserved for the framework, the right half is for you to use freely for your module. Utilization of the status bar is optional, the method for interacting with the status bar is not. To begin, you must define two routines in your module:
    ####################################################################################################################
    def _get_status (self):
        '''
        Return the text to display in the status bar on page change.
        '''
     
        return self.status_msg
     
    ####################################################################################################################
    def _set_status (self, status_msg):
        '''
        Set the text to display in the status bar.
        '''
     
        self.status_msg = status_msg
        self.main_frame.status_bar.SetStatusText(self.status_msg, 1)
    
The _get_status() routine is called from the console as the user selects between various modules. This allows your module to maintain a status message persistently as the user transitions back and forth between modules.

Creating a Log Window

Utilizing a log window is optional. However, if you plan on using one it should be placed within a splitter and must be named 'log'. You must then create and bind a routine for handing situations where generated log data exceeds the maximum size of the log control:
    self.Bind(wx.EVT_TEXT_MAXLEN, self.OnMaxLogLengthReached, self.log)
     
    ####################################################################################################################
    def OnMaxLogLengthReached (self, event):
        '''
        Clear the log window when the max length is reach.
        
        @todo: Make this smarter by maybe only clearing half the lines.
        '''
        
        self.log.SetValue("")
If you are placing your log control in a splitter window (which is wise) and you want to prevent the user from accidentally closing the log window. Then set a minimum pane size on the containing sizer:
    self.log_splitter.SetMinimumPaneSize(25)
Finally, create and utilize the following shortcut routines to the log control:
    ####################################################################################################################
    def err (self, message):
        '''
        Write an error message to log window.
        '''
     
        self.log.AppendText("[!] %s\n" % message)
     
     
    ####################################################################################################################
    def msg (self, message):
        '''
        Write a log message to log window.
        '''
     
        self.log.AppendText("[*] %s\n" % message)

Take Pride in your Work

At the bottom of the __init__() routine for your main wxPanel, write your name and module name to the log window:
    self.msg("PaiMei Explorer")
    self.msg("Module by Pedram Amini\n")

Some Final Notes

In case you haven't already noticed, there is no console-wide (global) PIDA modules container. Instead, each GUI module within PaiMei is responsible for loading and storing it's own PIDA modules. The reasoning behind this is that various console modules may have custom modifications they may need to make to the PIDA module on load, that can result in incompatibilities with other console modules. These leads to the natural question of, how does one add their own attributes to PIDA modules? Every class within the PIDA structure (module, function, basic block and instruction) contains a default-empty dictionary variable named ext (for extension or extending). To add your own attributes, simply create a new dictionary key with your module name and assign whatever type you want to it. For example, if I want to add a count of the number of times specific functions were accessed within a PIDA module, I might create the following addition:
    for key in module.functions.keys():
        module.functions[key].ext["PAIMEIexplore"] = {}
        module.functions[key].ext["PAIMEIexplore"]["hit_count"] = 0
If you want to save your attribute extensions, simply dump the PIDA module back to disk. The ext dictionary will be included in the file and restored the next time it is loaded.