Cython and IDA Pro

To run this notebook you will need the ida_ipython plugin. The binary used is notepad.exe. This notebook shows how you can use Cython to access IDA api's that are not exposed via IDAPython. As you can see below in this example i used gcc with the Anaconda distribution to compile the Cython code. I suggest trying to trying to compile some Cython outside of IDA first, to make sure that it is all working.


In [1]:
import idc
print "MD5: {} Binary: {}".format(idc.GetInputMD5(), idc.GetInputFile())


-----------------------------------------------------------------------------------------------------
Python 2.7.5 |Anaconda 2.1.0 (32-bit)| (default, May 31 2013, 10:43:53) [MSC v.1500 32 bit (Intel)] 
IDAPython v1.7.0 final (serial 0) (c) The IDAPython Team <idapython@googlegroups.com>
-----------------------------------------------------------------------------------------------------
MD5: E30299799C4ECE3B53F4A7B8897A35B6 Binary: notepad.exe

My configuration

Below are some commands to show my configuration, so you can use it for comparision.


In [2]:
!echo %PYTHONHOME%
!where gcc
!gcc -v


C:\Anaconda
C:\Anaconda\Scripts\gcc.bat
Using built-in specs.
COLLECT_GCC=C:\Anaconda\Scripts\gcc.bat\..\..\MinGW\bin\gcc.exe
COLLECT_LTO_WRAPPER=c:/anaconda/mingw/bin/../libexec/gcc/i686-w64-mingw32/4.7.0/lto-wrapper.exe
Target: i686-w64-mingw32
Configured with: ../../../build/gcc/src/configure --target=i686-w64-mingw32 --prefix=/c/bb/vista64-mingw32/mingw-x86-x86/build/build/root --with-sysroot=/c/bb/vista64-mingw32/mingw-x86-x86/build/build/root --enable-languages=all,obj-c++ --enable-fully-dynamic-string --disable-multilib
Thread model: win32
gcc version 4.7.0 20111219 (experimental) (GCC) 

I have also set my compiler to MinGW32 in disutils.cfg file


In [3]:
!type %PYTHONHOME%\Lib\distutils\distutils.cfg


[build]
compiler=mingw32

The Actual Cython Code

First we load the Cython extention for IPython, then we create a simple test to call in msg funciton.


In [4]:
%load_ext cythonmagic

In [5]:
%%cython -+ -f -IC:/dev/IDA/idasdks/idasdk61/include -c "-D__NT__ -D__IDP__ -DWIN32" --link-args "C:/dev/IDA/idasdks/idasdk61/lib/x86_win_gcc_32/ida.a"
cdef extern from "pro.h": pass
cdef extern from "kernwin.hpp":
    int msg(const char* msg, ...)
    
msg("Hello from Cython!\n")

The command line parameters mean the following.

  • -+ forces C++ mode
  • -f will force recompile/execution each time
  • -IC:/dev/IDA/idasdks/idasdk61/include points to your IDA SDK include
  • -c "-D__NT__ -D__IDP__ -DWIN32" definitions for the IDA SDK to compile
  • --link-args "C:/dev/IDA/idasdks/idasdk61/lib/x86_win_gcc_32/ida.a" library file for linking

You will need to change some of these to get it to work on other compilers, you can read more of the documentation below.


In [6]:
%%cython?

Below is a slightly more complicated example exposing some of the type info api


In [7]:
%%cython -+ -f -lm -IC:/dev/IDA/idasdks/idasdk61/include -c "-D__NT__ -D__IDP__ -DWIN32" --link-args "C:/dev/IDA/idasdks/idasdk61/lib/x86_win_gcc_32/ida.a"
ctypedef unsigned int ea_t
ctypedef int bool

cdef extern from "pro.h":
    cdef cppclass _qstring[T]:
        T *c_str() 
    ctypedef _qstring[uchar] qtype

cdef extern from "nalt.hpp":
    bool get_tinfo(ea_t ea, qtype *type, qtype *fields)   
    
cpdef pget_tinfo(ea_t ea):
    cdef qtype typ
    cdef qtype fields
    get_tinfo(ea, &typ, &fields)
    return typ.c_str(), fields.c_str()

In [8]:
hex(idc.LocByName("_WinMain@16"))


Out[8]:
'0x401005'

In [9]:
pget_tinfo(idc.LocByName("_WinMain@16"))


Out[9]:
('\x0cS\x07\x05=\nHINSTANCE=\nHINSTANCE=\x06LPSTR\x07',
 '\nhInstance\x0ehPrevInstance\nlpCmdLine\tnShowCmd')

Cython can be used to access the C API or to speed up code. You could also just write most of the code in C then just call in from Cython in the notebook, if you’re more comfortable with that. For more information have a look at the documentation.